summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2011-05-19 16:21:13 -0400
committerDan Winship <danw@gnome.org>2011-08-12 11:10:43 -0400
commit5fd2fa5bf5a07a66d2150740d534a398598e8dd1 (patch)
treed40cb5a96e53cd518c8a00e14855bf6196fcf03b
parent4dabe20ed5753bccd2abf8ad02e95ce6ab53036c (diff)
downloadgobject-introspection-5fd2fa5bf5a07a66d2150740d534a398598e8dd1.tar.gz
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
-rw-r--r--girepository/gdump.c83
-rw-r--r--girepository/gienuminfo.c17
-rw-r--r--girepository/gienuminfo.h1
-rw-r--r--girepository/girnode.c7
-rw-r--r--girepository/girnode.h1
-rw-r--r--girepository/girparser.c4
-rw-r--r--girepository/girwriter.c4
-rw-r--r--girepository/gitypelib-internal.h4
-rw-r--r--giscanner/ast.py11
-rw-r--r--giscanner/dumper.py26
-rw-r--r--giscanner/gdumpparser.py41
-rw-r--r--giscanner/girparser.py4
-rw-r--r--giscanner/girwriter.py4
-rw-r--r--giscanner/maintransformer.py6
-rwxr-xr-x[-rw-r--r--]giscanner/scannermain.py3
-rw-r--r--tests/scanner/Foo-1.0-expected.gir2
16 files changed, 177 insertions, 41 deletions
diff --git a/girepository/gdump.c b/girepository/gdump.c
index cb6e7419..e607f323 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 062f3abf..338a46ee 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 6b24fe7e..fc0f3c84 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 1c51bfd4..166ca30a 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 fb2616b1..6e03821b 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 4e552725..c9b7d629 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 2cdc9a11..d9f916c5 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 2bda8d9d..49fbe4e3 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 d4780f9e..bd56aef3 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 615b3fc5..61cba257 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 87621bc9..35fea72b 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 bcf68bfd..45a93ed6 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 4a6c47e0..1da2417d 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 34d17b44..d2d1f2d8 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
index 52ee4cc0..3c1386a9 100644..100755
--- 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 8b9dc387..cc4c8d7a 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"