[gobject-introspection/gir-docbook] Switch to storing string form of error quarks



commit d92fb1e2433e6c64e47da6277e30e8fad455e719
Author: Dan Winship <danw gnome org>
Date:   Thu May 19 16:21:13 2011 -0400

    Switch to storing string form of error quarks
    
    Instead of storing the name of the function to call to get the
    error quark, store the string form of the error quark, which
    we derive from the introspection binary during scanning.
    
    Update EnumBlob and GIEnumInfo to include the new information.
    
    This will allow determining a back-mapping from error quark
    to error domain without having to dlsym() and call all the
    known error quark functions.
    
    Based on earlier patches from Owen Taylor and Maxim Ermilov.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=602516

 girepository/gdump.c               |   83 +++++++++++++++++++++++++++++-------
 girepository/gienuminfo.c          |   17 +++++++
 girepository/gienuminfo.h          |    1 +
 girepository/girnode.c             |    7 +++
 girepository/girnode.h             |    1 +
 girepository/girparser.c           |    4 ++
 girepository/girwriter.c           |    4 ++
 girepository/gitypelib-internal.h  |    4 +-
 giscanner/ast.py                   |   11 ++++-
 giscanner/dumper.py                |   26 +++++++++---
 giscanner/gdumpparser.py           |   41 +++++++++++++++---
 giscanner/girparser.py             |    4 +-
 giscanner/girwriter.py             |    4 +-
 giscanner/maintransformer.py       |    6 +--
 giscanner/scannermain.py           |    3 +-
 tests/scanner/Foo-1.0-expected.gir |    2 +-
 16 files changed, 177 insertions(+), 41 deletions(-)
---
diff --git a/girepository/gdump.c b/girepository/gdump.c
index cb6e741..e607f32 100644
--- a/girepository/gdump.c
+++ b/girepository/gdump.c
@@ -70,6 +70,7 @@ goutput_write (GOutputStream *out, const char *str)
 }
 
 typedef GType (*GetTypeFunc)(void);
+typedef GQuark (*ErrorQuarkFunc)(void);
 
 static GType
 invoke_get_type (GModule *self, const char *symbol, GError **error)
@@ -97,6 +98,23 @@ invoke_get_type (GModule *self, const char *symbol, GError **error)
   return ret;
 }
 
+static GQuark
+invoke_error_quark (GModule *self, const char *symbol, GError **error)
+{
+  ErrorQuarkFunc sym;
+
+  if (!g_module_symbol (self, symbol, (void**)&sym))
+    {
+      g_set_error (error,
+		   G_IO_ERROR,
+		   G_IO_ERROR_FAILED,
+		   "Failed to find symbol '%s'", symbol);
+      return G_TYPE_INVALID;
+    }
+
+  return sym ();
+}
+
 static void
 dump_properties (GType type, GOutputStream *out)
 {
@@ -365,6 +383,13 @@ dump_type (GType type, const char *symbol, GOutputStream *out)
     }
 }
 
