From: Dan Winship Date: Thu, 19 May 2011 20:21:13 +0000 (-0400) Subject: Switch to storing string form of error quarks X-Git-Tag: GOBJECT_INTROSPECTION_1_29_17~78 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5fd2fa5bf5a07a66d2150740d534a398598e8dd1;p=platform%2Fupstream%2Fgobject-introspection.git 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 --- 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, " \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 old mode 100644 new mode 100755 index 52ee4cc0..3c1386a9 --- 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">