Switch to storing string form of error quarks
authorDan Winship <danw@gnome.org>
Thu, 19 May 2011 20:21:13 +0000 (16:21 -0400)
committerDan Winship <danw@gnome.org>
Fri, 12 Aug 2011 15:10:43 +0000 (11:10 -0400)
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

16 files changed:
girepository/gdump.c
girepository/gienuminfo.c
girepository/gienuminfo.h
girepository/girnode.c
girepository/girnode.h
girepository/girparser.c
girepository/girwriter.c
girepository/gitypelib-internal.h
giscanner/ast.py
giscanner/dumper.py
giscanner/gdumpparser.py
giscanner/girparser.py
giscanner/girwriter.py
giscanner/maintransformer.py
giscanner/scannermain.py [changed mode: 0644->0755]
tests/scanner/Foo-1.0-expected.gir

index cb6e74197bc0f91435418cd691c71fdbccbdcb6c..e607f3237389213e66b139a164897bb0c5e0455b 100644 (file)
@@ -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);
index 062f3abf224594dc1f34d59fc7f0a98d66a6efa1..338a46ee04a81274518e77903074cf2f4c18a85b 100644 (file)
@@ -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
index 6b24fe7efbaa32339c1be3b2e3d64fd6ca587672..fc0f3c84263b45d777b3cd903820f3edceccca56 100644 (file)
@@ -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);
 
index 1c51bfd4b0cc6f8181613fda71474c6e02fe3bf6..166ca30a31818bf59bac73737bfa36a76d08cefd 100644 (file)
@@ -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;
index fb2616b1e9b312c255c944f83eb6faab73d6a799..6e03821ba189bb8879d507eca2440bcae85d6e0f 100644 (file)
@@ -285,6 +285,7 @@ struct _GIrNodeEnum
 
   gchar *gtype_name;
   gchar *gtype_init;
+  gchar *error_domain;
 
   GList *values;
 };
index 4e5527259ef3fecbdec2d65c3deb67513f21173d..c9b7d62926f3f642ae8fdbd0de8713e5270f2d85 100644 (file)
@@ -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
index 2cdc9a11f3cbad53516f44e46d0b168c8c968b07..d9f916c5533a36a7fa526e317b37a6e22cf80dc3 100644 (file)
@@ -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\"");
index 2bda8d9d06abe2e9ecd411e8c30e82290cf0f9c9..49fbe4e3ef776ebf3994e640b5fe341ead092538 100644 (file)
@@ -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;
index d4780f9edd6aa0ddfdd61433bf199d271000cdc8..bd56aef3c4ab44212d996583e9a294cf8a6f7269 100644 (file)
@@ -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):
index 615b3fc575c522c2e150b3a26df917ea5857eb40..61cba257d08eb5b31882af9ab10ac5d8e103fd5a 100644 (file)
@@ -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()
index 87621bc905123c4768bbbc793e0dc3410f3e7b43..35fea72bb1feb43e06dcf15c89e0f7a600e83d88 100644 (file)
@@ -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)
index bcf68bfd5bf66a073c8915536dd353c549482fc2..45a93ed6a96ddf6587c713d97c8c8bff166a766c 100644 (file)
@@ -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)
index 4a6c47e05a1154ff340ec7a65e6b37bdcc0ab998..1da2417d3cdcf63357dce32459b03de0cd5585e6 100644 (file)
@@ -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)
index 34d17b440e41e53e5cf6ba6c4a75db06643940b2..d2d1f2d8a8c35a47830eaf5e8c44719f1855c4b9 100644 (file)
@@ -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, ))
old mode 100644 (file)
new mode 100755 (executable)
index 52ee4cc..3c1386a
@@ -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)
index 8b9dc387074653c091deb4058b24e54b8e444059..cc4c8d7a2a12b59daf301cd0cb930ec94437f5f2 100644 (file)
@@ -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"