+static void
+dump_error_quark (GQuark quark, const char *symbol, GOutputStream *out)
+{
+  escaped_printf (out, "  <error-quark function=\"%s\" domain=\"%s\"/>\n",
+		  symbol, g_quark_to_string (quark));
+}
+
 /**
  * g_irepository_dump:
  * @arg: Comma-separated pair of input and output filenames
@@ -437,29 +462,55 @@ g_irepository_dump (const char *arg, GError **error)
     {
       gsize len;
       char *line = g_data_input_stream_read_line (in, &len, NULL, NULL);
-      GType type;
+      const char *function;
 
       if (line == NULL || *line == '\0')
-	{
-	  g_free (line);
-	  break;
-	}
+        {
+          g_free (line);
+          break;
+        }
 
       g_strchomp (line);
-      type = invoke_get_type (self, line, error);
 
-      if (type == G_TYPE_INVALID)
-	{
-          caught_error = TRUE;
-	  g_free (line);
-	  break;
-	}
+      if (strncmp (line, "get-type:", strlen ("get-type:")) == 0)
+        {
+          GType type;
 
-      if (g_hash_table_lookup (output_types, (gpointer) type))
-	goto next;
-      g_hash_table_insert (output_types, (gpointer) type, (gpointer) type);
+          function = line + strlen ("get-type:");
+
+          type = invoke_get_type (self, function, error);
+
+          if (type == G_TYPE_INVALID)
+            {
+              g_printerr ("Invalid GType function: '%s'\n", function);
+              caught_error = TRUE;
+              g_free (line);
+              break;
+            }
+
+          if (g_hash_table_lookup (output_types, (gpointer) type))
+            goto next;
+          g_hash_table_insert (output_types, (gpointer) type, (gpointer) type);
+
+          dump_type (type, function, G_OUTPUT_STREAM (output));
+        }
+      else if (strncmp (line, "error-quark:", strlen ("error-quark:")) == 0)
+        {
+          GQuark quark;
+          function = line + strlen ("error-quark:");
+          quark = invoke_error_quark (self, function, error);
+
+          if (quark == 0)
+            {
+              g_printerr ("Invalid error quark function: '%s'\n", function);
+              caught_error = TRUE;
+              g_free (line);
+              break;
+            }
+
+          dump_error_quark (quark, function, G_OUTPUT_STREAM (output));
+        }
 
-      dump_type (type, line, G_OUTPUT_STREAM (output));
 
     next:
       g_free (line);
diff --git a/girepository/gienuminfo.c b/girepository/gienuminfo.c
index 062f3ab..338a46e 100644
--- a/girepository/gienuminfo.c
+++ b/girepository/gienuminfo.c
@@ -66,6 +66,23 @@ g_enum_info_get_n_values (GIEnumInfo *info)
   return blob->n_values;
 }
 
+const gchar *
+g_enum_info_get_error_domain (GIEnumInfo *info)
+{
+  GIRealInfo *rinfo = (GIRealInfo *)info;
+  EnumBlob *blob;
+
+  g_return_val_if_fail (info != NULL, 0);
+  g_return_val_if_fail (GI_IS_ENUM_INFO (info), 0);
+
+  blob = (EnumBlob *)&rinfo->typelib->data[rinfo->offset];
+
+  if (blob->error_domain)
+    return g_typelib_get_string (rinfo->typelib, blob->error_domain);
+  else
+    return NULL;
+}
+
 /**
  * g_enum_info_get_value:
  * @info: a #GIEnumInfo
diff --git a/girepository/gienuminfo.h b/girepository/gienuminfo.h
index 6b24fe7..fc0f3c8 100644
--- a/girepository/gienuminfo.h
+++ b/girepository/gienuminfo.h
@@ -41,6 +41,7 @@ gint           g_enum_info_get_n_values      (GIEnumInfo  *info);
 GIValueInfo  * g_enum_info_get_value         (GIEnumInfo  *info,
 					      gint         n);
 GITypeTag      g_enum_info_get_storage_type  (GIEnumInfo  *info);
+const gchar *  g_enum_info_get_error_domain  (GIEnumInfo  *info);
 
 gint64         g_value_info_get_value        (GIValueInfo *info);
 
diff --git a/girepository/girnode.c b/girepository/girnode.c
index 1c51bfd..166ca30 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -328,6 +328,7 @@ _g_ir_node_free (GIrNode *node)
 	g_free (node->name);
 	g_free (enum_->gtype_name);
 	g_free (enum_->gtype_init);
+	g_free (enum_->error_domain);
 
 	for (l = enum_->values; l; l = l->next)
 	  _g_ir_node_free ((GIrNode *)l->data);
@@ -712,6 +713,8 @@ _g_ir_node_get_full_size_internal (GIrNode *parent,
 	    size += ALIGN_VALUE (strlen (enum_->gtype_name) + 1, 4);
 	    size += ALIGN_VALUE (strlen (enum_->gtype_init) + 1, 4);
 	  }
+	if (enum_->error_domain)
+	  size += ALIGN_VALUE (strlen (enum_->error_domain) + 1, 4);
 
 	for (l = enum_->values; l; l = l->next)
 	  size += _g_ir_node_get_full_size_internal (node, (GIrNode *)l->data);
@@ -2021,6 +2024,10 @@ _g_ir_node_build_typelib (GIrNode         *node,
 	    blob->gtype_name = 0;
 	    blob->gtype_init = 0;
 	  }
+	if (enum_->error_domain)
+	  blob->error_domain = _g_ir_write_string (enum_->error_domain, strings, data, offset2);
+	else
+	  blob->error_domain = 0;
 
 	blob->n_values = 0;
 	blob->reserved2 = 0;
diff --git a/girepository/girnode.h b/girepository/girnode.h
index fb2616b..6e03821 100644
--- a/girepository/girnode.h
+++ b/girepository/girnode.h
@@ -285,6 +285,7 @@ struct _GIrNodeEnum
 
   gchar *gtype_name;
   gchar *gtype_init;
+  gchar *error_domain;
 
   GList *values;
 };
diff --git a/girepository/girparser.c b/girepository/girparser.c
index 4e55272..c9b7d62 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -1332,6 +1332,7 @@ start_enum (GMarkupParseContext *context,
   const gchar *typename;
   const gchar *typeinit;
   const gchar *deprecated;
+  const gchar *error_domain;
   GIrNodeEnum *enum_;
 
   if (!((strcmp (element_name, "enumeration") == 0 && ctx->state == STATE_NAMESPACE) ||
@@ -1344,6 +1345,7 @@ start_enum (GMarkupParseContext *context,
   name = find_attribute ("name", attribute_names, attribute_values);
   typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
   typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
+  error_domain = find_attribute ("glib:error-domain", attribute_names, attribute_values);
   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
 
   if (name == NULL)
@@ -1361,6 +1363,8 @@ start_enum (GMarkupParseContext *context,
   ((GIrNode *)enum_)->name = g_strdup (name);
   enum_->gtype_name = g_strdup (typename);
   enum_->gtype_init = g_strdup (typeinit);
+  enum_->error_domain = g_strdup (error_domain);
+
   if (deprecated)
     enum_->deprecated = TRUE;
   else
diff --git a/girepository/girwriter.c b/girepository/girwriter.c
index 2cdc9a1..d9f916c 100644
--- a/girepository/girwriter.c
+++ b/girepository/girwriter.c
@@ -805,6 +805,7 @@ write_enum_info (const gchar *namespace,
   const gchar *name;
   const gchar *type_name;
   const gchar *type_init;
+  const gchar *error_domain;
   gboolean deprecated;
   gint i;
 
@@ -813,6 +814,7 @@ write_enum_info (const gchar *namespace,
 
   type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
   type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+  error_domain = g_enum_info_get_error_domain (info);
 
   if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_ENUM)
     xml_start_element (file, "enumeration");
@@ -822,6 +824,8 @@ write_enum_info (const gchar *namespace,
 
   if (type_init)
     xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init);
+  if (error_domain)
+    xml_printf (file, " glib:error-domain=\"%s\"", error_domain);
 
   if (deprecated)
     xml_printf (file, " deprecated=\"1\"");
diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h
index 2bda8d9..49fbe4e 100644
--- a/girepository/gitypelib-internal.h
+++ b/girepository/gitypelib-internal.h
@@ -798,6 +798,8 @@ typedef struct {
  * (will be a signed or unsigned integral type)
  * @gtype_name: String name of the associated #GType
  * @gtype_init: String naming the symbol which gets the runtime #GType
+ * @error_domain: String naming the #GError domain this enum is
+ *   associated with
  * @n_values: The lengths of the values arrays.
  * @values: Describes the enum values.
  */
