[STRIP_SUFFIX] ability to flag suffixes to be stripped.
[gnome.gobject-introspection] / giscanner / transformer.py
index 2746b6e..6179c2b 100644 (file)
 #
 
 import os
+import sys
 
 from .ast import (Bitfield, Callback, Enum, Function, Namespace, Member,
                   Parameter, Return, Struct, Field,
                   Type, Array, Alias, Interface, Class, Node, Union,
                   Varargs, Constant, type_name_from_ctype,
                   type_names, TYPE_STRING, BASIC_GIR_TYPES)
-from .config import DATADIR
+from .config import DATADIR, GIR_DIR, GIR_SUFFIX
 from .glibast import GLibBoxed
 from .girparser import GIRParser
 from .odict import odict
@@ -46,6 +47,8 @@ _xdg_data_dirs = [x for x in os.environ.get('XDG_DATA_DIRS', '').split(':') \
 class SkipError(Exception):
     pass
 
+class VaListSkipError(SkipError):
+    pass
 
 class Names(object):
     names = property(lambda self: self._names)
@@ -80,9 +83,15 @@ class Transformer(object):
     def get_includes(self):
         return self._includes
 
+    def set_strip_suffix(self, strip_suffix):
+        self._strip_suffix = strip_suffix
+
     def set_strip_prefix(self, strip_prefix):
         self._strip_prefix = strip_prefix
 
+    def get_strip_prefix(self):
+        return self._strip_prefix
+
     def get_pkgconfig_packages(self):
         return self._pkg_config_packages
 
@@ -114,15 +123,17 @@ class Transformer(object):
     def _find_include(self, include):
         searchdirs = self._includepaths[:]
         for path in _xdg_data_dirs:
-            searchdirs.append(os.path.join(path, 'gir-1.0'))
+            searchdirs.append(os.path.join(path, GIR_SUFFIX))
+        searchdirs.append(GIR_DIR)
 
         girname = '%s-%s.gir' % (include.name, include.version)
         for d in searchdirs:
             path = os.path.join(d, girname)
             if os.path.exists(path):
                 return path
-        raise ValueError("Couldn't find include %r (search path: %r)"\
+        sys.stderr.write("Couldn't find include %r (search path: %r)\n"\
                          % (girname, searchdirs))
+        sys.exit(1)
 
     def _parse_include(self, filename):
         parser = self._cachestore.load(filename)
@@ -173,14 +184,23 @@ class Transformer(object):
         # when --strip-prefix=g:
         #   GHashTable -> HashTable
         #   g_hash_table_new -> hash_table_new
+        stripped = False
         prefix = self._strip_prefix.lower()
-        if isfunction:
+        
+        if isfunction and '_' in name:
             prefix += '_'
         if len(name) > len(prefix) and name.lower().startswith(prefix):
             name = name[len(prefix):]
+            stripped = True
 
         while name.startswith('_'):
             name = name[1:]
+
+        if (stripped and self._strip_suffix and 
+            len(name) > len(self._strip_suffix) and
+            name.endswith(self._strip_suffix)
+            name = name[:-1*len(self._strip_suffix)]
+            
         return name
 
     def _traverse_one(self, symbol, stype=None):
@@ -210,15 +230,13 @@ class Transformer(object):
 
     def _enum_common_prefix(self, symbol):
         def common_prefix(a, b):
-            alen = len(a)
-            blen = len(b)
-            l = min(alen, blen)
-            for i in xrange(l):
-                if a[i] != b[i]:
-                    return a[:i]
-            if alen > blen:
-                return b
-            return a
+            commonparts = []
+            for aword, bword in zip(a.split('_'), b.split('_')):
+                if aword != bword:
+                    return '_'.join(commonparts) + '_'
+                commonparts.append(aword)
+            return min(a, b)
+
         # Nothing less than 2 has a common prefix
         if len(list(symbol.base_type.child_list)) < 2:
             return None
@@ -265,8 +283,10 @@ class Transformer(object):
                       symbol.ident)
 
     def _type_is_callback(self, type):
-        if (isinstance(type, Callback) or
-            isinstance(self._typedefs_ns.get(type.name), Callback)):
+        if isinstance(type, Callback):
+            return True
+        node = self._names.names.get(type.name)
+        if node and isinstance(node[1], Callback):
             return True
         return False
 
@@ -279,9 +299,8 @@ class Transformer(object):
         return False
 
     def _handle_destroy(self, param, destroy_idx, destroy_param):
-        if ((self._namespace.name == 'GLib' and
-             destroy_param.type.name == 'DestroyNotify') or
-            destroy_param.type.name == 'GLib.DestroyNotify'):
+        if (destroy_param.type.name == 'GLib.DestroyNotify' or
+            destroy_param.type.ctype == 'GDestroyNotify'):
             param.destroy_name = destroy_param.name
             param.destroy_index = destroy_idx
             return True
@@ -292,6 +311,10 @@ class Transformer(object):
             if not self._type_is_callback(param.type):
                 continue
 
+            # set a default scope
+            if param.scope is None:
+                param.scope = 'call'
+
             # j is the index where we look for closure/destroy to
             # group with the callback param
             j = i + 1
@@ -348,7 +371,17 @@ class Transformer(object):
         source_type = symbol.base_type
         if (source_type.type == CTYPE_POINTER and
             symbol.base_type.base_type.type == CTYPE_FUNCTION):
-            node = self._create_callback(symbol)
+            try:
+                node = self._create_callback(symbol)
+            except VaListSkipError:
+                #this handles va_list members, and converts them
+                #to unwritable, unreadable void*
+                ftype = Type("any", "void*")
+                ftype = self.resolve_param_type(ftype)
+                node = Field(symbol.ident, ftype, ftype.name,
+                         readable=False, writable=False, bits=symbol.const_int)
+
+
         elif source_type.type == CTYPE_STRUCT and source_type.name is None:
             node = self._create_struct(symbol, anonymous=True)
         elif source_type.type == CTYPE_UNION and source_type.name is None:
@@ -455,7 +488,7 @@ class Transformer(object):
     def _create_type(self, source_type, is_param, is_retval):
         ctype = self._create_source_type(source_type)
         if ctype.startswith('va_list'):
-            raise SkipError()
+            raise VaListSkipError()
         # FIXME: FILE* should not be skipped, it should be handled
         #        properly instead
         elif ctype == 'FILE*':
@@ -472,9 +505,9 @@ class Transformer(object):
         rettype.derefed_canonical = self._canonicalize_ctype(derefed_ctype)
 
         canontype = type_name_from_ctype(ctype)
-        if ((canontype == TYPE_STRING or
-             source_type.type == CTYPE_POINTER) and
-            source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST):
+        # Is it a const char * or a const gpointer?
+        if ((canontype == TYPE_STRING or source_type.type == CTYPE_POINTER) and
+            (source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST)):
             rettype.is_const = True
         return rettype
 
@@ -497,7 +530,8 @@ class Transformer(object):
     def _create_const(self, symbol):
         # Don't create constants for non-public things
         # http://bugzilla.gnome.org/show_bug.cgi?id=572790
-        if not symbol.source_filename.endswith('.h'):
+        if (symbol.source_filename is None or
+            not symbol.source_filename.endswith('.h')):
             return None
         name = self.remove_prefix(symbol.ident)
         if symbol.const_string is not None:
@@ -662,7 +696,7 @@ class Transformer(object):
                                                      self.ctype_of(ptype),
                                                      names, **kwargs)
         elif isinstance(ptype, basestring):
-            return self.resolve_type_name_full(ptype, None, names, **kwargs)
+            return self.resolve_type_name_full(ptype, ptype, names, **kwargs)
         else:
             raise AssertionError("Unhandled param: %r" % (ptype, ))
         return ptype
@@ -682,3 +716,8 @@ class Transformer(object):
             else:
                 break
         return type_name
+
+    def iter_enums(self):
+        for node in self._namespace.nodes:
+            if isinstance(node, Enum):
+                yield node