Advertisement
Guest User

Untitled

a guest
Aug 25th, 2019
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 54.02 KB | None | 0 0
  1. import sys
  2. import os
  3. import re
  4. from optparse import OptionParser
  5. import ConfigParser
  6.  
  7.  
  8. try:
  9. import pygccxml
  10. except ImportError:
  11. print "You must instal pygccxml in-order to run this script."
  12. sys.exit(1)
  13.  
  14. from pygccxml.declarations.cpptypes import *
  15. from pygccxml.declarations.type_traits import *
  16. from pygccxml.declarations.type_traits_classes import *
  17. from pygccxml.declarations.calldef import *
  18. from pygccxml.declarations.calldef_types import *
  19. from pygccxml.declarations.free_calldef import *
  20. from pygccxml.declarations.calldef_members import *
  21. from pygccxml.declarations.class_declaration import ACCESS_TYPES, class_declaration_t
  22. from pygccxml.declarations.typedef import typedef_t
  23.  
  24. class UnsupportedError(NotImplementedError):
  25. """Exception for unsupported features."""
  26. pass
  27.  
  28. DEBUG = False
  29.  
  30. ARRAY_SIZE_VAR_NAME = 'arr_size'
  31. RET_VAL_ON_EXCEPTION = 'NULL'
  32. GENERATED_FILE_SUFFIX = "_C_Wrapper"
  33.  
  34. THIS_VAR_NAME = 'class_this'
  35. RET_VAL_CLASS_NAME = 'ptr_ret_val_class'
  36. WAS_EXCEPTION_ARG_NAME = 'ptr_was_exception'
  37. C_BOOL_TYPE_NAME = 'BOOL_C'
  38. C_TRUE_VAL = 'TRUE_C'
  39. C_FALSE_VAL = 'FALSE_C'
  40. # TODO: check whether those vars are in [arg_info.arg_name for arg_info in func_info.func_args_info_list], and if so - add a suffix.
  41.  
  42. PYGCCXML_DTOR_TOKEN = re.compile(r"._\d+")
  43.  
  44. PYGCCXML_FUNC_DECL_ARGS = re.compile(r".*\((.*?)\)") # =The last ()'s contents.
  45.  
  46. OPERATOR_MAP = {
  47. '+': "plus",
  48. '-': "minus",
  49. '*': "multiply",
  50. '/': "divison",
  51. '%': "mod",
  52. '^': "bitwise_xor",
  53. '&': "bitwise_and",
  54. '|': "bitwise_or",
  55. '~': "bitwise_not",
  56. '!': "not",
  57. '=': "assign",
  58. '<': "smaller",
  59. '>': "bigger",
  60. '+=': "plus_assign",
  61. '-=': "minus_assign",
  62. '*=': "multiply_assign",
  63. '/=': "division_assign",
  64. '%=': "mod_assign",
  65. '^=': "bitwise_xor_assign",
  66. '&=': "bitwise_and_assign",
  67. '|=': "bitwise_or_assign",
  68. '<<': "shift_left",
  69. '>>': "shift_right",
  70. '<<=': "shift_left_assign",
  71. '>>=': "shift_right_assign",
  72. '==': "equal",
  73. '!=': "not_assign",
  74. '<=': "smaller_or_equal",
  75. '>=': "bigger_or_equal",
  76. '&&': "and",
  77. '||': "or",
  78. '++': "plus_plus",
  79. '--': "minus_minus",
  80. ',': "comma",
  81. '->*': "pointer_redirect",
  82. '->': "redirect",
  83. '()': "function_call",
  84. '[]': "subscript",
  85. 'new': "new",
  86. 'new []': "new_array",
  87. 'delete': "delete",
  88. 'delete []': "delete_array"
  89. } # TODO: Check the function_call op.
  90.  
  91. OPERATORS_LIST_BY_LENGTH = sorted(OPERATOR_MAP.keys(), key=len, reverse=True) # From the longest to the shortest, to check '+=' before '+' (or '=').
  92.  
  93. # Proxy funcs to shield from possible pygccxml implementation changes:
  94.  
  95. def is_declarated_type(arg):
  96. """Returns whether the argument is a declaration type."""
  97. return isinstance(arg, declarated_t)
  98.  
  99. def is_ellipsis(arg):
  100. """Returns whether the argument is ellipsis (...)."""
  101. return isinstance(arg, ellipsis_t)
  102.  
  103. def is_qualifier(arg):
  104. """Returns whether the argument is a qualifier."""
  105. return isinstance(arg, type_qualifiers_t)
  106.  
  107. def is_unknown_type(arg):
  108. """Returns whether the argument is an unknown type."""
  109. return isinstance(arg, unknown_t)
  110.  
  111. def is_member_function_type(arg):
  112. """Returns whether the argument is a member function type."""
  113. return isinstance(arg, member_function_type_t)
  114.  
  115. def is_typedef(arg):
  116. """Returns whether the argument is a typedef."""
  117. return isinstance(arg, typedef_t)
  118.  
  119. def get_public_default_ctor(cls):
  120. """Returns the class public default ctor, or None if one doesn't exist."""
  121. return has_trivial_constructor(cls)
  122.  
  123. def has_public_dtor(cls):
  124. """Returns whether the class has a public destructor."""
  125. return has_public_destructor(cls)
  126.  
  127. def is_abstract_class_declaration(arg):
  128. """Returns whether arg is a class declaration that is not a typedef - for example: typedef abstract_class_decl typedef_decl"""
  129. #return is_class_declaration(decl) and not is_typedef(decl)
  130. return isinstance(arg, class_declaration_t)
  131.  
  132. def get_full_name(decl, sub_seq=None):
  133. """Generates a C++ token's name, including namespaces."""
  134. #if is_abstract_class_declaration(decl):
  135. # ns_name = get_full_name(decl.parent)
  136. # if not ns_name.endswith("::"): # True to every namespace except for the global namespace.
  137. # ns_name += "::"
  138. # return ns_name + decl.declaration.name
  139. full_name = pygccxml.declarations.full_name(decl)
  140. if sub_seq is not None:
  141. for old_token, new_token in sub_seq:
  142. full_name = full_name.replace(old_token, new_token)
  143. return full_name
  144.  
  145.  
  146. def get_func_decl_str(func):
  147. """Return a func declaration string."""
  148. args_str = PYGCCXML_FUNC_DECL_ARGS.match(func.create_decl_string()).group(1).strip()
  149. return "%s(%s)" % (get_full_name(func), args_str)
  150.  
  151. def python_to_camel_case(decl_str):
  152. """Python to (Upper-)Camel Case naming convention, e.g.: "func_name" -> "FuncName" """
  153. words = decl_str.split("_")
  154. return "".join([word.capitalize() for word in words])
  155.  
  156. def strip_global_ns(decl_str):
  157. """Strip the global namespace ot a C++ declaration string."""
  158. return decl_str.lstrip(':')
  159.  
  160. def get_c_name(decl, is_full_name=True, c_sub_seq=None):
  161. """Generates a C token from a C++ token."""
  162. if is_full_name:
  163. cpp_name = get_full_name(decl)
  164. else:
  165. cpp_name = decl.name
  166. c_name = strip_global_ns(cpp_name).replace('::', '_').replace('~', "delete_").replace('>', '_').replace('<', '_').replace(' ', '').replace(',', '_').replace('*', "_ptr_").replace('&', "_ref_")
  167. # The first substitution is for namespaces. The second is for dtors. All others are for templates.
  168. if c_sub_seq is not None:
  169. for old_token, new_token in c_sub_seq:
  170. if old_token: # FIXME:
  171. c_name = c_name.replace(old_token, new_token)
  172. return c_name
  173.  
  174. def get_class_ptr_name(class_c_name):
  175. """Generates a class pointer token from its C class token."""
  176. return "PTR_%s" % (class_c_name,)
  177.  
  178. def get_error_arg_str(is_c99):
  179. """Returns the type-name string of the error arg."""
  180. if is_c99:
  181. c_bool_type_str = "bool"
  182. else:
  183. c_bool_type_str = C_BOOL_TYPE_NAME
  184. return "%s *%s" % (c_bool_type_str, WAS_EXCEPTION_ARG_NAME)
  185.  
  186. def get_enum_c_name(enum):
  187. """Generates a C enum token from a C++ one."""
  188. enum_name = get_c_name(enum)
  189. if enum_name == enum.name: # To prevent enum redifinition in the global scope. unlike typedef redifinition - it causes a compilation error.
  190. enum_name += "_C" # TODO: Can (still) cause redifinition.
  191. return enum_name
  192.  
  193. def get_header_guard_name(generated_base_file_path):
  194. """Returns the header guard. for a specific header file name."""
  195. generated_header_file_name = os.path.basename(generated_base_file_path+".h")
  196. return generated_header_file_name.upper().replace('.', '_')
  197.  
  198. def is_public_concrete_func(member_func):
  199. """Reurns whether a member function\operator is public and concrete."""
  200. return ((member_func.access_type == ACCESS_TYPES.PUBLIC) and (member_func.virtuality != VIRTUALITY_TYPES.PURE_VIRTUAL))
  201.  
  202. def get_class_by_decl(global_ns, class_decl, is_safe=True):
  203. """Returns the class for a class declaration."""
  204. try:
  205. return global_ns.class_(get_full_name(class_decl))
  206. except pygccxml.declarations.runtime_errors.multiple_declarations_found_t:
  207. #print(global_ns, get_full_name(class_decl))
  208. #pass
  209. return global_ns.classes(get_full_name(class_decl))[1]
  210. except pygccxml.declarations.runtime_errors.declaration_not_found_t:
  211. if is_safe:
  212. raise UnsupportedError("No concrete class for class declaration %s. Possible reason: template instatiation is missing." % (str(class_decl),))
  213. else:
  214. raise
  215.  
  216. def exception_handling_str(generate_exception_handling_code, output_str, generate_error_arg, is_c99, is_void_ret_type, ret_type_c_str):
  217. """Generates exception handling wrapper around an implementation output string, with or without an error argument."""
  218. if not generate_exception_handling_code:
  219. return output_str
  220.  
  221. if is_void_ret_type:
  222. on_exception_return_str = ""
  223. else:
  224. on_exception_return_str = "\treturn (%s) %s;\n" % (ret_type_c_str, RET_VAL_ON_EXCEPTION)
  225. if is_c99:
  226. c_false_str = "false"
  227. c_true_str = "true"
  228. else:
  229. c_false_str = C_FALSE_VAL
  230. c_true_str = C_TRUE_VAL
  231. error_arg_no_exception_str = ""
  232. error_arg_was_exception_str = ""
  233. if generate_error_arg:
  234. error_arg_no_exception_str = "if((void *)%s != NULL) (*%s) = %s;\n" % (WAS_EXCEPTION_ARG_NAME, WAS_EXCEPTION_ARG_NAME, c_false_str)
  235. error_arg_was_exception_str = "if((void *)%s != NULL) (*%s) = %s;\n" % (WAS_EXCEPTION_ARG_NAME, WAS_EXCEPTION_ARG_NAME, c_true_str)
  236. return """ try {
  237. %s%s
  238. }
  239. catch(...) {
  240. %s\t%s
  241. }""" % (error_arg_no_exception_str, output_str, error_arg_was_exception_str, on_exception_return_str)
  242.  
  243.  
  244. class MemoryFile(object):
  245. """A class to implement a file on the memory."""
  246.  
  247. MARK_TOKEN = "@@@"
  248. def __init__(self, path):
  249. self.path = path
  250. self.lines = [self.MARK_TOKEN]
  251.  
  252. def close(self):
  253. """Closes the memory file."""
  254. self.lines.remove(self.MARK_TOKEN)
  255. out_file = open(self.path, 'w')
  256. out_file.write("\n".join(self.lines))
  257. out_file.close()
  258.  
  259. def write(self, str):
  260. """Writes a string to the memory file."""
  261. self.lines.append(str)
  262.  
  263. def write_at_mark(self, str):
  264. """Writes a string at the mark position of the memory file."""
  265. self.lines.insert(self.lines.index(self.MARK_TOKEN), str)
  266.  
  267. def set_mark(self):
  268. """Set the mark posiion in the memory file."""
  269. self.lines.remove(self.MARK_TOKEN)
  270. self.lines.append(self.MARK_TOKEN)
  271.  
  272.  
  273. class BasicOutputClass(object):
  274. """A class to handle the files output."""
  275.  
  276. def __init__(self, header_file_path, generate_dl):
  277. self.header_file_path = header_file_path
  278. header_file_name = os.path.basename(header_file_path)
  279. generated_base_file_name = header_file_name[:header_file_name.rindex(".h")]+GENERATED_FILE_SUFFIX
  280. self.generated_base_file_path = os.path.join(os.path.dirname(header_file_path), generated_base_file_name)
  281. self.generate_dl = generate_dl
  282. self.cpp_file = MemoryFile(self.generated_base_file_path+".cpp")
  283. self.h_file = MemoryFile(self.generated_base_file_path+".h")
  284. if generate_dl:
  285. self.def_file = MemoryFile(self.generated_base_file_path+".def")
  286.  
  287. def close(self):
  288. """Forces the output file creation."""
  289. self.cpp_file.close()
  290. self.h_file.close()
  291. if self.generate_dl:
  292. self.def_file.close()
  293.  
  294. def write_to_cpp_file(self, output_str):
  295. """Write a string in the cpp file."""
  296. self.cpp_file.write(output_str+'\n')
  297. if DEBUG:
  298. print "CPP: %s" % (output_str,)
  299.  
  300. def write_to_h_file(self, output_str):
  301. """Write a string in the header file."""
  302. self.h_file.write(output_str+'\n')
  303. if DEBUG:
  304. print "H: %s" % (output_str,)
  305.  
  306. def write_at_h_file_mark(self, output_str):
  307. """Write a string in the header file's mark."""
  308. self.h_file.write_at_mark(output_str+'\n')
  309. if DEBUG:
  310. print "H (FRONT): %s" % (output_str,)
  311.  
  312. def write_to_def_file(self, output_str):
  313. """Write a string in the def file, if this option is enabled."""
  314. if self.generate_dl:
  315. self.def_file.write(output_str+'\n')
  316. if DEBUG:
  317. print "DEF: %s" % (output_str,)
  318.  
  319. def mark_h_file_front(self):
  320. """Mark the start of the header file, where the typedefs would be written."""
  321. self.h_file.set_mark()
  322.  
  323.  
  324. class CodeOutputClass(BasicOutputClass):
  325. """A class to handle the code output."""
  326.  
  327. def __init__(self, header_file_path, generate_exception_handling_code, generate_dl, is_compact_string, generate_operators, is_assume_copy, is_assume_assign, generate_error_arg, is_verbose, is_camel_case):
  328. super(CodeOutputClass, self).__init__(header_file_path, generate_dl)
  329. self.generate_exception_handling_code = generate_exception_handling_code
  330. self.is_compact_string = is_compact_string
  331. self.generate_operators = generate_operators
  332. self.is_assume_copy = is_assume_copy
  333. self.is_assume_assign = is_assume_assign
  334. self.generate_error_arg = generate_error_arg
  335. self.is_verbose = is_verbose
  336. self.is_camel_case = is_camel_case
  337.  
  338. def __del__(self):
  339. super(CodeOutputClass, self).__del__()
  340.  
  341. def output_class_typedef(self, cls, global_context, alternate_class_c_ptr_name=None):
  342. """Outputs a C class representation."""
  343. class_c_name, class_c_ptr_name = global_context.add_class(cls, alternate_class_c_ptr_name)
  344. verbose_str = ""
  345. if self.is_verbose:
  346. verbose_str = "\t/* A C wrapper for class %s */" % (get_full_name(cls),)
  347. self.write_at_h_file_mark("typedef struct _%s *%s;%s" % (class_c_name, class_c_ptr_name, verbose_str))
  348.  
  349. def output_func(self, func, global_context, is_array_version=False, generate_min_args_ver_only=False):
  350. """Outputs a function C wrapper."""
  351.  
  352. func_info = FuncInfo(func, global_context, self.generate_error_arg, generate_min_args_ver_only)
  353. c_func_name = func_info.c_func_name
  354.  
  355. if (func_info.func_type == func_info.DTOR):
  356. # To fix the pygccxml dtor name of ~._<num> for declarated classes.
  357. c_func_name = PYGCCXML_DTOR_TOKEN.sub(get_c_name(func.parent, False), c_func_name)
  358.  
  359. for used_def_vals_num in range(func_info.optional_args_num+1): # Variations to handle default values.
  360. func_args_decl_list = [arg_c_str for arg_c_str in func_info.gen_func_args_c_strs()]
  361. func_args = func_args_decl_list[:len(func_args_decl_list)-used_def_vals_num]
  362. if is_array_version and (func_info.func_type == func_info.CTOR):
  363. func_args.append("size_t %s" % (ARRAY_SIZE_VAR_NAME,)) # Needed for new[].
  364. func_args_str = ", ".join(func_args)
  365. func_args_impl_list = []
  366. for arg_info in func_info.func_args_info_list[:len(func_info.func_args_info_list)-used_def_vals_num]:
  367. redirection_str = ""
  368. if arg_info.is_redirected:
  369. redirection_str = "*"
  370. cast_str = ""
  371. if arg_info.cast_str:
  372. cast_str = "(%s)" % (arg_info.cast_str,)
  373. arg_name = arg_info.arg_name
  374. func_args_impl_list.append((redirection_str, cast_str, arg_name))
  375. func_args_impl_str = ", ".join(["%s%s%s" % (redirection_str, cast_str, arg_name) for redirection_str, cast_str, arg_name in func_args_impl_list])
  376.  
  377. if is_array_version:
  378. c_func_name = "%s_array" % (c_func_name,)
  379. unique_c_func_name = global_context.generate_unique_token(c_func_name)
  380. if self.is_camel_case:
  381. unique_c_func_name = python_to_camel_case(unique_c_func_name)
  382.  
  383. self.write_to_def_file('\t'+unique_c_func_name)
  384. func_prototype = "%s %s(%s)" % (func_info.ret_type_info.arg_type_c_str, unique_c_func_name , func_args_str)
  385. verbose_str = ""
  386. if self.is_verbose:
  387. verbose_str = "\t/* A C wrapper for func %s */" % (get_func_decl_str(func),)
  388. self.write_to_h_file("%s;%s" % (func_prototype, verbose_str))
  389. self.write_to_cpp_file("%s {" % (func_prototype,))
  390.  
  391. ret_val_c_str = "%s%s(%s)" % (func_info.class_redirection, func_info.full_name, func_args_impl_str)
  392.  
  393. output_str = "\t\t"
  394. if (func_info.func_type == func_info.CTOR):
  395. if func_info.is_default_ctor():
  396. ctor_args_str = ""
  397. else:
  398. ctor_args_str = "(%s)" % (func_args_impl_str,)
  399. array_str = ""
  400. if is_array_version:
  401. array_str = "[%s]" % (ARRAY_SIZE_VAR_NAME,)
  402. nothrow_str = ""
  403. if not self.generate_exception_handling_code:
  404. nothrow_str = "(std::nothrow) "
  405. ret_val_c_str = "new %s%s%s%s" % (nothrow_str, func_info.ret_type_info.class_name, ctor_args_str, array_str)
  406. elif (func_info.func_type == func_info.DTOR):
  407. array_str = ""
  408. if is_array_version:
  409. array_str = "[]"
  410. cast_str = "(%s*)" % (global_context.get_full_name(func.parent),)
  411. ret_val_c_str = "delete %s(%s%s)" % (array_str, cast_str, THIS_VAR_NAME)
  412. else:
  413. if (func_info.ret_type_info.is_class) and (func_info.ret_type_info.is_redirected):# and not(func_info.ret_type_info.is_ptr):
  414. # Special case: a class should be returned by value. We'll try to return a pointer to a new instance, if possible.
  415. nothrow_str = ""
  416. if not self.generate_exception_handling_code:
  417. nothrow_str = "(std::nothrow) "
  418. if func_info.ret_type_info.can_create_with_copy_constructor or ((func_info.ret_type_info.can_create_with_copy_constructor is None) and self.is_assume_copy):
  419. ret_val_c_str = "new %s%s(%s)" % (nothrow_str, func_info.ret_type_info.class_name, ret_val_c_str)
  420. elif func_info.ret_type_info.can_create_with_default_constructor or ((func_info.ret_type_info.can_create_with_default_constructor is None) and self.is_assume_assign):
  421. output_str += "%s *%s = new %s%s;\n" % (func_info.ret_type_info.class_name, RET_VAL_CLASS_NAME, nothrow_str, func_info.ret_type_info.class_name)
  422. nothrow_null_check_str = ""
  423. if not self.generate_exception_handling_code:
  424. nothrow_null_check_str = "if((void*)%s != NULL) " % (RET_VAL_CLASS_NAME,)
  425. output_str += "%s*%s = %s;\n" % (nothrow_null_check_str, RET_VAL_CLASS_NAME, ret_val_c_str)
  426. ret_val_c_str = RET_VAL_CLASS_NAME
  427. else:
  428. raise UnsupportedError("Cannot handle a class return value without a public copy ctor or public default ctor an assignment operator in %s" % (func_info.full_name, ))
  429. if func_info.ret_type_info.is_void():
  430. return_str = ""
  431. else:
  432. return_str = "return "
  433. cast_str = ""
  434. if func_info.ret_type_info.cast_str:
  435. cast_str = "(%s)" % (func_info.ret_type_info.arg_type_c_str,)
  436. ref_str = ""
  437. if (func_info.ret_type_info.is_ref and not(func_info.ret_type_info.is_class)):
  438. ref_str = "&"
  439. output_str += "%s%s%s%s;" % (return_str, cast_str, ref_str, ret_val_c_str)
  440. output_str = exception_handling_str(self.generate_exception_handling_code, output_str, self.generate_error_arg, global_context.is_c99, func_info.ret_type_info.is_void(), func_info.ret_type_info.arg_type_c_str)
  441. self.write_to_cpp_file("%s" % (output_str,))
  442. self.write_to_cpp_file( "}")
  443.  
  444. def output_std_string(self, string_typedef, global_context):
  445. """Outputs the std::(w)string C wrapper."""
  446. is_wstring, string_class, string_c_ptr_name = global_context.add_std_string(string_typedef)
  447. if self.is_compact_string: # Otherwise, it would be outputed like other classes, recursively, as needed.
  448. self.output_class_typedef(string_class, global_context, string_c_ptr_name)
  449. public_default_ctor = get_public_default_ctor(string_class)
  450. self.output_func(public_default_ctor, global_context)
  451. self.output_func(public_default_ctor, global_context, True)
  452.  
  453. if is_wstring:
  454. char_str = "wchar_t"
  455. else:
  456. char_str = "char"
  457. char_ptr_str = "const %s *" % (char_str,)
  458. for ctor in string_class.constructors():
  459. if (len(ctor.required_args) == 1) and (char_ptr_str == ctor.required_args[0].decl_type.build_decl_string()):
  460. self.output_func(ctor, global_context, False, True) # Outputs the std::(w)string(char*) ctor. We don't generate the allocator<char_str> optional arg.
  461. break
  462.  
  463. string_dtor = has_destructor(string_class)
  464. self.output_func(string_dtor, global_context)
  465. self.output_func(string_dtor, global_context, True)
  466. c_str_func = string_class.member_function("c_str")
  467. self.output_func(c_str_func, global_context)
  468.  
  469. def output_enum(self, enum, global_context):
  470. """Outputs an enum C version."""
  471. enum_name = get_enum_c_name(enum)
  472. verbose_str = ""
  473. if self.is_verbose:
  474. verbose_str = "\t/* A C wrapper for enum %s */" % (get_full_name(enum),)
  475. self.write_at_h_file_mark("enum %s {" % (enum_name,))
  476. self.write_at_h_file_mark("%s" % (",\n".join(["\t%s=%s" % (global_context.generate_unique_token(key, True), val) for key, val in enum.values]),)) # Needed to handle 2 enums with same keys in different namespaces.
  477. self.write_at_h_file_mark("};%s" % (verbose_str,))
  478. global_context.add_enum(enum)
  479.  
  480. def output_typedef(self, typedef, global_context):
  481. """Outputs a typedef C version."""
  482. typedef_info=ArgInfo(typedef.decl_type, global_context, get_c_name(typedef))
  483. if typedef_info.is_c_decl: # There is no support for typedefs that aren't C declerations - they'll be stripped to their raw C-type.
  484. verbose_str = ""
  485. if self.is_verbose:
  486. verbose_str = "\t/* A C wrapper for typedef %s */" % (get_full_name(typedef),)
  487. self.write_at_h_file_mark("typedef %s;%s" % (typedef_info.get_type_name_str(), verbose_str))
  488. global_context.add_typedef(typedef)
  489. # TODO: What about a typedef of an enum?
  490.  
  491. def output_class_code(self, cls, global_context):
  492. """Output cls class code."""
  493. for ctor in cls.constructors(allow_empty=True):
  494. if (ctor.access_type == ACCESS_TYPES.PUBLIC):
  495. self.output_func(ctor, global_context)
  496.  
  497. if has_public_dtor(cls):
  498. dtor = has_destructor(cls)
  499. self.output_func(dtor, global_context)
  500.  
  501. public_default_ctor = get_public_default_ctor(cls)
  502. if public_default_ctor is not None:
  503. self.output_func(public_default_ctor, global_context, True)
  504. self.output_func(dtor, global_context, True)
  505.  
  506. for member_func in cls.member_functions(allow_empty=True):
  507. if is_public_concrete_func(member_func):
  508. self.output_func(member_func, global_context)
  509.  
  510. if self.generate_operators:
  511. for member_op in cls.member_operators(allow_empty=True):
  512. if is_public_concrete_func(member_op):
  513. self.output_func(member_op, global_context)
  514.  
  515. def output_prefix_code(self, is_c99):
  516. """Output the prefix code (includes, base typedefs, etc.)."""
  517. header_file_name = os.path.basename(self.header_file_path)
  518. generated_header_file_name = os.path.basename(self.generated_base_file_path+".h")
  519. generated_base_file_name = os.path.basename(self.generated_base_file_path)
  520. self.write_to_cpp_file("""#include "%s" """ % (header_file_name,))
  521. self.write_to_cpp_file("""#include "%s" """ % (generated_header_file_name,))
  522. self.write_to_def_file("""LIBRARY "%s"
  523. EXPORTS""" % (generated_base_file_name,))
  524.  
  525. header_guard = get_header_guard_name(self.generated_base_file_path)
  526. self.write_to_h_file("#ifndef %s" % (header_guard,))
  527. self.write_to_h_file("#define %s" % (header_guard,))
  528.  
  529. self.write_to_h_file("""#ifdef __cplusplus
  530. extern "C" {
  531. #endif""")
  532.  
  533. if not is_c99:
  534. self.write_to_h_file("#define %s 0" % (C_FALSE_VAL,))
  535. self.write_to_h_file("#define %s 1" % (C_TRUE_VAL,))
  536. self.write_to_h_file("typedef unsigned char %s;" % (C_BOOL_TYPE_NAME,))
  537.  
  538. self.mark_h_file_front()
  539.  
  540. if self.generate_dl:
  541. self.write_to_cpp_file("""#ifdef WIN32
  542. #include <Windows.h>
  543. extern "C" BOOL WINAPI DllMain(
  544. HINSTANCE hinstDLL, // handle to DLL module
  545. DWORD fdwReason, // reason for calling function
  546. LPVOID lpReserved ) // reserved
  547. {
  548. // Perform actions based on the reason for calling.
  549. switch( fdwReason )
  550. {
  551. case DLL_PROCESS_ATTACH:
  552. // Initialize once for each new process.
  553. // Return FALSE to fail DLL load.
  554. break;
  555.  
  556. case DLL_THREAD_ATTACH:
  557. // Do thread-specific initialization.
  558. break;
  559.  
  560. case DLL_THREAD_DETACH:
  561. // Do thread-specific cleanup.
  562. break;
  563.  
  564. case DLL_PROCESS_DETACH:
  565. // Perform any necessary cleanup.
  566. break;
  567. }
  568. return TRUE; // Successful DLL_PROCESS_ATTACH.
  569. }
  570. #endif // WIN32""")
  571.  
  572. def output_suffix_code(self):
  573. """Output the suffix code (header protectors, etc.)."""
  574. self.write_to_h_file("""#ifdef __cplusplus
  575. }
  576. #endif /* __cplusplus */""")
  577. generated_header_file_name = os.path.basename(self.generated_base_file_path+".h")
  578. self.write_to_h_file("#endif /* %s */" % (get_header_guard_name(self.generated_base_file_path),))
  579.  
  580.  
  581. class CodeContext(object):
  582. """The code context (classes, typdefs, etc.) of the parsed header files."""
  583.  
  584. CLASS = 0
  585. TYPEDEF = 1
  586. ENUM = 2
  587.  
  588. def __init__(self, header_file_path, gccxml_file_path, compiler_type, is_c99):
  589. generator_path, generator_name = pygccxml.utils.find_xml_generator()
  590.  
  591. #config = pygccxml.parser.config_t(gccxml_path=gccxml_file_path, compiler=compiler_type)
  592. config = pygccxml.parser.xml_generator_configuration_t(
  593. gccxml_path=gccxml_file_path, compiler=compiler_type,
  594. xml_generator=generator_name, xml_generator_path=generator_path,
  595. include_paths=["/usr/include", "/usr/include/opencascade"])
  596. #config = pygccxml.parser.xml_generator_configuration_t(
  597. # xml_generator_path=gccxml_file_path,
  598. # xml_generator=compiler_type or "gccxml")
  599. decls = pygccxml.parser.parse([header_file_path], config)
  600. self.global_ns = pygccxml.declarations.get_global_namespace(decls)
  601.  
  602. self.is_c99 = is_c99
  603. self.class_c_ptrs_map = {}
  604. self.token_freqs = {}
  605. self.typedefs_map = {}
  606. self.std_wstring_c_name = None
  607. self.std_string_c_name = None
  608. self.recursive_classes = []
  609. self.recursive_typedefs = []
  610. self.recursive_enums = []
  611. self.enums_map = {}
  612.  
  613. def __getattr__(self, attr_name):
  614. """ CodeContext becomes a proxy to the global namespace attributes."""
  615. return getattr(self.global_ns, attr_name)
  616.  
  617. def generate_unique_token(self, c_func_name, always_add_suffix=False):
  618. """Generates a unique C token."""
  619. # TODO: Use the args types instead, perhaps.
  620. if c_func_name in self.token_freqs:
  621. self.token_freqs[c_func_name] += 1
  622. return "%s%d" % (c_func_name, self.token_freqs[c_func_name])
  623. else:
  624. self.token_freqs[c_func_name] = 1
  625. if always_add_suffix:
  626. return "%s%d" % (c_func_name, self.token_freqs[c_func_name])
  627. else:
  628. return c_func_name
  629.  
  630. def add_class(self, cls, alternate_class_c_ptr_name=None):
  631. """Add cls to the code context."""
  632. class_c_name = self.get_c_name(cls)
  633. if alternate_class_c_ptr_name is None:
  634. class_c_ptr_name = get_class_ptr_name(class_c_name)
  635. else:
  636. class_c_ptr_name = alternate_class_c_ptr_name
  637. self.class_c_ptrs_map[self.get_full_name(cls)] = class_c_ptr_name
  638. return (class_c_name, class_c_ptr_name)
  639.  
  640. def add_typedef(self, typedef):
  641. """Add typedef to the code context."""
  642. self.typedefs_map[get_full_name(typedef)] = get_c_name(typedef)
  643.  
  644. def add_enum(self, enum):
  645. """Add an enum to the code context."""
  646. self.enums_map[get_full_name(enum)] = get_enum_c_name(enum)
  647.  
  648. def get_class_data(self, cls):
  649. """Get the class data for cls from the code context."""
  650. class_name = self.get_full_name(cls)
  651. if class_name not in self.class_c_ptrs_map:
  652. self.add_class(cls)
  653. if is_abstract_class_declaration(cls):
  654. cls = get_class_by_decl(self.global_ns, cls)
  655. if cls is not None:
  656. self.recursive_classes.append(cls)
  657. return (class_name, self.class_c_ptrs_map[class_name])
  658.  
  659. def get_typedef_data(self, typedef):
  660. """Get the data for typedef from the code context."""
  661. typedef_name = get_full_name(typedef)
  662. if typedef_name not in self.typedefs_map:
  663. self.add_typedef(typedef)
  664. self.recursive_typedefs.append(typedef)
  665. return (typedef_name, self.typedefs_map[typedef_name])
  666.  
  667. def get_enum_data(self, enum):
  668. """Get the data for enum from the code context."""
  669. enum_name = get_full_name(enum)
  670. if enum_name not in self.enums_map:
  671. self.add_enum(enum)
  672. self.recursive_enums.append(enum)
  673. return (enum_name, self.enums_map[enum_name])
  674.  
  675. def add_std_string(self, string_typedef):
  676. """Add std::(w)string to the code context."""
  677. string_class = get_class_by_decl(self.global_ns, string_typedef.decl_type.declaration, False)
  678. string_name = string_typedef.name
  679. is_wstring = ("wstring" in string_name)
  680. if is_wstring:
  681. self.wstring_ctor_name = get_public_default_ctor(string_class).name
  682. self.std_wstring_c_name = get_c_name(string_class)
  683. self.std_wstring_typedef_c_name = get_c_name(string_typedef)
  684. self.wstring_name = string_name
  685. self.wstring_full_name = get_full_name(string_class)
  686. self.wstring_full_typedef_name = get_full_name(string_typedef)
  687. string_c_ptr_name=get_class_ptr_name(self.std_wstring_typedef_c_name) # We replace the ptr of the class with that of the typedef - more readable.
  688. else:
  689. self.string_ctor_name = get_public_default_ctor(string_class).name
  690. self.std_string_c_name = get_c_name(string_class)
  691. self.std_string_typedef_c_name = get_c_name(string_typedef)
  692. self.string_name = string_name
  693. self.string_full_name = get_full_name(string_class)
  694. self.string_full_typedef_name = get_full_name(string_typedef)
  695. string_c_ptr_name=get_class_ptr_name(self.std_string_typedef_c_name) # We replace the ptr of the class with that of the typedef - more readable.
  696. self.add_typedef(string_typedef)
  697. return (is_wstring, string_class, string_c_ptr_name)
  698.  
  699. def gen_recursive_elems(self):
  700. """Generates the elements gathered recursively that needs to be outputed."""
  701. while self.recursive_classes or self.recursive_typedefs or self.recursive_enums:
  702. # Not a for loop - since classes may get into self.recursive_classes during this loop (e.g.: std::string::allocator inside std::string methods). The same is true for typedefs.
  703. if self.recursive_enums:
  704. yield (self.ENUM, self.recursive_enums.pop(0))
  705. elif self.recursive_typedefs:
  706. yield (self.TYPEDEF, self.recursive_typedefs.pop(0))
  707. elif self.recursive_classes:
  708. yield (self.CLASS, self.recursive_classes.pop(0))
  709.  
  710. def gen_sub_seq(self):
  711. """Generates a substitution sequence for C++ tokens."""
  712. if self.std_wstring_c_name is not None:
  713. yield (self.wstring_full_name, self.wstring_full_typedef_name) # Make the std::wstring declerations more readable.
  714. if self.std_string_c_name is not None:
  715. yield (self.string_full_name, self.string_full_typedef_name) # Make the std::wstring declerations more readable.
  716.  
  717. def gen_c_sub_seq(self):
  718. """Generates a substitution sequence for C tokens."""
  719. if self.std_wstring_c_name is not None:
  720. yield (self.std_wstring_c_name, self.std_wstring_typedef_c_name) # Make the std::wstring declerations more readable.
  721. yield (self.wstring_ctor_name, self.wstring_name) # Replace basic_string() with wstring().
  722. if self.std_string_c_name is not None:
  723. yield (self.std_string_c_name, self.std_string_typedef_c_name) # Make the std::string declerations more readable.
  724. yield (self.string_ctor_name, self.string_name) # Replace basic_string() with string().
  725.  
  726. def get_full_name(self, decl):
  727. """ Returns decl full name in the current code context."""
  728. return get_full_name(decl, self.gen_sub_seq())
  729.  
  730. def get_c_name(self, decl):
  731. """ Returns decl C-name in the current code context."""
  732. return get_c_name(decl, True, self.gen_c_sub_seq())
  733.  
  734. class ArgInfo(object):
  735. """A class to parse a func argument."""
  736.  
  737. def __init__(self, arg_type, global_context, arg_name=""):
  738. self.class_name = None
  739. self.is_const = False
  740. self.is_ref = False
  741. self.is_class = False
  742. self.arg_type_c_str = None
  743. self.is_ptr = False
  744. self.is_enum = False
  745. self.is_typedef = False
  746. self.arg_type = arg_type
  747. self.arg_name = arg_name
  748. self.cast_str = ""
  749. self.is_func_ptr = False
  750.  
  751. ptrs_list=[]
  752.  
  753. if "std::_Aux_cont" in str(arg_type):
  754. # Handle special case for MSVSC 2008, for example, when trying to instantiate vector<int>.
  755. # TODO: Handle the special case in a generic way.
  756. raise UnsupportedError("No support for std::_Aux_cont in: %s" % (str(arg_type),))
  757.  
  758. curr_arg = arg_type
  759. while not(is_fundamental(curr_arg)) or is_typedef(curr_arg) or is_declarated_type(curr_arg) or is_enum(curr_arg):
  760. if is_abstract_class_declaration(curr_arg):
  761. self.is_class = True
  762. cls = get_class_by_decl(global_context.global_ns, curr_arg)
  763. break
  764. elif is_typedef(curr_arg):
  765. self.is_typedef = True
  766. typedef_name, typedef_c_name = global_context.get_typedef_data(curr_arg)
  767. curr_arg = curr_arg.decl_type # Don't use remove_alias() since this deletes ALL the typedefs - and we don't want that.
  768. #TODO: Is this good to classes, either?
  769. elif is_declarated_type(curr_arg):
  770. #curr_arg_decl_str = curr_arg.build_decl_string()
  771. #if pygccxml.declarations.templates.is_instantiation(curr_arg_decl_str) and not(is_std_string(curr_arg) or is_std_wstring(curr_arg)):
  772. # raise UnsupportedError("Currently templates are not supported.")
  773. # TODO: Check STL contains, for example vector.
  774. #self.is_typedef, typedef_name, typedef_c_name = global_context.get_possible_typedef_data(curr_arg)
  775. curr_arg = curr_arg.declaration # And not remove_declarated(curr_arg) - since this would break a typedef completely, etc.
  776. elif is_const(curr_arg):
  777. self.is_const = True
  778. curr_arg = remove_const(curr_arg)
  779. elif is_ellipsis(curr_arg):
  780. raise UnsupportedError("Ellipsis arg types are not handeled.")
  781. elif is_qualifier(curr_arg):
  782. curr_arg = base_type(curr_arg) # TODO: Is this correct?
  783. elif is_unknown_type(curr_arg):
  784. raise UnsupportedError("Unknown arg type: %s" % (str(curr_arg),))
  785. elif is_volatile(curr_arg):
  786. curr_arg = remove_volatile(curr_arg) # Not being dealt.
  787. elif is_calldef_pointer(curr_arg):
  788. curr_arg = curr_arg.base # remove_pointer() doesn't work here.
  789. if is_member_function_type(curr_arg):
  790. raise UnsupportedError("Member function pointers are not supported: %s" % (str(arg_type),))
  791. self.is_func_ptr = True
  792. self.func_ptr_info = FuncPtrInfo(curr_arg, arg_name, global_context)
  793. break
  794. elif is_pointer(curr_arg) or is_array(curr_arg):
  795. ptrs_list.append(self.is_const)
  796. self.is_const = False
  797. curr_arg = remove_pointer(curr_arg)
  798. elif is_reference(curr_arg):
  799. self.is_ref = True # Only the 1st ref is handeled
  800. curr_arg = remove_reference(curr_arg)
  801. elif is_enum(curr_arg):
  802. self.is_enum = True
  803. break
  804. elif is_class(curr_arg):
  805. self.is_class = True
  806. cls = curr_arg
  807. break
  808.  
  809. self.is_c_bool = is_bool(curr_arg) and not global_context.is_c99 # This is redundent if the compiler is C99 compatible.
  810. self.is_c_decl = not(self.is_class or self.is_ref or self.is_c_bool) #= A simple C decleration.
  811. self.is_redirected = (self.is_class or self.is_ref)
  812.  
  813. if self.is_c_decl:
  814. self.arg_type_c_str = strip_global_ns(arg_type.build_decl_string())
  815. if self.is_typedef:
  816. stripped_typedef_name = strip_global_ns(typedef_name)
  817. if typedef_c_name != stripped_typedef_name: # There is a namespace
  818. self.cast_str = self.arg_type_c_str
  819. self.arg_type_c_str = self.arg_type_c_str.replace(typedef_name, typedef_c_name)
  820. # The following line is needed to handle the case where arg_type.build_decl_string() is a typedef -> we've stripped the global namespace, and the type won't be replaced with the last line.
  821. self.arg_type_c_str = self.arg_type_c_str.replace(stripped_typedef_name, typedef_c_name)
  822. elif self.is_enum:
  823. self.cast_str = self.arg_type_c_str
  824. enum_name, enum_c_name = global_context.get_enum_data(curr_arg)
  825. if "enum " not in enum_c_name: # C++ style's enum
  826. enum_c_name = "enum %s" % (enum_c_name,)
  827. self.arg_type_c_str = self.arg_type_c_str.replace(strip_global_ns(get_full_name(curr_arg)), enum_c_name)
  828. else:
  829. if self.is_class:
  830. if cls is not None:
  831. self.can_create_with_copy_constructor = has_copy_constructor(cls)
  832. self.can_create_with_default_constructor = (has_public_assign(cls) and has_trivial_constructor(cls))
  833. self.class_name, base_arg_type_c_str = global_context.get_class_data(cls)
  834. else: # For class declaration with no concrete classes.
  835. self.can_create_with_copy_constructor = None
  836. self.can_create_with_default_constructor = None
  837. self.class_name, base_arg_type_c_str = global_context.get_class_data(curr_arg)
  838. if len(ptrs_list) > 0:
  839. if ptrs_list.pop(): # The class ptr covers 1 redirection level...
  840. base_arg_type_c_str = "const " + base_arg_type_c_str #...but we shouldn't forget the const correctness for the ptr we've just removed.
  841. self.is_redirected = False
  842. else:
  843. base_arg_type_c_str = strip_global_ns(curr_arg.build_decl_string())
  844. if self.is_ref: # The (is_class and is_ref) case is dealt in the is_class case.
  845. ptrs_list.append(True) # We add a const indirection. Notice that self.is_const is about the contents - not about the ptr.
  846. curr_ptrs_list = []
  847. for is_ptr_const in reversed(ptrs_list): # reversed - since ptrs are read from right-to-left.
  848. if is_ptr_const:
  849. curr_ptrs_list.append('* const')
  850. else:
  851. curr_ptrs_list.append('*')
  852. ptrs_str = ''.join(curr_ptrs_list)
  853. const_content_str = ""
  854. if self.is_const:
  855. const_content_str = "const "
  856. self.arg_type_c_str = "%s%s%s" % (const_content_str, base_arg_type_c_str, ptrs_str)
  857. if self.is_class:
  858. self.cast_str = self.arg_type_c_str.replace(global_context.get_class_data(curr_arg)[1], self.class_name+'*')
  859. if self.is_c_bool:
  860. self.cast_str = self.arg_type_c_str
  861. self.arg_type_c_str = self.arg_type_c_str.replace("bool", C_BOOL_TYPE_NAME)
  862. if self.is_func_ptr and not(self.is_typedef): # TODO: Is this position covers all bases?
  863. self.arg_type_c_str = self.func_ptr_info.type_str
  864.  
  865. if len(ptrs_list) > 0:
  866. self.is_ptr = True
  867.  
  868. def is_void(self):
  869. """Returns whether the argument is void."""
  870. return is_void(self.arg_type)
  871.  
  872. def get_type_name_str(self):
  873. """Returns the type and name argument string."""
  874. if self.is_func_ptr and not(self.is_typedef): # TODO: What about if the typedef is stripped down?
  875. return self.arg_type_c_str.replace("(*)", "(*%s)" % (self.arg_name,))
  876. return "%s %s" % (self.arg_type_c_str, self.arg_name)
  877.  
  878. class FuncPtrInfo:
  879. """A class to parse a function pointer."""
  880.  
  881. def __init__(self, func_type, name, global_context):
  882. self.func_args_info_list = []
  883. self.func_type = func_type
  884. self.name = name
  885.  
  886. for arg in func_type.arguments_types:
  887. self.func_args_info_list.append(ArgInfo(arg, global_context))
  888.  
  889. self.ret_type_info = ArgInfo(func_type.return_type, global_context)
  890.  
  891. func_args_decl_list = [arg_info.arg_type_c_str for arg_info in self.func_args_info_list]
  892. func_args_str = ", ".join(func_args_decl_list)
  893.  
  894. self.type_str = "%s (*%s)(%s)" % (self.ret_type_info.arg_type_c_str, name, func_args_str)
  895.  
  896. class FuncInfo:
  897. """A class to parse a function or a class method."""
  898.  
  899. FREE_FUNC = 0
  900. FREE_OP = 1
  901. MEMBER_FUNC = 2
  902. MEMBER_OP = 3
  903. CTOR = 4
  904. DTOR = 5
  905. FUNC_TYPE_MAP = {free_function_t: FREE_FUNC,
  906. free_operator_t: FREE_OP,
  907. member_function_t: MEMBER_FUNC,
  908. member_operator_t: MEMBER_OP,
  909. constructor_t: CTOR,
  910. destructor_t: DTOR}
  911.  
  912. def __init__(self, func, global_context, generate_error_arg, generate_min_args_ver_only=False):
  913. if func.has_ellipsis:
  914. raise UnsupportedError("Ellipsis arg types are not handeled.")
  915.  
  916. self.func_args_info_list = []
  917. self.func = func
  918. self.full_name = global_context.get_full_name(func)
  919. self.c_func_name = global_context.get_c_name(func)
  920.  
  921. self.func_type = self.FUNC_TYPE_MAP[type(func)]
  922. if (self.func_type == self.MEMBER_OP) or (self.func_type == self.FREE_OP):
  923. if not("operator_" in self.c_func_name):
  924. # Fix missing space in the func name ("operator+" -> "operator_+").
  925. self.c_func_name = self.c_func_name.replace("operator", "operator_")
  926. for op_name in OPERATORS_LIST_BY_LENGTH:
  927. self.c_func_name = self.c_func_name.replace(op_name, OPERATOR_MAP[op_name])
  928.  
  929. self.generate_error_arg = generate_error_arg
  930. self.is_c99 = global_context.is_c99
  931.  
  932. if generate_min_args_ver_only:
  933. self.optional_args_num = 0
  934. else:
  935. self.optional_args_num = len(func.optional_args) # There are always len(func.optional_args) optional arguments, but we don't want to use them when we generate_min_args_ver_only.
  936. if generate_min_args_ver_only:
  937. arguments = func.required_args
  938. else:
  939. arguments = func.arguments
  940. for arg in arguments:
  941. self.func_args_info_list.append(ArgInfo(arg.decl_type, global_context, arg.name))
  942.  
  943. self.class_redirection = ""
  944. if (self.func_type == self.MEMBER_FUNC) or (self.func_type == self.DTOR) or (self.func_type == self.MEMBER_OP):
  945. self.class_name, class_c_ptr = global_context.get_class_data(func.parent)
  946. self.class_arg_c_str = "%s %s" % (class_c_ptr, THIS_VAR_NAME)
  947.  
  948. if (self.func_type == self.MEMBER_FUNC) or (self.func_type == self.MEMBER_OP):
  949. self.is_static = func.has_static
  950.  
  951. if self.is_static:
  952. self.c_func_name += "_static"
  953. self.class_redirection = ""
  954.  
  955. const_class_redirection_str = ""
  956. if func.has_const:
  957. self.class_arg_c_str = "const " + self.class_arg_c_str
  958. self.c_func_name += "_const"
  959. const_class_redirection_str = "const "
  960.  
  961. if not self.is_static:
  962. self.class_redirection = "((%s%s*) %s)->" % (const_class_redirection_str, self.class_name, THIS_VAR_NAME,)
  963.  
  964. if self.func_type == self.CTOR:
  965. self.ret_type_info = ArgInfo(func.parent, global_context)
  966. # TODO: The ctor returns a ptr to the class. Here we put the class_t and not pointer_t(class_t) - since it messes-up the ArgInfo's ctor.
  967. # The reason it works is that handling class and class-ptr is the same - but depending on it is very bad.
  968. elif (self.func_type == self.DTOR):
  969. self.ret_type_info = ArgInfo(void_t(), global_context)
  970. else:
  971. self.ret_type_info = ArgInfo(func.return_type, global_context)
  972.  
  973. def gen_func_args_c_strs(self):
  974. """A generator to the func args types and names."""
  975. if self.generate_error_arg:
  976. yield get_error_arg_str(self.is_c99)
  977. if (self.func_type == self.DTOR) or (self.func_type == self.MEMBER_OP) or ((self.func_type == self.MEMBER_FUNC) and not self.is_static):
  978. yield self.class_arg_c_str
  979. for arg_info in self.func_args_info_list:
  980. yield arg_info.get_type_name_str()
  981.  
  982. def is_default_ctor(self):
  983. """Returns whether the func is a default ctor."""
  984. if self.func_type == self.CTOR:
  985. return is_trivial_constructor(self.func)
  986. return False
  987.  
  988.  
  989. def unsupported_wrapper(func, ignore_unsupported_features=True):
  990. """A decorator to ignore unsupported features exception, if enabled."""
  991. def decorated(*args, **kws):
  992. try:
  993. func(*args, **kws)
  994. except UnsupportedError, ex:
  995. if ignore_unsupported_features:
  996. print ex.args[0]
  997. else:
  998. raise
  999. return decorated
  1000.  
  1001.  
  1002. def generate_c_wrapper(header_file_path, generate_dl=True, generate_exception_handling_code=True, is_compact_string=True, is_assume_copy=False, is_assume_assign=False, generate_error_arg=True, is_verbose=False, generate_operators=True, ignore_unsupported_features=True, is_c99=False, is_camel_case=False, gccxml_file_path = '', compiler_type = None):
  1003. """Outputs a C wrapper for header_file_path."""
  1004.  
  1005. if generate_error_arg and not(generate_exception_handling_code):
  1006. print "Ignoring error argument generation option, since the exception handling generation option is disabled"
  1007. generate_error_arg = False
  1008.  
  1009. header_file_path=os.path.abspath(header_file_path)
  1010.  
  1011. output_class = CodeOutputClass(header_file_path, generate_exception_handling_code, generate_dl, is_compact_string, generate_operators, is_assume_copy, is_assume_assign, generate_error_arg, is_verbose, is_camel_case)
  1012. global_context = CodeContext(header_file_path, gccxml_file_path, compiler_type, is_c99)
  1013.  
  1014. output_class.output_prefix_code(global_context.is_c99)
  1015.  
  1016. output_class.output_typedef=unsupported_wrapper(output_class.output_typedef, ignore_unsupported_features)
  1017. output_class.output_func=unsupported_wrapper(output_class.output_func, ignore_unsupported_features)
  1018.  
  1019. try:
  1020. string_typedef = global_context.typedef(name="::std::string")
  1021. output_class.output_std_string(string_typedef, global_context)
  1022. string_typedef = global_context.typedef(name="::std::wstring")
  1023. output_class.output_std_string(string_typedef, global_context)
  1024. except pygccxml.declarations.runtime_errors.declaration_not_found_t:
  1025. pass
  1026.  
  1027. for cls in global_context.classes(header_file=header_file_path, allow_empty=True):
  1028. output_class.output_class_typedef(cls, global_context)
  1029.  
  1030. for typedef in global_context.typedefs(header_file=header_file_path, allow_empty=True):
  1031. output_class.output_typedef(typedef, global_context)
  1032.  
  1033. for enum in global_context.enumerations(header_file=header_file_path, allow_empty=True):
  1034. output_class.output_enum(enum, global_context)
  1035.  
  1036. for cls in global_context.classes(header_file=header_file_path, allow_empty=True):
  1037. output_class.output_class_code(cls, global_context)
  1038.  
  1039. for free_func in global_context.free_functions(header_file=header_file_path, allow_empty=True):
  1040. output_class.output_func(free_func, global_context)
  1041.  
  1042. if output_class.generate_operators:
  1043. for free_op in global_context.free_operators(header_file=header_file_path, allow_empty=True):
  1044. output_class.output_func(free_op, global_context)
  1045.  
  1046. for elem_type, elem in global_context.gen_recursive_elems():
  1047. if elem_type == global_context.CLASS:
  1048. output_class.output_class_typedef(elem, global_context)
  1049. output_class.output_class_code(elem, global_context)
  1050. elif elem_type == global_context.TYPEDEF:
  1051. output_class.output_typedef(elem, global_context)
  1052. elif elem_type == global_context.ENUM:
  1053. output_class.output_enum(elem, global_context)
  1054.  
  1055. output_class.output_suffix_code()
  1056.  
  1057. output_class.close() # Forces the output file creation.
  1058.  
  1059.  
  1060. def safe_config_get_wrapper(config_get_func):
  1061. """A decorator to mask ConfigParser methods from option not existing exception, returning a default value instead."""
  1062. def decorated(section_name, key_name, def_val=None):
  1063. try:
  1064. return config_get_func(section_name, key_name)
  1065. except ConfigParser.NoOptionError:
  1066. return def_val
  1067. return decorated
  1068.  
  1069. def get_option(options, option, def_val):
  1070. """Returns a default value (other than None) when an optparse var option does not exist."""
  1071. ret_val = getattr(options, option)
  1072. if ret_val is None:
  1073. return def_val
  1074. return ret_val
  1075.  
  1076. def parse_option(config_get_func, section_name, option_name, options, def_val):
  1077. """Parses one program option. The args parsing order is:
  1078. 1. Command line args.
  1079. 2. Config file options.
  1080. 3. Default values."""
  1081. option = def_val
  1082. if config_get_func is not None:
  1083. option = config_get_func(section_name, option_name, def_val)
  1084. return get_option(options, option_name, option)
  1085.  
  1086. if __name__ == '__main__':
  1087.  
  1088. cmd_line_parser = OptionParser("usage: %prog [options] <header_file_path>")
  1089. cmd_line_parser.add_option("-g", "--gccxml", dest='gccxml_file_path', help="The gccxml file path")
  1090. cmd_line_parser.add_option("-c", "--config", dest='config_file_path', help="The config file path")
  1091. cmd_line_parser.add_option("-t", "--compiler", dest='compiler_type', help="The compiler type")
  1092. cmd_line_parser.add_option("-i", "--ignore", action='store_false', dest='ignore_unsupported_features', help="Raise exception if an unsupported feature (like templates) is encountered.")
  1093. cmd_line_parser.add_option("-d", "--dl", action='store_false', dest='generate_dl', help="Don't generate a def file (and a DllMain() function under Windows).")
  1094. cmd_line_parser.add_option("-e", "--error", action='store_false', dest='generate_error_arg', help="Don't add error output args.")
  1095. cmd_line_parser.add_option("-n", "--nothrow", action='store_false', dest='generate_exception_handling_code', help="Don't generate exception handling code.")
  1096. cmd_line_parser.add_option("-v", "--verbose", action='store_false', dest='is_verbose', help="Don'e generate verbose output.")
  1097. cmd_line_parser.add_option("-9", "--c99", action='store_true', dest='is_c99', help="Compiler with C99 support.")
  1098. cmd_line_parser.add_option("-o", "--operator", action='store_false', dest='generate_operators', help="Don't generate operators.")
  1099. cmd_line_parser.add_option("-s", "--string", action='store_false', dest='is_compact_string', help="Output std::string in a compact format.")
  1100. cmd_line_parser.add_option("--camel", action='store_true', dest='is_camel_case', help="The functions would be outputed in (Upper) Camel Case conventions, not Python conventions (e.g.: FuncName and not func_name).")
  1101. cmd_line_parser.add_option("--copy", action='store_true', dest='is_assume_copy', help="Assume public copy constructor for class declarations with no concrete classes.")
  1102. cmd_line_parser.add_option("--assign", action='store_true', dest='is_assume_assign', help="Assume public default constructor and assignment operator for class delarations with no concrete classes.")
  1103. (options, args) = cmd_line_parser.parse_args()
  1104.  
  1105. if len(args) != 1:
  1106. cmd_line_parser.error("<header_file_path> is required")
  1107.  
  1108. safe_config_get = None
  1109. safe_config_get_bool = None
  1110. if options.config_file_path is not None:
  1111. config = ConfigParser.RawConfigParser()
  1112. config.read(options.config_file_path)
  1113. safe_config_get = safe_config_get_wrapper(config.get)
  1114. safe_config_get_bool = safe_config_get_wrapper(config.getboolean)
  1115.  
  1116. generate_dl = parse_option(safe_config_get_bool, 'Cpp2C Config', 'generate_dl', options, True)
  1117. generate_error_arg = parse_option(safe_config_get_bool, 'Cpp2C Config', 'generate_error_arg', options, True)
  1118. ignore_unsupported_features = parse_option(safe_config_get_bool, 'Cpp2C Config', 'ignore_unsupported_features', options, True)
  1119. generate_exception_handling_code = parse_option(safe_config_get_bool, 'Cpp2C Config', 'generate_exception_handling_code', options, True)
  1120. gccxml_file_path = parse_option(safe_config_get, 'GccXml Config', 'gccxml_file_path', options, "")
  1121. compiler_type = parse_option(safe_config_get, 'GccXml Config', 'compiler_type', options, None)
  1122. is_verbose = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_verbose', options, True)
  1123. is_c99 = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_c99', options, False)
  1124. generate_operators = parse_option(safe_config_get_bool, 'Cpp2C Config', 'generate_operators', options, True)
  1125. is_compact_string = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_compact_string', options, True)
  1126. is_camel_case = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_camel_case', options, False)
  1127. is_assume_copy = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_assume_copy', options, False)
  1128. is_assume_assign = parse_option(safe_config_get_bool, 'Cpp2C Config', 'is_assume_assign', options, False)
  1129.  
  1130. generate_c_wrapper(args[0], generate_dl, generate_exception_handling_code, is_compact_string, is_assume_copy, is_assume_assign, generate_error_arg, is_verbose, generate_operators, ignore_unsupported_features, is_c99, is_camel_case, gccxml_file_path, compiler_type)
  1131. print "Done."
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement