Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : * GObject introspection: Dump introspection data
3 : : *
4 : : * Copyright (C) 2008 Colin Walters <walters@verbum.org>
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Lesser General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Lesser General Public
19 : : * License along with this library; if not, write to the
20 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 : : * Boston, MA 02111-1307, USA.
22 : : */
23 : :
24 : : /* This file is both compiled into libgirepository.so, and installed
25 : : * on the filesystem. But for the dumper, we want to avoid linking
26 : : * to libgirepository; see
27 : : * https://bugzilla.gnome.org/show_bug.cgi?id=630342
28 : : */
29 : : #ifdef GI_COMPILATION
30 : : #include "config.h"
31 : : #include "girepository.h"
32 : : #endif
33 : :
34 : : #include <glib.h>
35 : : #include <glib-object.h>
36 : : #include <glib/gstdio.h>
37 : : #include <gmodule.h>
38 : :
39 : : #include <stdlib.h>
40 : : #include <stdint.h>
41 : : #include <stdio.h>
42 : : #include <string.h>
43 : :
44 : : /* Analogue of g_output_stream_write_all(). */
45 : : static gboolean
46 : 19 : write_all (FILE *out,
47 : : const void *buffer,
48 : : size_t count,
49 : : size_t *bytes_written,
50 : : GError **error)
51 : : {
52 : : size_t ret;
53 : :
54 : 19 : ret = fwrite (buffer, 1, count, out);
55 : :
56 : 19 : if (bytes_written != NULL)
57 : 19 : *bytes_written = ret;
58 : :
59 : 19 : if (ret < count)
60 : : {
61 : 0 : g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
62 : : "Failed to write to file");
63 : 0 : return FALSE;
64 : : }
65 : :
66 : 19 : return TRUE;
67 : : }
68 : :
69 : : /* Analogue of g_data_input_stream_read_line(). */
70 : : static char *
71 : 6 : read_line (FILE *input,
72 : : size_t *len_out)
73 : : {
74 : 6 : GByteArray *buffer = g_byte_array_new ();
75 : 6 : const uint8_t nul = '\0';
76 : :
77 : : while (TRUE)
78 : 125 : {
79 : : size_t ret;
80 : : uint8_t byte;
81 : :
82 : 131 : ret = fread (&byte, 1, 1, input);
83 : 131 : if (ret == 0)
84 : 4 : break;
85 : :
86 : 127 : if (byte == '\n')
87 : 2 : break;
88 : :
89 : 125 : g_byte_array_append (buffer, &byte, 1);
90 : : }
91 : :
92 : 6 : g_byte_array_append (buffer, &nul, 1);
93 : :
94 : 6 : if (len_out != NULL)
95 : 6 : *len_out = buffer->len - 1; /* don’t include terminating nul */
96 : :
97 : 6 : return (char *) g_byte_array_free (buffer, FALSE);
98 : : }
99 : :
100 : : static void
101 : : escaped_printf (FILE *out, const char *fmt, ...) G_GNUC_PRINTF (2, 3);
102 : :
103 : : static void
104 : 4 : escaped_printf (FILE *out, const char *fmt, ...)
105 : : {
106 : : char *str;
107 : : va_list args;
108 : : size_t written;
109 : 4 : GError *error = NULL;
110 : :
111 : 4 : va_start (args, fmt);
112 : :
113 : 4 : str = g_markup_vprintf_escaped (fmt, args);
114 : 4 : if (!write_all (out, str, strlen (str), &written, &error))
115 : : {
116 : 0 : g_critical ("failed to write to iochannel: %s", error->message);
117 : 0 : g_clear_error (&error);
118 : : }
119 : 4 : g_free (str);
120 : :
121 : 4 : va_end (args);
122 : 4 : }
123 : :
124 : : static void
125 : 15 : goutput_write (FILE *out, const char *str)
126 : : {
127 : : size_t written;
128 : 15 : GError *error = NULL;
129 : 15 : if (!write_all (out, str, strlen (str), &written, &error))
130 : : {
131 : 0 : g_critical ("failed to write to iochannel: %s", error->message);
132 : 0 : g_clear_error (&error);
133 : : }
134 : 15 : }
135 : :
136 : : typedef GType (*GetTypeFunc)(void);
137 : : typedef GQuark (*ErrorQuarkFunc)(void);
138 : :
139 : : static GType
140 : 3 : invoke_get_type (GModule *self, const char *symbol, GError **error)
141 : : {
142 : : GetTypeFunc sym;
143 : : GType ret;
144 : :
145 : 3 : if (!g_module_symbol (self, symbol, (void**)&sym))
146 : : {
147 : 1 : g_set_error (error,
148 : : G_FILE_ERROR,
149 : : G_FILE_ERROR_FAILED,
150 : : "Failed to find symbol '%s'", symbol);
151 : 1 : return G_TYPE_INVALID;
152 : : }
153 : :
154 : 2 : ret = sym ();
155 : 2 : if (ret == G_TYPE_INVALID)
156 : : {
157 : 0 : g_set_error (error,
158 : : G_FILE_ERROR,
159 : : G_FILE_ERROR_FAILED,
160 : : "Function '%s' returned G_TYPE_INVALID", symbol);
161 : : }
162 : 2 : return ret;
163 : : }
164 : :
165 : : static GQuark
166 : 1 : invoke_error_quark (GModule *self, const char *symbol, GError **error)
167 : : {
168 : : ErrorQuarkFunc sym;
169 : :
170 : 1 : if (!g_module_symbol (self, symbol, (void**)&sym))
171 : : {
172 : 1 : g_set_error (error,
173 : : G_FILE_ERROR,
174 : : G_FILE_ERROR_FAILED,
175 : : "Failed to find symbol '%s'", symbol);
176 : 1 : return G_TYPE_INVALID;
177 : : }
178 : :
179 : 0 : return sym ();
180 : : }
181 : :
182 : : static char *
183 : 0 : value_transform_to_string (const GValue *value)
184 : : {
185 : 0 : GValue tmp = G_VALUE_INIT;
186 : 0 : char *s = NULL;
187 : :
188 : 0 : g_value_init (&tmp, G_TYPE_STRING);
189 : :
190 : 0 : if (g_value_transform (value, &tmp))
191 : : {
192 : 0 : const char *str = g_value_get_string (&tmp);
193 : :
194 : 0 : if (str != NULL)
195 : 0 : s = g_strescape (str, NULL);
196 : : }
197 : :
198 : 0 : g_value_unset (&tmp);
199 : :
200 : 0 : return s;
201 : : }
202 : :
203 : : /* A simpler version of g_strdup_value_contents(), but with stable
204 : : * output and less complex semantics
205 : : */
206 : : static char *
207 : 0 : value_to_string (const GValue *value)
208 : : {
209 : 0 : if (value == NULL)
210 : 0 : return NULL;
211 : :
212 : 0 : if (G_VALUE_HOLDS_STRING (value))
213 : : {
214 : 0 : const char *s = g_value_get_string (value);
215 : :
216 : 0 : if (s == NULL)
217 : 0 : return g_strdup ("NULL");
218 : :
219 : 0 : return g_strescape (s, NULL);
220 : : }
221 : : else
222 : : {
223 : 0 : GType value_type = G_VALUE_TYPE (value);
224 : :
225 : 0 : switch (G_TYPE_FUNDAMENTAL (value_type))
226 : : {
227 : 0 : case G_TYPE_BOXED:
228 : 0 : if (g_value_get_boxed (value) == NULL)
229 : 0 : return NULL;
230 : : else
231 : 0 : return value_transform_to_string (value);
232 : : break;
233 : :
234 : 0 : case G_TYPE_OBJECT:
235 : 0 : if (g_value_get_object (value) == NULL)
236 : 0 : return NULL;
237 : : else
238 : 0 : return value_transform_to_string (value);
239 : : break;
240 : :
241 : 0 : case G_TYPE_POINTER:
242 : 0 : return NULL;
243 : :
244 : 0 : default:
245 : 0 : return value_transform_to_string (value);
246 : : }
247 : : }
248 : :
249 : : return NULL;
250 : : }
251 : :
252 : : static void
253 : 2 : dump_properties (GType type, FILE *out)
254 : : {
255 : : unsigned int i;
256 : 2 : unsigned int n_properties = 0;
257 : : GParamSpec **props;
258 : :
259 : 2 : if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT)
260 : : {
261 : : GObjectClass *klass;
262 : 1 : klass = g_type_class_ref (type);
263 : 1 : props = g_object_class_list_properties (klass, &n_properties);
264 : : }
265 : : else
266 : : {
267 : : void *klass;
268 : 1 : klass = g_type_default_interface_ref (type);
269 : 1 : props = g_object_interface_list_properties (klass, &n_properties);
270 : : }
271 : :
272 : 2 : for (i = 0; i < n_properties; i++)
273 : : {
274 : : GParamSpec *prop;
275 : :
276 : 0 : prop = props[i];
277 : 0 : if (prop->owner_type != type)
278 : 0 : continue;
279 : :
280 : 0 : const GValue *v = g_param_spec_get_default_value (prop);
281 : 0 : char *default_value = value_to_string (v);
282 : :
283 : 0 : if (v != NULL && default_value != NULL)
284 : : {
285 : 0 : escaped_printf (out, " <property name=\"%s\" type=\"%s\" flags=\"%d\" default-value=\"%s\"/>\n",
286 : : prop->name,
287 : : g_type_name (prop->value_type),
288 : 0 : prop->flags,
289 : : default_value);
290 : : }
291 : : else
292 : : {
293 : 0 : escaped_printf (out, " <property name=\"%s\" type=\"%s\" flags=\"%d\"/>\n",
294 : : prop->name,
295 : : g_type_name (prop->value_type),
296 : 0 : prop->flags);
297 : : }
298 : :
299 : 0 : g_free (default_value);
300 : : }
301 : :
302 : 2 : g_free (props);
303 : 2 : }
304 : :
305 : : static void
306 : 2 : dump_signals (GType type, FILE *out)
307 : : {
308 : : unsigned int i;
309 : : unsigned int n_sigs;
310 : : unsigned int *sig_ids;
311 : :
312 : 2 : sig_ids = g_signal_list_ids (type, &n_sigs);
313 : 2 : for (i = 0; i < n_sigs; i++)
314 : : {
315 : : unsigned int sigid;
316 : : GSignalQuery query;
317 : : unsigned int j;
318 : :
319 : 0 : sigid = sig_ids[i];
320 : 0 : g_signal_query (sigid, &query);
321 : :
322 : 0 : escaped_printf (out, " <signal name=\"%s\" return=\"%s\"",
323 : : query.signal_name, g_type_name (query.return_type));
324 : :
325 : 0 : if (query.signal_flags & G_SIGNAL_RUN_FIRST)
326 : 0 : escaped_printf (out, " when=\"first\"");
327 : 0 : else if (query.signal_flags & G_SIGNAL_RUN_LAST)
328 : 0 : escaped_printf (out, " when=\"last\"");
329 : 0 : else if (query.signal_flags & G_SIGNAL_RUN_CLEANUP)
330 : 0 : escaped_printf (out, " when=\"cleanup\"");
331 : 0 : else if (query.signal_flags & G_SIGNAL_MUST_COLLECT)
332 : 0 : escaped_printf (out, " when=\"must-collect\"");
333 : 0 : if (query.signal_flags & G_SIGNAL_NO_RECURSE)
334 : 0 : escaped_printf (out, " no-recurse=\"1\"");
335 : :
336 : 0 : if (query.signal_flags & G_SIGNAL_DETAILED)
337 : 0 : escaped_printf (out, " detailed=\"1\"");
338 : :
339 : 0 : if (query.signal_flags & G_SIGNAL_ACTION)
340 : 0 : escaped_printf (out, " action=\"1\"");
341 : :
342 : 0 : if (query.signal_flags & G_SIGNAL_NO_HOOKS)
343 : 0 : escaped_printf (out, " no-hooks=\"1\"");
344 : :
345 : 0 : goutput_write (out, ">\n");
346 : :
347 : 0 : for (j = 0; j < query.n_params; j++)
348 : : {
349 : 0 : escaped_printf (out, " <param type=\"%s\"/>\n",
350 : 0 : g_type_name (query.param_types[j]));
351 : : }
352 : 0 : goutput_write (out, " </signal>\n");
353 : : }
354 : 2 : g_free (sig_ids);
355 : 2 : }
356 : :
357 : : static void
358 : 1 : dump_object_type (GType type, const char *symbol, FILE *out)
359 : : {
360 : : unsigned int n_interfaces;
361 : : unsigned int i;
362 : : GType *interfaces;
363 : :
364 : 1 : escaped_printf (out, " <class name=\"%s\" get-type=\"%s\"",
365 : : g_type_name (type), symbol);
366 : 1 : if (type != G_TYPE_OBJECT)
367 : : {
368 : : GString *parent_str;
369 : : GType parent;
370 : 1 : gboolean first = TRUE;
371 : :
372 : 1 : parent = g_type_parent (type);
373 : 1 : parent_str = g_string_new ("");
374 : 2 : while (parent != G_TYPE_INVALID)
375 : : {
376 : 1 : if (first)
377 : 1 : first = FALSE;
378 : : else
379 : : g_string_append_c (parent_str, ',');
380 : 1 : g_string_append (parent_str, g_type_name (parent));
381 : 1 : parent = g_type_parent (parent);
382 : : }
383 : :
384 : 1 : escaped_printf (out, " parents=\"%s\"", parent_str->str);
385 : :
386 : 1 : g_string_free (parent_str, TRUE);
387 : : }
388 : :
389 : 1 : if (G_TYPE_IS_ABSTRACT (type))
390 : 0 : escaped_printf (out, " abstract=\"1\"");
391 : :
392 : 1 : if (G_TYPE_IS_FINAL (type))
393 : 1 : escaped_printf (out, " final=\"1\"");
394 : :
395 : 1 : goutput_write (out, ">\n");
396 : :
397 : 1 : interfaces = g_type_interfaces (type, &n_interfaces);
398 : 1 : for (i = 0; i < n_interfaces; i++)
399 : : {
400 : 0 : GType itype = interfaces[i];
401 : 0 : escaped_printf (out, " <implements name=\"%s\"/>\n",
402 : : g_type_name (itype));
403 : : }
404 : 1 : g_free (interfaces);
405 : :
406 : 1 : dump_properties (type, out);
407 : 1 : dump_signals (type, out);
408 : 1 : goutput_write (out, " </class>\n");
409 : 1 : }
410 : :
411 : : static void
412 : 1 : dump_interface_type (GType type, const char *symbol, FILE *out)
413 : : {
414 : : unsigned int n_interfaces;
415 : : unsigned int i;
416 : : GType *interfaces;
417 : :
418 : 1 : escaped_printf (out, " <interface name=\"%s\" get-type=\"%s\">\n",
419 : : g_type_name (type), symbol);
420 : :
421 : 1 : interfaces = g_type_interface_prerequisites (type, &n_interfaces);
422 : 2 : for (i = 0; i < n_interfaces; i++)
423 : : {
424 : 1 : GType itype = interfaces[i];
425 : 1 : if (itype == G_TYPE_OBJECT)
426 : : {
427 : : /* Treat this as implicit for now; in theory GInterfaces are
428 : : * supported on things like GstMiniObject, but right now
429 : : * the introspection system only supports GObject.
430 : : * http://bugzilla.gnome.org/show_bug.cgi?id=559706
431 : : */
432 : 1 : continue;
433 : : }
434 : 0 : escaped_printf (out, " <prerequisite name=\"%s\"/>\n",
435 : : g_type_name (itype));
436 : : }
437 : 1 : g_free (interfaces);
438 : :
439 : 1 : dump_properties (type, out);
440 : 1 : dump_signals (type, out);
441 : 1 : goutput_write (out, " </interface>\n");
442 : 1 : }
443 : :
444 : : static void
445 : 0 : dump_boxed_type (GType type, const char *symbol, FILE *out)
446 : : {
447 : 0 : escaped_printf (out, " <boxed name=\"%s\" get-type=\"%s\"/>\n",
448 : : g_type_name (type), symbol);
449 : 0 : }
450 : :
451 : : static void
452 : 0 : dump_pointer_type (GType type, const char *symbol, FILE *out)
453 : : {
454 : 0 : escaped_printf (out, " <pointer name=\"%s\" get-type=\"%s\"/>\n",
455 : : g_type_name (type), symbol);
456 : 0 : }
457 : :
458 : : static void
459 : 0 : dump_flags_type (GType type, const char *symbol, FILE *out)
460 : : {
461 : : unsigned int i;
462 : : GFlagsClass *klass;
463 : :
464 : 0 : klass = g_type_class_ref (type);
465 : 0 : escaped_printf (out, " <flags name=\"%s\" get-type=\"%s\">\n",
466 : : g_type_name (type), symbol);
467 : :
468 : 0 : for (i = 0; i < klass->n_values; i++)
469 : : {
470 : 0 : GFlagsValue *value = &(klass->values[i]);
471 : :
472 : 0 : escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%u\"/>\n",
473 : : value->value_name, value->value_nick, value->value);
474 : : }
475 : 0 : goutput_write (out, " </flags>\n");
476 : 0 : }
477 : :
478 : : static void
479 : 0 : dump_enum_type (GType type, const char *symbol, FILE *out)
480 : : {
481 : : unsigned int i;
482 : : GEnumClass *klass;
483 : :
484 : 0 : klass = g_type_class_ref (type);
485 : 0 : escaped_printf (out, " <enum name=\"%s\" get-type=\"%s\">\n",
486 : : g_type_name (type), symbol);
487 : :
488 : 0 : for (i = 0; i < klass->n_values; i++)
489 : : {
490 : 0 : GEnumValue *value = &(klass->values[i]);
491 : :
492 : 0 : escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%d\"/>\n",
493 : : value->value_name, value->value_nick, value->value);
494 : : }
495 : 0 : goutput_write (out, " </enum>");
496 : 0 : }
497 : :
498 : : static void
499 : 0 : dump_fundamental_type (GType type, const char *symbol, FILE *out)
500 : : {
501 : : unsigned int n_interfaces;
502 : : unsigned int i;
503 : : GType *interfaces;
504 : : GString *parent_str;
505 : : GType parent;
506 : 0 : gboolean first = TRUE;
507 : :
508 : :
509 : 0 : escaped_printf (out, " <fundamental name=\"%s\" get-type=\"%s\"",
510 : : g_type_name (type), symbol);
511 : :
512 : 0 : if (G_TYPE_IS_ABSTRACT (type))
513 : 0 : escaped_printf (out, " abstract=\"1\"");
514 : :
515 : 0 : if (G_TYPE_IS_FINAL (type))
516 : 0 : escaped_printf (out, " final=\"1\"");
517 : :
518 : 0 : if (G_TYPE_IS_INSTANTIATABLE (type))
519 : 0 : escaped_printf (out, " instantiatable=\"1\"");
520 : :
521 : 0 : parent = g_type_parent (type);
522 : 0 : parent_str = g_string_new ("");
523 : 0 : while (parent != G_TYPE_INVALID)
524 : : {
525 : 0 : if (first)
526 : 0 : first = FALSE;
527 : : else
528 : : g_string_append_c (parent_str, ',');
529 : 0 : if (!g_type_name (parent))
530 : 0 : break;
531 : 0 : g_string_append (parent_str, g_type_name (parent));
532 : 0 : parent = g_type_parent (parent);
533 : : }
534 : :
535 : 0 : if (parent_str->len > 0)
536 : 0 : escaped_printf (out, " parents=\"%s\"", parent_str->str);
537 : 0 : g_string_free (parent_str, TRUE);
538 : :
539 : 0 : goutput_write (out, ">\n");
540 : :
541 : 0 : interfaces = g_type_interfaces (type, &n_interfaces);
542 : 0 : for (i = 0; i < n_interfaces; i++)
543 : : {
544 : 0 : GType itype = interfaces[i];
545 : 0 : escaped_printf (out, " <implements name=\"%s\"/>\n",
546 : : g_type_name (itype));
547 : : }
548 : 0 : g_free (interfaces);
549 : 0 : goutput_write (out, " </fundamental>\n");
550 : 0 : }
551 : :
552 : : static void
553 : 2 : dump_type (GType type, const char *symbol, FILE *out)
554 : : {
555 : 2 : switch (g_type_fundamental (type))
556 : : {
557 : 1 : case G_TYPE_OBJECT:
558 : 1 : dump_object_type (type, symbol, out);
559 : 1 : break;
560 : 1 : case G_TYPE_INTERFACE:
561 : 1 : dump_interface_type (type, symbol, out);
562 : 1 : break;
563 : 0 : case G_TYPE_BOXED:
564 : 0 : dump_boxed_type (type, symbol, out);
565 : 0 : break;
566 : 0 : case G_TYPE_FLAGS:
567 : 0 : dump_flags_type (type, symbol, out);
568 : 0 : break;
569 : 0 : case G_TYPE_ENUM:
570 : 0 : dump_enum_type (type, symbol, out);
571 : 0 : break;
572 : 0 : case G_TYPE_POINTER:
573 : 0 : dump_pointer_type (type, symbol, out);
574 : 0 : break;
575 : 0 : default:
576 : 0 : dump_fundamental_type (type, symbol, out);
577 : 0 : break;
578 : : }
579 : 2 : }
580 : :
581 : : static void
582 : 0 : dump_error_quark (GQuark quark, const char *symbol, FILE *out)
583 : : {
584 : 0 : escaped_printf (out, " <error-quark function=\"%s\" domain=\"%s\"/>\n",
585 : : symbol, g_quark_to_string (quark));
586 : 0 : }
587 : :
588 : : /**
589 : : * gi_repository_dump:
590 : : * @input_filename: (type filename): Input filename (for example `input.txt`)
591 : : * @output_filename: (type filename): Output filename (for example `output.xml`)
592 : : * @error: a %GError
593 : : *
594 : : * Dump the introspection data from the types specified in @input_filename to
595 : : * @output_filename.
596 : : *
597 : : * The input file should be a
598 : : * UTF-8 Unix-line-ending text file, with each line containing either
599 : : * `get-type:` followed by the name of a [type@GObject.Type] `_get_type`
600 : : * function, or `error-quark:` followed by the name of an error quark function.
601 : : * No extra whitespace is allowed.
602 : : *
603 : : * This function will overwrite the contents of the output file.
604 : : *
605 : : * Returns: true on success, false on error
606 : : * Since: 2.80
607 : : */
608 : : #ifndef GI_COMPILATION
609 : : static gboolean
610 : : dump_irepository (const char *input_filename,
611 : : const char *output_filename,
612 : : GError **error) G_GNUC_UNUSED;
613 : : static gboolean
614 : 0 : dump_irepository (const char *input_filename,
615 : : const char *output_filename,
616 : : GError **error)
617 : : #else
618 : : gboolean
619 : 4 : gi_repository_dump (const char *input_filename,
620 : : const char *output_filename,
621 : : GError **error)
622 : : #endif
623 : : {
624 : : GHashTable *output_types;
625 : : FILE *input;
626 : : FILE *output;
627 : : GModule *self;
628 : 4 : gboolean caught_error = FALSE;
629 : :
630 : 4 : self = g_module_open (NULL, 0);
631 : 4 : if (!self)
632 : : {
633 : 0 : g_set_error (error,
634 : : G_FILE_ERROR,
635 : : G_FILE_ERROR_FAILED,
636 : : "failed to open self: %s",
637 : : g_module_error ());
638 : 0 : return FALSE;
639 : : }
640 : :
641 : 4 : input = g_fopen (input_filename, "rbe");
642 : 4 : if (input == NULL)
643 : : {
644 : 0 : int saved_errno = errno;
645 : 0 : g_set_error (error, G_FILE_ERROR, (int) g_file_error_from_errno (saved_errno),
646 : : "Failed to open ‘%s’: %s", input_filename, g_strerror (saved_errno));
647 : :
648 : 0 : g_module_close (self);
649 : :
650 : 0 : return FALSE;
651 : : }
652 : :
653 : 4 : output = g_fopen (output_filename, "wbe");
654 : 4 : if (output == NULL)
655 : : {
656 : 0 : int saved_errno = errno;
657 : 0 : g_set_error (error, G_FILE_ERROR, (int) g_file_error_from_errno (saved_errno),
658 : : "Failed to open ‘%s’: %s", output_filename, g_strerror (saved_errno));
659 : :
660 : 0 : fclose (input);
661 : 0 : g_module_close (self);
662 : :
663 : 0 : return FALSE;
664 : : }
665 : :
666 : 4 : goutput_write (output, "<?xml version=\"1.0\"?>\n");
667 : 4 : goutput_write (output, "<dump>\n");
668 : :
669 : 4 : output_types = g_hash_table_new (NULL, NULL);
670 : :
671 : : while (TRUE)
672 : 2 : {
673 : : size_t len;
674 : 6 : char *line = read_line (input, &len);
675 : : const char *function;
676 : :
677 : 6 : if (line == NULL || *line == '\0')
678 : : {
679 : 2 : g_free (line);
680 : 2 : break;
681 : : }
682 : :
683 : 4 : g_strchomp (line);
684 : :
685 : 4 : if (strncmp (line, "get-type:", strlen ("get-type:")) == 0)
686 : : {
687 : : GType type;
688 : :
689 : 3 : function = line + strlen ("get-type:");
690 : :
691 : 3 : type = invoke_get_type (self, function, error);
692 : :
693 : 3 : if (type == G_TYPE_INVALID)
694 : : {
695 : 1 : g_printerr ("Invalid GType function: '%s'\n", function);
696 : 1 : caught_error = TRUE;
697 : 1 : g_free (line);
698 : 1 : break;
699 : : }
700 : :
701 : 2 : if (g_hash_table_lookup (output_types, (gpointer) type))
702 : 0 : goto next;
703 : 2 : g_hash_table_insert (output_types, (gpointer) type, (gpointer) type);
704 : :
705 : 2 : dump_type (type, function, output);
706 : : }
707 : 1 : else if (strncmp (line, "error-quark:", strlen ("error-quark:")) == 0)
708 : : {
709 : : GQuark quark;
710 : 1 : function = line + strlen ("error-quark:");
711 : 1 : quark = invoke_error_quark (self, function, error);
712 : :
713 : 1 : if (quark == 0)
714 : : {
715 : 1 : g_printerr ("Invalid error quark function: '%s'\n", function);
716 : 1 : caught_error = TRUE;
717 : 1 : g_free (line);
718 : 1 : break;
719 : : }
720 : :
721 : 0 : dump_error_quark (quark, function, output);
722 : : }
723 : :
724 : :
725 : 0 : next:
726 : 2 : g_free (line);
727 : : }
728 : :
729 : 4 : g_hash_table_destroy (output_types);
730 : :
731 : 4 : goutput_write (output, "</dump>\n");
732 : :
733 : : {
734 : : /* Avoid overwriting an earlier set error */
735 : 4 : if (fclose (input) != 0 && !caught_error)
736 : : {
737 : 0 : int saved_errno = errno;
738 : :
739 : 0 : g_set_error (error, G_FILE_ERROR, (int) g_file_error_from_errno (saved_errno),
740 : : "Error closing input file ‘%s’: %s", input_filename,
741 : : g_strerror (saved_errno));
742 : 0 : caught_error = TRUE;
743 : : }
744 : :
745 : 4 : if (fclose (output) != 0 && !caught_error)
746 : : {
747 : 0 : int saved_errno = errno;
748 : :
749 : 0 : g_set_error (error, G_FILE_ERROR, (int) g_file_error_from_errno (saved_errno),
750 : : "Error closing output file ‘%s’: %s", output_filename,
751 : : g_strerror (saved_errno));
752 : 0 : caught_error = TRUE;
753 : : }
754 : : }
755 : :
756 : 4 : return !caught_error;
757 : : }
|