SHARE
TWEET

Untitled

a guest Aug 25th, 2019 59 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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."
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top