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