@@ -817,7 +819,7 @@ typedef struct {
   guint16   n_values;
   guint16   reserved2;
 
-  guint32   reserved3;
+  guint32   error_domain;
 
   ValueBlob values[];
 } EnumBlob;
diff --git a/giscanner/ast.py b/giscanner/ast.py
index d4780f9..bd56aef 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -569,6 +569,13 @@ class Function(Callable):
         self.shadows = None # C symbol string
 
 
+class ErrorQuarkFunction(Function):
+
+    def __init__(self, name, retval, parameters, throws, symbol, error_domain):
+        Function.__init__(self, name, retval, parameters, throws, symbol)
+        self.error_domain = error_domain
+
+
 class VFunction(Callable):
 
     def __init__(self, name, retval, parameters, throws):
@@ -704,8 +711,8 @@ class Enum(Node, Registered):
         self.c_symbol_prefix = c_symbol_prefix
         self.ctype = ctype
         self.members = members
-        # Associated error quark
-        self.error_quark = None
+        # Associated error domain name
+        self.error_domain = None
 
 
 class Bitfield(Node, Registered):
diff --git a/giscanner/dumper.py b/giscanner/dumper.py
index 615b3fc..61cba25 100644
--- a/giscanner/dumper.py
+++ b/giscanner/dumper.py
@@ -76,9 +76,10 @@ class LinkerError(Exception):
 
 class DumpCompiler(object):
 
-    def __init__(self, options, get_type_functions):
+    def __init__(self, options, get_type_functions, error_quark_functions):
         self._options = options
         self._get_type_functions = get_type_functions
+        self._error_quark_functions = error_quark_functions
 
         self._compiler_cmd = os.environ.get('CC', 'gcc')
         self._linker_cmd = os.environ.get('CC', self._compiler_cmd)
@@ -114,9 +115,9 @@ class DumpCompiler(object):
         f = open(c_path, 'w')
         f.write(_PROGRAM_TEMPLATE % tpl_args)
 
-        # We need to reference our get_type functions to make sure they are
-        # pulled in at the linking stage if the library is a static library
-        # rather than a shared library.
+        # We need to reference our get_type and error_quark functions
+        # to make sure they are pulled in at the linking stage if the
+        # library is a static library rather than a shared library.
         if len(self._get_type_functions) > 0:
             for func in self._get_type_functions:
                 f.write("extern GType " + func + "(void);\n")
@@ -129,6 +130,18 @@ class DumpCompiler(object):
                     f.write(",\n")
                 f.write("  " + func)
             f.write("\n};\n")
+        if len(self._error_quark_functions) > 0:
+            for func in self._error_quark_functions:
+                f.write("extern GQuark " + func + "(void);\n")
+            f.write("GQuark (*GI_ERROR_QUARK_FUNCS_[])(void) = {\n")
+            first = True
+            for func in self._error_quark_functions:
+                if first:
+                    first = False
+                else:
+                    f.write(",\n")
+                f.write("  " + func)
+            f.write("\n};\n")
         f.close()
 
         o_path = self._generate_tempfile(tmpdir, '.o')
@@ -271,6 +284,7 @@ class DumpCompiler(object):
             else:
                 args.append('-l' + library)
 
-def compile_introspection_binary(options, get_type_functions):
-    dc = DumpCompiler(options, get_type_functions)
+def compile_introspection_binary(options, get_type_functions,
+                                 error_quark_functions):
+    dc = DumpCompiler(options, get_type_functions, error_quark_functions)
     return dc.run()
diff --git a/giscanner/gdumpparser.py b/giscanner/gdumpparser.py
index 87621bc..35fea72 100644
--- a/giscanner/gdumpparser.py
+++ b/giscanner/gdumpparser.py
@@ -68,7 +68,8 @@ class GDumpParser(object):
         self._namespace = transformer.namespace
         self._binary = None
         self._get_type_functions = []
-        self._gtype_data = {}
+        self._error_quark_functions = []
+        self._error_domains = {}
         self._boxed_types = {}
         self._private_internal_types = {}
 
@@ -94,6 +95,9 @@ class GDumpParser(object):
     def get_get_type_functions(self):
         return self._get_type_functions
 
+    def get_error_quark_functions(self):
+        return self._error_quark_functions
+
     def set_introspection_binary(self, binary):
         self._binary = binary
 
@@ -105,9 +109,10 @@ class GDumpParser(object):
         tree = self._execute_binary_get_tree()
         root = tree.getroot()
         for child in root:
-            self._gtype_data[child.attrib['name']] = child
-        for child in root:
-            self._introspect_type(child)
+            if child.tag == 'error-quark':
+                self._introspect_error_quark(child)
+            else:
+                self._introspect_type(child)
 
         # Pair up boxed types and class records
         for name, boxed in self._boxed_types.iteritems():
@@ -138,10 +143,14 @@ class GDumpParser(object):
     def _execute_binary_get_tree(self):
         """Load the library (or executable), returning an XML
 blob containing data gleaned from GObject's primitive introspection."""
-        in_path = os.path.join(self._binary.tmpdir, 'types.txt')
+        in_path = os.path.join(self._binary.tmpdir, 'functions.txt')
         f = open(in_path, 'w')
-        # TODO: Introspect GQuark functions
         for func in self._get_type_functions:
+            f.write('get-type:')
+            f.write(func)
+            f.write('\n')
+        for func in self._error_quark_functions:
+            f.write('error-quark:')
             f.write(func)
             f.write('\n')
         f.close()
@@ -209,6 +218,8 @@ blob containing data gleaned from GObject's primitive introspection."""
             return
         elif (symbol.endswith('_get_type') or symbol.endswith('_get_gtype')):
             self._initparse_get_type_function(func)
+        elif symbol.endswith('_error_quark'):
+            self._initparse_error_quark_function(func)
 
     def _initparse_get_type_function(self, func):
         if func.symbol in ('g_object_get_type',
@@ -229,6 +240,12 @@ blob containing data gleaned from GObject's primitive introspection."""
         self._get_type_functions.append(func.symbol)
         return True
 
+    def _initparse_error_quark_function(self, func):
+        if (func.retval.type.ctype != 'GQuark'):
+            return False
+        self._error_quark_functions.append(func.symbol)
+        return True
+
     def _initparse_gobject_record(self, record):
         # Special handling for when we're parsing GObject / GLib
         if record.name in ('Object', 'InitiallyUnowned', 'ParamSpec'):
@@ -495,6 +512,18 @@ different --identifier-prefix.""" % (xmlnode.attrib['name'], self._namespace.ide
                 # (see also _find_class_record and transformer.py)
                 field.writable = False
 
+    def _introspect_error_quark(self, xmlnode):
+        symbol = xmlnode.attrib['function']
+        error_domain = xmlnode.attrib['domain']
+        function = self._namespace.get_by_symbol(symbol)
+        if function is None:
+            return
+
+        node = ast.ErrorQuarkFunction(function.name, function.retval,
+                                      function.parameters, function.throws,
+                                      function.symbol, error_domain)
+        self._namespace.append(node, replace=True)
+
     def _pair_boxed_type(self, boxed):
         try:
             name = self._transformer.strip_identifier(boxed.gtype_name)
diff --git a/giscanner/girparser.py b/giscanner/girparser.py
index bcf68bf..45a93ed 100644
--- a/giscanner/girparser.py
+++ b/giscanner/girparser.py
@@ -536,7 +536,7 @@ class GIRParser(object):
         ctype = node.attrib.get(_cns('type'))
         get_type = node.attrib.get(_glibns('get-type'))
         type_name = node.attrib.get(_glibns('type-name'))
-        glib_error_quark = node.attrib.get(_glibns('error-quark'))
+        glib_error_domain = node.attrib.get(_glibns('error-domain'))
         if node.tag == _corens('bitfield'):
             klass = ast.Bitfield
         else:
@@ -546,7 +546,7 @@ class GIRParser(object):
                     members=members,
                     gtype_name=type_name,
                     get_type=get_type)
-        obj.error_quark = glib_error_quark
+        obj.error_domain = glib_error_domain
         obj.ctype = ctype
         self._parse_generic_attribs(node, obj)
         self._namespace.append(obj)
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index 4a6c47e..1da2417 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -328,8 +328,8 @@ and/or use gtk-doc annotations. ''')
         self._append_node_generic(enum, attrs)
         self._append_registered(enum, attrs)
         attrs.append(('c:type', enum.ctype))
-        if enum.error_quark:
-            attrs.append(('glib:error-quark', enum.error_quark))
+        if enum.error_domain:
+            attrs.append(('glib:error-domain', enum.error_domain))
 
         with self.tagcontext('enumeration', attrs):
             self._write_generic(enum)
diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py
index 34d17b4..d2d1f2d 100644
--- a/giscanner/maintransformer.py
+++ b/giscanner/maintransformer.py
@@ -858,9 +858,7 @@ the ones that failed to resolve removed."""
                 uscore_enums[no_uscore_prefixed] = enum
 
         for node in self._namespace.itervalues():
-            if not isinstance(node, ast.Function):
-                continue
-            if node.retval.type.target_giname != 'GLib.Quark':
+            if not isinstance(node, ast.ErrorQuarkFunction):
                 continue
             short = node.symbol[:-len('_quark')]
             if short == "g_io_error":
@@ -872,7 +870,7 @@ the ones that failed to resolve removed."""
                 if enum is None:
                     enum = uscore_enums.get(short)
             if enum is not None:
-                enum.error_quark = node.symbol
+                enum.error_domain = node.error_domain
             else:
                 message.warn_node(node,
                     """%s: Couldn't find corresponding enumeration""" % (node.symbol, ))
diff --git a/giscanner/scannermain.py b/giscanner/scannermain.py
old mode 100644
new mode 100755
index 52ee4cc..3c1386a
--- a/giscanner/scannermain.py
+++ b/giscanner/scannermain.py
@@ -300,7 +300,8 @@ def create_binary(transformer, options, args):
         binary = IntrospectionBinary(args)
     else:
         binary = compile_introspection_binary(options,
-                                              gdump_parser.get_get_type_functions())
+                                              gdump_parser.get_get_type_functions(),
+                                              gdump_parser.get_error_quark_functions())
 
     shlibs = resolve_shlibs(options, binary, options.libraries)
     gdump_parser.set_introspection_binary(binary)
diff --git a/tests/scanner/Foo-1.0-expected.gir b/tests/scanner/Foo-1.0-expected.gir
index 8b9dc38..cc4c8d7 100644
--- a/tests/scanner/Foo-1.0-expected.gir
+++ b/tests/scanner/Foo-1.0-expected.gir
@@ -191,7 +191,7 @@ and/or use gtk-doc annotations.  -->
                  glib:type-name="FooError"
                  glib:get-type="foo_error_get_type"
                  c:type="FooError"
-                 glib:error-quark="foo_error_quark">
+                 glib:error-domain="foo-error-quark">
       <member name="good"
               value="0"
               c:identifier="FOO_ERROR_GOOD"



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]