Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : * GObject introspection: A parser for the XML GIR format
3 : : *
4 : : * Copyright (C) 2005 Matthias Clasen
5 : : * Copyright (C) 2008 Philip Van Hoof
6 : : *
7 : : * SPDX-License-Identifier: LGPL-2.1-or-later
8 : : *
9 : : * This library is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU Lesser General Public
11 : : * License as published by the Free Software Foundation; either
12 : : * version 2 of the License, or (at your option) any later version.
13 : : *
14 : : * This library is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : * Lesser General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU Lesser General Public
20 : : * License along with this library; if not, write to the
21 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 : : * Boston, MA 02111-1307, USA.
23 : : */
24 : :
25 : : #include "config.h"
26 : :
27 : : #include "girparser-private.h"
28 : :
29 : : #include "girnode-private.h"
30 : : #include "gitypelib-internal.h"
31 : :
32 : : #include <stdlib.h>
33 : : #include <string.h>
34 : : #include <stdio.h>
35 : : #include <time.h> /* For time_t */
36 : : #include <sys/types.h> /* For off_t on both Unix and Windows */
37 : :
38 : : #ifdef G_OS_UNIX
39 : : #include <sys/socket.h> /* For socklen_t */
40 : : #endif
41 : :
42 : : /* This is a "major" version in the sense that it's only bumped
43 : : * for incompatible changes.
44 : : */
45 : : #define SUPPORTED_GIR_VERSION "1.2"
46 : :
47 : : #ifdef G_OS_WIN32
48 : :
49 : : #include <windows.h>
50 : :
51 : : #ifdef GIR_DIR
52 : : #undef GIR_DIR
53 : : #endif
54 : :
55 : : /* GIR_DIR is used only in code called just once,
56 : : * so no problem leaking this
57 : : */
58 : : #define GIR_DIR \
59 : : g_build_filename (g_win32_get_package_installation_directory_of_module(NULL), \
60 : : "share", \
61 : : GIR_SUFFIX, \
62 : : NULL)
63 : : #endif
64 : :
65 : : struct _GIIrParser
66 : : {
67 : : char **includes;
68 : : char **gi_gir_path;
69 : : GList *parsed_modules; /* All previously parsed modules */
70 : : GLogLevelFlags logged_levels;
71 : : };
72 : :
73 : : typedef enum
74 : : {
75 : : STATE_NONE = 0,
76 : : STATE_START,
77 : : STATE_END,
78 : : STATE_REPOSITORY,
79 : : STATE_INCLUDE,
80 : : STATE_C_INCLUDE, /* 5 */
81 : : STATE_PACKAGE,
82 : : STATE_NAMESPACE,
83 : : STATE_ENUM,
84 : : STATE_BITFIELD,
85 : : STATE_FUNCTION, /* 10 */
86 : : STATE_FUNCTION_RETURN,
87 : : STATE_FUNCTION_PARAMETERS,
88 : : STATE_FUNCTION_PARAMETER,
89 : : STATE_CLASS,
90 : : STATE_CLASS_FIELD, /* 15 */
91 : : STATE_CLASS_PROPERTY,
92 : : STATE_INTERFACE,
93 : : STATE_INTERFACE_PROPERTY,
94 : : STATE_INTERFACE_FIELD,
95 : : STATE_IMPLEMENTS, /* 20 */
96 : : STATE_PREREQUISITE,
97 : : STATE_BOXED,
98 : : STATE_BOXED_FIELD,
99 : : STATE_STRUCT,
100 : : STATE_STRUCT_FIELD, /* 25 */
101 : : STATE_UNION,
102 : : STATE_UNION_FIELD,
103 : : STATE_NAMESPACE_CONSTANT,
104 : : STATE_CLASS_CONSTANT,
105 : : STATE_INTERFACE_CONSTANT, /* 30 */
106 : : STATE_ALIAS,
107 : : STATE_TYPE,
108 : : STATE_ATTRIBUTE,
109 : : STATE_PASSTHROUGH
110 : : } ParseState;
111 : :
112 : : typedef struct _ParseContext ParseContext;
113 : : struct _ParseContext
114 : : {
115 : : GIIrParser *parser;
116 : :
117 : : ParseState state;
118 : : int unknown_depth;
119 : : ParseState prev_state;
120 : :
121 : : GList *modules;
122 : : GList *include_modules;
123 : : GList *dependencies;
124 : : GHashTable *aliases;
125 : : GHashTable *disguised_structures;
126 : : GHashTable *pointer_structures;
127 : :
128 : : const char *file_path;
129 : : const char *namespace;
130 : : const char *c_prefix;
131 : : GIIrModule *current_module;
132 : : GSList *node_stack;
133 : : char *current_alias;
134 : : GIIrNode *current_typed;
135 : : GList *type_stack;
136 : : GList *type_parameters;
137 : : int type_depth;
138 : : ParseState in_embedded_state;
139 : : };
140 : : #define CURRENT_NODE(ctx) ((GIIrNode *)((ctx)->node_stack->data))
141 : :
142 : : static void start_element_handler (GMarkupParseContext *context,
143 : : const char *element_name,
144 : : const char **attribute_names,
145 : : const char **attribute_values,
146 : : void *user_data,
147 : : GError **error);
148 : : static void end_element_handler (GMarkupParseContext *context,
149 : : const char *element_name,
150 : : void *user_data,
151 : : GError **error);
152 : : static void text_handler (GMarkupParseContext *context,
153 : : const char *text,
154 : : gsize text_len,
155 : : void *user_data,
156 : : GError **error);
157 : : static void cleanup (GMarkupParseContext *context,
158 : : GError *error,
159 : : void *user_data);
160 : : static void state_switch (ParseContext *ctx, ParseState newstate);
161 : :
162 : :
163 : : static GMarkupParser markup_parser =
164 : : {
165 : : start_element_handler,
166 : : end_element_handler,
167 : : text_handler,
168 : : NULL,
169 : : cleanup
170 : : };
171 : :
172 : : static gboolean
173 : : start_alias (GMarkupParseContext *context,
174 : : const char *element_name,
175 : : const char **attribute_names,
176 : : const char **attribute_values,
177 : : ParseContext *ctx,
178 : : GError **error);
179 : : static gboolean
180 : : start_type (GMarkupParseContext *context,
181 : : const char *element_name,
182 : : const char **attribute_names,
183 : : const char **attribute_values,
184 : : ParseContext *ctx,
185 : : GError **error);
186 : :
187 : : static const char *find_attribute (const char *name,
188 : : const char **attribute_names,
189 : : const char **attribute_values);
190 : :
191 : :
192 : : GIIrParser *
193 : 0 : gi_ir_parser_new (void)
194 : : {
195 : 0 : GIIrParser *parser = g_slice_new0 (GIIrParser);
196 : 0 : const char *gi_gir_path = g_getenv ("GI_GIR_PATH");
197 : :
198 [ # # ]: 0 : if (gi_gir_path != NULL)
199 : 0 : parser->gi_gir_path = g_strsplit (gi_gir_path, G_SEARCHPATH_SEPARATOR_S, 0);
200 : :
201 : 0 : parser->logged_levels = G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_DEBUG);
202 : 0 : return parser;
203 : : }
204 : :
205 : : void
206 : 0 : gi_ir_parser_set_debug (GIIrParser *parser,
207 : : GLogLevelFlags logged_levels)
208 : : {
209 : 0 : parser->logged_levels = logged_levels;
210 : 0 : }
211 : :
212 : : void
213 : 0 : gi_ir_parser_free (GIIrParser *parser)
214 : : {
215 : : GList *l;
216 : :
217 : 0 : g_strfreev (parser->includes);
218 : 0 : g_strfreev (parser->gi_gir_path);
219 : :
220 [ # # ]: 0 : for (l = parser->parsed_modules; l; l = l->next)
221 : 0 : gi_ir_module_free (l->data);
222 : :
223 : 0 : g_slice_free (GIIrParser, parser);
224 : 0 : }
225 : :
226 : : void
227 : 0 : gi_ir_parser_set_includes (GIIrParser *parser,
228 : : const char *const *includes)
229 : : {
230 : 0 : g_strfreev (parser->includes);
231 : :
232 : 0 : parser->includes = g_strdupv ((char **)includes);
233 : 0 : }
234 : :
235 : : static void
236 : 0 : firstpass_start_element_handler (GMarkupParseContext *context,
237 : : const char *element_name,
238 : : const char **attribute_names,
239 : : const char **attribute_values,
240 : : void *user_data,
241 : : GError **error)
242 : : {
243 : 0 : ParseContext *ctx = user_data;
244 : :
245 [ # # ]: 0 : if (strcmp (element_name, "alias") == 0)
246 : : {
247 : 0 : start_alias (context, element_name, attribute_names, attribute_values,
248 : : ctx, error);
249 : : }
250 [ # # # # ]: 0 : else if (ctx->state == STATE_ALIAS && strcmp (element_name, "type") == 0)
251 : : {
252 : 0 : start_type (context, element_name, attribute_names, attribute_values,
253 : : ctx, error);
254 : : }
255 [ # # ]: 0 : else if (strcmp (element_name, "record") == 0)
256 : : {
257 : : const char *name;
258 : : const char *disguised;
259 : : const char *pointer;
260 : :
261 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
262 : 0 : disguised = find_attribute ("disguised", attribute_names, attribute_values);
263 : 0 : pointer = find_attribute ("pointer", attribute_names, attribute_values);
264 : :
265 [ # # ]: 0 : if (g_strcmp0 (pointer, "1") == 0)
266 : : {
267 : : char *key;
268 : :
269 : 0 : key = g_strdup_printf ("%s.%s", ctx->namespace, name);
270 : 0 : g_hash_table_replace (ctx->pointer_structures, key, GINT_TO_POINTER (1));
271 : : }
272 [ # # ]: 0 : else if (g_strcmp0 (disguised, "1") == 0)
273 : : {
274 : : char *key;
275 : :
276 : 0 : key = g_strdup_printf ("%s.%s", ctx->namespace, name);
277 : 0 : g_hash_table_replace (ctx->disguised_structures, key, GINT_TO_POINTER (1));
278 : : }
279 : : }
280 : 0 : }
281 : :
282 : : static void
283 : 0 : firstpass_end_element_handler (GMarkupParseContext *context,
284 : : const char *element_name,
285 : : gpointer user_data,
286 : : GError **error)
287 : : {
288 : 0 : ParseContext *ctx = user_data;
289 [ # # ]: 0 : if (strcmp (element_name, "alias") == 0)
290 : : {
291 : 0 : state_switch (ctx, STATE_NAMESPACE);
292 : 0 : g_free (ctx->current_alias);
293 : 0 : ctx->current_alias = NULL;
294 : : }
295 [ # # # # ]: 0 : else if (strcmp (element_name, "type") == 0 && ctx->state == STATE_TYPE)
296 : 0 : state_switch (ctx, ctx->prev_state);
297 : 0 : }
298 : :
299 : : static GMarkupParser firstpass_parser =
300 : : {
301 : : firstpass_start_element_handler,
302 : : firstpass_end_element_handler,
303 : : NULL,
304 : : NULL,
305 : : NULL,
306 : : };
307 : :
308 : : static char *
309 : 0 : locate_gir (GIIrParser *parser,
310 : : const char *girname)
311 : : {
312 : : const char *const *datadirs;
313 : : const char *const *dir;
314 : 0 : char *path = NULL;
315 : :
316 : 0 : g_debug ("Looking for %s", girname);
317 : 0 : datadirs = g_get_system_data_dirs ();
318 : :
319 [ # # ]: 0 : if (parser->includes != NULL)
320 : : {
321 [ # # ]: 0 : for (dir = (const char *const *)parser->includes; *dir; dir++)
322 : : {
323 : 0 : path = g_build_filename (*dir, girname, NULL);
324 : 0 : g_debug ("Trying %s from includes", path);
325 [ # # ]: 0 : if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
326 : 0 : return g_steal_pointer (&path);
327 : 0 : g_clear_pointer (&path, g_free);
328 : : }
329 : : }
330 : :
331 [ # # ]: 0 : if (parser->gi_gir_path != NULL)
332 : : {
333 [ # # ]: 0 : for (dir = (const char *const *) parser->gi_gir_path; *dir; dir++)
334 : : {
335 [ # # ]: 0 : if (**dir == '\0')
336 : 0 : continue;
337 : :
338 : 0 : path = g_build_filename (*dir, girname, NULL);
339 : 0 : g_debug ("Trying %s from GI_GIR_PATH", path);
340 [ # # ]: 0 : if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
341 : 0 : return g_steal_pointer (&path);
342 : 0 : g_clear_pointer (&path, g_free);
343 : : }
344 : : }
345 : :
346 : 0 : path = g_build_filename (g_get_user_data_dir (), GIR_SUFFIX, girname, NULL);
347 : 0 : g_debug ("Trying %s from user data dir", path);
348 [ # # ]: 0 : if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
349 : 0 : return g_steal_pointer (&path);
350 : 0 : g_clear_pointer (&path, g_free);
351 : :
352 [ # # ]: 0 : for (dir = datadirs; *dir; dir++)
353 : : {
354 : 0 : path = g_build_filename (*dir, GIR_SUFFIX, girname, NULL);
355 : 0 : g_debug ("Trying %s from system data dirs", path);
356 [ # # ]: 0 : if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
357 : 0 : return g_steal_pointer (&path);
358 : 0 : g_clear_pointer (&path, g_free);
359 : : }
360 : :
361 : 0 : path = g_build_filename (GIR_DIR, girname, NULL);
362 : 0 : g_debug ("Trying %s from GIR_DIR", path);
363 [ # # ]: 0 : if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
364 : 0 : return g_steal_pointer (&path);
365 : 0 : g_clear_pointer (&path, g_free);
366 : :
367 : 0 : path = g_build_filename (GOBJECT_INTROSPECTION_DATADIR, GIR_SUFFIX, girname, NULL);
368 : 0 : g_debug ("Trying %s from DATADIR", path);
369 [ # # ]: 0 : if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
370 : 0 : return g_steal_pointer (&path);
371 : 0 : g_clear_pointer (&path, g_free);
372 : :
373 : : #ifdef G_OS_UNIX
374 : 0 : path = g_build_filename ("/usr/share", GIR_SUFFIX, girname, NULL);
375 : 0 : g_debug ("Trying %s", path);
376 [ # # ]: 0 : if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
377 : 0 : return g_steal_pointer (&path);
378 : 0 : g_clear_pointer (&path, g_free);
379 : : #endif
380 : :
381 : 0 : g_debug ("Did not find %s", girname);
382 : 0 : return NULL;
383 : : }
384 : :
385 : : #define MISSING_ATTRIBUTE(context,error,element,attribute) \
386 : : do { \
387 : : int line_number, char_number; \
388 : : g_markup_parse_context_get_position (context, &line_number, &char_number); \
389 : : g_set_error (error, \
390 : : G_MARKUP_ERROR, \
391 : : G_MARKUP_ERROR_INVALID_CONTENT, \
392 : : "Line %d, character %d: The attribute '%s' on the element '%s' must be specified", \
393 : : line_number, char_number, attribute, element); \
394 : : } while (0)
395 : :
396 : : static const char *
397 : 0 : find_attribute (const char *name,
398 : : const char **attribute_names,
399 : : const char **attribute_values)
400 : : {
401 : : size_t i;
402 : :
403 [ # # ]: 0 : for (i = 0; attribute_names[i] != NULL; i++)
404 [ # # ]: 0 : if (strcmp (attribute_names[i], name) == 0)
405 : 0 : return attribute_values[i];
406 : :
407 : 0 : return 0;
408 : : }
409 : :
410 : : static void
411 : 0 : state_switch (ParseContext *ctx, ParseState newstate)
412 : : {
413 : 0 : g_assert (ctx->state != newstate);
414 : 0 : ctx->prev_state = ctx->state;
415 : 0 : ctx->state = newstate;
416 : :
417 [ # # ]: 0 : if (ctx->state == STATE_PASSTHROUGH)
418 : 0 : ctx->unknown_depth = 1;
419 : 0 : }
420 : :
421 : : static GIIrNode *
422 : 0 : pop_node (ParseContext *ctx)
423 : : {
424 : : GSList *top;
425 : : GIIrNode *node;
426 : 0 : g_assert (ctx->node_stack != 0);
427 : :
428 : 0 : top = ctx->node_stack;
429 : 0 : node = top->data;
430 : :
431 : 0 : g_debug ("popping node %d %s", node->type, node->name);
432 : 0 : ctx->node_stack = top->next;
433 : 0 : g_slist_free_1 (top);
434 : 0 : return node;
435 : : }
436 : :
437 : : static void
438 : 0 : push_node (ParseContext *ctx, GIIrNode *node)
439 : : {
440 : 0 : g_assert (node != NULL);
441 : 0 : g_debug ("pushing node %d %s", node->type, node->name);
442 : 0 : ctx->node_stack = g_slist_prepend (ctx->node_stack, node);
443 : 0 : }
444 : :
445 : : static GIIrNodeType * parse_type_internal (GIIrModule *module,
446 : : const char *str,
447 : : char **next,
448 : : gboolean in_glib,
449 : : gboolean in_gobject);
450 : :
451 : : typedef struct {
452 : : const char *str;
453 : : size_t size;
454 : : unsigned int is_signed : 1;
455 : : } IntegerAliasInfo;
456 : :
457 : : /*
458 : : * signedness:
459 : : * @T: a numeric type
460 : : *
461 : : * Returns: 1 if @T is signed, 0 if it is unsigned
462 : : */
463 : : #define signedness(T) (((T) -1) <= 0)
464 : : G_STATIC_ASSERT (signedness (int) == 1);
465 : : G_STATIC_ASSERT (signedness (unsigned int) == 0);
466 : :
467 : : static IntegerAliasInfo integer_aliases[] = {
468 : : { "gchar", sizeof (gchar), 1 },
469 : : { "guchar", sizeof (guchar), 0 },
470 : : { "gshort", sizeof (gshort), 1 },
471 : : { "gushort", sizeof (gushort), 0 },
472 : : { "gint", sizeof (gint), 1 },
473 : : { "guint", sizeof (guint), 0 },
474 : : { "glong", sizeof (glong), 1 },
475 : : { "gulong", sizeof (gulong), 0 },
476 : : { "gssize", sizeof (gssize), 1 },
477 : : { "gsize", sizeof (gsize), 0 },
478 : : { "gintptr", sizeof (gintptr), 1 },
479 : : { "guintptr", sizeof (guintptr), 0 },
480 : : #define INTEGER_ALIAS(T) { #T, sizeof (T), signedness (T) }
481 : : INTEGER_ALIAS (off_t),
482 : : INTEGER_ALIAS (time_t),
483 : : #ifdef G_OS_UNIX
484 : : INTEGER_ALIAS (dev_t),
485 : : INTEGER_ALIAS (gid_t),
486 : : INTEGER_ALIAS (pid_t),
487 : : INTEGER_ALIAS (socklen_t),
488 : : INTEGER_ALIAS (uid_t),
489 : : #endif
490 : : #undef INTEGER_ALIAS
491 : : };
492 : :
493 : : typedef struct {
494 : : const char *str;
495 : : int tag;
496 : : gboolean pointer;
497 : : } BasicTypeInfo;
498 : :
499 : : #define BASIC_TYPE_FIXED_OFFSET 3
500 : :
501 : : static BasicTypeInfo basic_types[] = {
502 : : { "none", GI_TYPE_TAG_VOID, 0 },
503 : : { "gpointer", GI_TYPE_TAG_VOID, 1 },
504 : :
505 : : { "gboolean", GI_TYPE_TAG_BOOLEAN, 0 },
506 : : { "gint8", GI_TYPE_TAG_INT8, 0 }, /* Start of BASIC_TYPE_FIXED_OFFSET */
507 : : { "guint8", GI_TYPE_TAG_UINT8, 0 },
508 : : { "gint16", GI_TYPE_TAG_INT16, 0 },
509 : : { "guint16", GI_TYPE_TAG_UINT16, 0 },
510 : : { "gint32", GI_TYPE_TAG_INT32, 0 },
511 : : { "guint32", GI_TYPE_TAG_UINT32, 0 },
512 : : { "gint64", GI_TYPE_TAG_INT64, 0 },
513 : : { "guint64", GI_TYPE_TAG_UINT64, 0 },
514 : : { "gfloat", GI_TYPE_TAG_FLOAT, 0 },
515 : : { "gdouble", GI_TYPE_TAG_DOUBLE, 0 },
516 : : { "GType", GI_TYPE_TAG_GTYPE, 0 },
517 : : { "utf8", GI_TYPE_TAG_UTF8, 1 },
518 : : { "filename", GI_TYPE_TAG_FILENAME,1 },
519 : : { "gunichar", GI_TYPE_TAG_UNICHAR, 0 },
520 : : };
521 : :
522 : : static const BasicTypeInfo *
523 : 0 : parse_basic (const char *str)
524 : : {
525 : : size_t i;
526 : 0 : size_t n_basic = G_N_ELEMENTS (basic_types);
527 : :
528 [ # # ]: 0 : for (i = 0; i < n_basic; i++)
529 : : {
530 [ # # ]: 0 : if (strcmp (str, basic_types[i].str) == 0)
531 : 0 : return &(basic_types[i]);
532 : : }
533 [ # # ]: 0 : for (i = 0; i < G_N_ELEMENTS (integer_aliases); i++)
534 : : {
535 [ # # ]: 0 : if (strcmp (str, integer_aliases[i].str) == 0)
536 : : {
537 [ # # # # : 0 : switch (integer_aliases[i].size)
# ]
538 : : {
539 : 0 : case sizeof (uint8_t):
540 [ # # ]: 0 : if (integer_aliases[i].is_signed)
541 : 0 : return &basic_types[BASIC_TYPE_FIXED_OFFSET];
542 : : else
543 : 0 : return &basic_types[BASIC_TYPE_FIXED_OFFSET+1];
544 : : break;
545 : 0 : case sizeof (uint16_t):
546 [ # # ]: 0 : if (integer_aliases[i].is_signed)
547 : 0 : return &basic_types[BASIC_TYPE_FIXED_OFFSET+2];
548 : : else
549 : 0 : return &basic_types[BASIC_TYPE_FIXED_OFFSET+3];
550 : : break;
551 : 0 : case sizeof (uint32_t):
552 [ # # ]: 0 : if (integer_aliases[i].is_signed)
553 : 0 : return &basic_types[BASIC_TYPE_FIXED_OFFSET+4];
554 : : else
555 : 0 : return &basic_types[BASIC_TYPE_FIXED_OFFSET+5];
556 : : break;
557 : 0 : case sizeof (uint64_t):
558 [ # # ]: 0 : if (integer_aliases[i].is_signed)
559 : 0 : return &basic_types[BASIC_TYPE_FIXED_OFFSET+6];
560 : : else
561 : 0 : return &basic_types[BASIC_TYPE_FIXED_OFFSET+7];
562 : : break;
563 : 0 : default:
564 : : g_assert_not_reached ();
565 : : }
566 : : }
567 : : }
568 : 0 : return NULL;
569 : : }
570 : :
571 : : static GIIrNodeType *
572 : 0 : parse_type_internal (GIIrModule *module,
573 : : const char *str,
574 : : char **next,
575 : : gboolean in_glib,
576 : : gboolean in_gobject)
577 : : {
578 : : const BasicTypeInfo *basic;
579 : : GIIrNodeType *type;
580 : 0 : char *temporary_type = NULL;
581 : :
582 : 0 : type = (GIIrNodeType *)gi_ir_node_new (GI_IR_NODE_TYPE, module);
583 : :
584 : 0 : type->unparsed = g_strdup (str);
585 : :
586 : : /* See comment below on GLib.List handling */
587 [ # # # # ]: 0 : if (in_gobject && strcmp (str, "Type") == 0)
588 : : {
589 : 0 : temporary_type = g_strdup ("GLib.Type");
590 : 0 : str = temporary_type;
591 : : }
592 : :
593 : 0 : basic = parse_basic (str);
594 [ # # ]: 0 : if (basic != NULL)
595 : : {
596 : 0 : type->is_basic = TRUE;
597 : 0 : type->tag = basic->tag;
598 : 0 : type->is_pointer = basic->pointer;
599 : :
600 : 0 : str += strlen(basic->str);
601 : : }
602 [ # # ]: 0 : else if (in_glib)
603 : : {
604 : : /* If we're inside GLib, handle "List" etc. by prefixing with
605 : : * "GLib." so the parsing code below doesn't have to get more
606 : : * special.
607 : : */
608 [ # # # # : 0 : if (g_str_has_prefix (str, "List<") ||
# # # # ]
609 [ # # ]: 0 : strcmp (str, "List") == 0)
610 : : {
611 : 0 : temporary_type = g_strdup_printf ("GLib.List%s", str + 4);
612 : 0 : str = temporary_type;
613 : : }
614 [ # # # # : 0 : else if (g_str_has_prefix (str, "SList<") ||
# # # # ]
615 [ # # ]: 0 : strcmp (str, "SList") == 0)
616 : : {
617 : 0 : temporary_type = g_strdup_printf ("GLib.SList%s", str + 5);
618 : 0 : str = temporary_type;
619 : : }
620 [ # # # # : 0 : else if (g_str_has_prefix (str, "HashTable<") ||
# # # # ]
621 [ # # ]: 0 : strcmp (str, "HashTable") == 0)
622 : : {
623 : 0 : temporary_type = g_strdup_printf ("GLib.HashTable%s", str + 9);
624 : 0 : str = temporary_type;
625 : : }
626 [ # # # # : 0 : else if (g_str_has_prefix (str, "Error<") ||
# # # # ]
627 [ # # ]: 0 : strcmp (str, "Error") == 0)
628 : : {
629 : 0 : temporary_type = g_strdup_printf ("GLib.Error%s", str + 5);
630 : 0 : str = temporary_type;
631 : : }
632 : : }
633 : :
634 [ # # ]: 0 : if (basic != NULL)
635 : : /* found a basic type */;
636 [ # # # # : 0 : else if (g_str_has_prefix (str, "GLib.List") ||
# # # # ]
637 [ # # # # : 0 : g_str_has_prefix (str, "GLib.SList"))
# # # # ]
638 : : {
639 : 0 : str += strlen ("GLib.");
640 [ # # # # : 0 : if (g_str_has_prefix (str, "List"))
# # # # ]
641 : : {
642 : 0 : type->tag = GI_TYPE_TAG_GLIST;
643 : 0 : type->is_glist = TRUE;
644 : 0 : type->is_pointer = TRUE;
645 : 0 : str += strlen ("List");
646 : : }
647 : : else
648 : : {
649 : 0 : type->tag = GI_TYPE_TAG_GSLIST;
650 : 0 : type->is_gslist = TRUE;
651 : 0 : type->is_pointer = TRUE;
652 : 0 : str += strlen ("SList");
653 : : }
654 : : }
655 [ # # # # : 0 : else if (g_str_has_prefix (str, "GLib.HashTable"))
# # # # ]
656 : : {
657 : 0 : str += strlen ("GLib.");
658 : :
659 : 0 : type->tag = GI_TYPE_TAG_GHASH;
660 : 0 : type->is_ghashtable = TRUE;
661 : 0 : type->is_pointer = TRUE;
662 : 0 : str += strlen ("HashTable");
663 : : }
664 [ # # # # : 0 : else if (g_str_has_prefix (str, "GLib.Error"))
# # # # ]
665 : : {
666 : 0 : str += strlen ("GLib.");
667 : :
668 : 0 : type->tag = GI_TYPE_TAG_ERROR;
669 : 0 : type->is_error = TRUE;
670 : 0 : type->is_pointer = TRUE;
671 : 0 : str += strlen ("Error");
672 : :
673 : : /* Silence a scan-build false positive */
674 : 0 : g_assert (str != NULL);
675 : :
676 [ # # ]: 0 : if (*str == '<')
677 : : {
678 : : char *tmp, *end;
679 : 0 : (str)++;
680 : :
681 : 0 : end = strchr (str, '>');
682 : 0 : tmp = g_strndup (str, end - str);
683 : 0 : type->errors = g_strsplit (tmp, ",", 0);
684 : 0 : g_free (tmp);
685 : :
686 : 0 : str = end;
687 : : }
688 : : }
689 : : else
690 : : {
691 : : const char *start;
692 : 0 : type->tag = GI_TYPE_TAG_INTERFACE;
693 : 0 : type->is_interface = TRUE;
694 : 0 : start = str;
695 : :
696 : : /* must be an interface type */
697 : 0 : while (g_ascii_isalnum (*str) ||
698 [ # # ]: 0 : *str == '.' ||
699 [ # # ]: 0 : *str == '-' ||
700 [ # # # # ]: 0 : *str == '_' ||
701 [ # # ]: 0 : *str == ':')
702 : 0 : (str)++;
703 : :
704 : 0 : type->giinterface = g_strndup (start, str - start);
705 : : }
706 : :
707 [ # # ]: 0 : if (next)
708 : 0 : *next = (char*)str;
709 : 0 : g_assert (type->tag >= 0 && type->tag < GI_TYPE_TAG_N_TYPES);
710 : 0 : g_free (temporary_type);
711 : 0 : return type;
712 : :
713 : : /* error: */
714 : : gi_ir_node_free ((GIIrNode *)type);
715 : : g_free (temporary_type);
716 : : return NULL;
717 : : }
718 : :
719 : : static const char *
720 : 0 : resolve_aliases (ParseContext *ctx, const char *type)
721 : : {
722 : : void *orig;
723 : : void *value;
724 : 0 : GSList *seen_values = NULL;
725 : : const char *lookup;
726 : : char *prefixed;
727 : :
728 [ # # ]: 0 : if (strchr (type, '.') == NULL)
729 : : {
730 : 0 : prefixed = g_strdup_printf ("%s.%s", ctx->namespace, type);
731 : 0 : lookup = prefixed;
732 : : }
733 : : else
734 : : {
735 : 0 : lookup = type;
736 : 0 : prefixed = NULL;
737 : : }
738 : :
739 : 0 : seen_values = g_slist_prepend (seen_values, (char*)lookup);
740 [ # # ]: 0 : while (g_hash_table_lookup_extended (ctx->current_module->aliases, lookup, &orig, &value))
741 : : {
742 : 0 : g_debug ("Resolved: %s => %s", lookup, (char*)value);
743 : 0 : lookup = value;
744 [ # # ]: 0 : if (g_slist_find_custom (seen_values, lookup,
745 : : (GCompareFunc)strcmp) != NULL)
746 : 0 : break;
747 : 0 : seen_values = g_slist_prepend (seen_values, (char*) lookup);
748 : : }
749 : 0 : g_slist_free (seen_values);
750 : :
751 [ # # ]: 0 : if (lookup == prefixed)
752 : 0 : lookup = type;
753 : :
754 : 0 : g_free (prefixed);
755 : :
756 : 0 : return lookup;
757 : : }
758 : :
759 : : static void
760 : 0 : is_pointer_or_disguised_structure (ParseContext *ctx,
761 : : const char *type,
762 : : gboolean *is_pointer,
763 : : gboolean *is_disguised)
764 : : {
765 : : const char *lookup;
766 : : char *prefixed;
767 : :
768 [ # # ]: 0 : if (strchr (type, '.') == NULL)
769 : : {
770 : 0 : prefixed = g_strdup_printf ("%s.%s", ctx->namespace, type);
771 : 0 : lookup = prefixed;
772 : : }
773 : : else
774 : : {
775 : 0 : lookup = type;
776 : 0 : prefixed = NULL;
777 : : }
778 : :
779 [ # # ]: 0 : if (is_pointer != NULL)
780 : 0 : *is_pointer = g_hash_table_lookup (ctx->current_module->pointer_structures, lookup) != NULL;
781 [ # # ]: 0 : if (is_disguised != NULL)
782 : 0 : *is_disguised = g_hash_table_lookup (ctx->current_module->disguised_structures, lookup) != NULL;
783 : :
784 : 0 : g_free (prefixed);
785 : 0 : }
786 : :
787 : : static GIIrNodeType *
788 : 0 : parse_type (ParseContext *ctx, const char *type)
789 : : {
790 : : GIIrNodeType *node;
791 : : const BasicTypeInfo *basic;
792 : : gboolean in_glib, in_gobject;
793 : :
794 : 0 : in_glib = strcmp (ctx->namespace, "GLib") == 0;
795 : 0 : in_gobject = strcmp (ctx->namespace, "GObject") == 0;
796 : :
797 : : /* Do not search aliases for basic types */
798 : 0 : basic = parse_basic (type);
799 [ # # ]: 0 : if (basic == NULL)
800 : 0 : type = resolve_aliases (ctx, type);
801 : :
802 : 0 : node = parse_type_internal (ctx->current_module, type, NULL, in_glib, in_gobject);
803 [ # # ]: 0 : if (node)
804 : 0 : g_debug ("Parsed type: %s => %d", type, node->tag);
805 : : else
806 : 0 : g_critical ("Failed to parse type: '%s'", type);
807 : :
808 : 0 : return node;
809 : : }
810 : :
811 : : static gboolean
812 : 0 : introspectable_prelude (GMarkupParseContext *context,
813 : : const char **attribute_names,
814 : : const char **attribute_values,
815 : : ParseContext *ctx,
816 : : ParseState new_state)
817 : : {
818 : : const char *introspectable_arg;
819 : : const char *shadowed_by;
820 : : gboolean introspectable;
821 : :
822 : 0 : g_assert (ctx->state != STATE_PASSTHROUGH);
823 : :
824 : 0 : introspectable_arg = find_attribute ("introspectable", attribute_names, attribute_values);
825 : 0 : shadowed_by = find_attribute ("shadowed-by", attribute_names, attribute_values);
826 : :
827 [ # # # # : 0 : introspectable = !(introspectable_arg && atoi (introspectable_arg) == 0) && shadowed_by == NULL;
# # ]
828 : :
829 [ # # ]: 0 : if (introspectable)
830 : 0 : state_switch (ctx, new_state);
831 : : else
832 : 0 : state_switch (ctx, STATE_PASSTHROUGH);
833 : :
834 : 0 : return introspectable;
835 : : }
836 : :
837 : : static gboolean
838 : 0 : start_glib_boxed (GMarkupParseContext *context,
839 : : const char *element_name,
840 : : const char **attribute_names,
841 : : const char **attribute_values,
842 : : ParseContext *ctx,
843 : : GError **error)
844 : : {
845 : : const char *name;
846 : : const char *typename;
847 : : const char *typeinit;
848 : : const char *deprecated;
849 : : GIIrNodeBoxed *boxed;
850 : :
851 [ # # ]: 0 : if (!(strcmp (element_name, "glib:boxed") == 0 &&
852 [ # # ]: 0 : ctx->state == STATE_NAMESPACE))
853 : 0 : return FALSE;
854 : :
855 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_BOXED))
856 : 0 : return TRUE;
857 : :
858 : 0 : name = find_attribute ("glib:name", attribute_names, attribute_values);
859 : 0 : typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
860 : 0 : typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
861 : 0 : deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
862 : :
863 [ # # ]: 0 : if (name == NULL)
864 : : {
865 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "glib:name");
866 : 0 : return FALSE;
867 : : }
868 [ # # ]: 0 : else if (typename == NULL)
869 : : {
870 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
871 : 0 : return FALSE;
872 : : }
873 [ # # ]: 0 : else if (typeinit == NULL)
874 : : {
875 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
876 : 0 : return FALSE;
877 : : }
878 : :
879 : 0 : boxed = (GIIrNodeBoxed *) gi_ir_node_new (GI_IR_NODE_BOXED,
880 : : ctx->current_module);
881 : :
882 : 0 : ((GIIrNode *)boxed)->name = g_strdup (name);
883 : 0 : boxed->gtype_name = g_strdup (typename);
884 : 0 : boxed->gtype_init = g_strdup (typeinit);
885 [ # # ]: 0 : if (deprecated)
886 : 0 : boxed->deprecated = TRUE;
887 : : else
888 : 0 : boxed->deprecated = FALSE;
889 : :
890 : 0 : push_node (ctx, (GIIrNode *)boxed);
891 : 0 : ctx->current_module->entries =
892 : 0 : g_list_append (ctx->current_module->entries, boxed);
893 : :
894 : 0 : return TRUE;
895 : : }
896 : :
897 : : static gboolean
898 : 0 : start_function (GMarkupParseContext *context,
899 : : const char *element_name,
900 : : const char **attribute_names,
901 : : const char **attribute_values,
902 : : ParseContext *ctx,
903 : : GError **error)
904 : : {
905 : : const char *name;
906 : : const char *shadows;
907 : : const char *symbol;
908 : : const char *deprecated;
909 : : const char *throws;
910 : : const char *set_property;
911 : : const char *get_property;
912 : : GIIrNodeFunction *function;
913 : 0 : gboolean found = FALSE;
914 : 0 : ParseState in_embedded_state = STATE_NONE;
915 : :
916 [ # # # # : 0 : switch (ctx->state)
# # ]
917 : : {
918 : 0 : case STATE_NAMESPACE:
919 [ # # ]: 0 : found = (strcmp (element_name, "function") == 0 ||
920 [ # # ]: 0 : strcmp (element_name, "callback") == 0);
921 : 0 : break;
922 : 0 : case STATE_CLASS:
923 : : case STATE_BOXED:
924 : : case STATE_STRUCT:
925 : : case STATE_UNION:
926 : 0 : found = strcmp (element_name, "constructor") == 0;
927 : : /* fallthrough */
928 : : G_GNUC_FALLTHROUGH;
929 : 0 : case STATE_INTERFACE:
930 : 0 : found = (found ||
931 [ # # ]: 0 : strcmp (element_name, "function") == 0 ||
932 [ # # # # ]: 0 : strcmp (element_name, "method") == 0 ||
933 [ # # ]: 0 : strcmp (element_name, "callback") == 0);
934 : 0 : break;
935 : 0 : case STATE_ENUM:
936 : 0 : found = strcmp (element_name, "function") == 0;
937 : 0 : break;
938 : 0 : case STATE_CLASS_FIELD:
939 : : case STATE_STRUCT_FIELD:
940 [ # # # # ]: 0 : found = (found || strcmp (element_name, "callback") == 0);
941 : 0 : in_embedded_state = ctx->state;
942 : 0 : break;
943 : 0 : default:
944 : 0 : break;
945 : : }
946 : :
947 [ # # ]: 0 : if (!found)
948 : 0 : return FALSE;
949 : :
950 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
951 : 0 : return TRUE;
952 : :
953 : 0 : ctx->in_embedded_state = in_embedded_state;
954 : :
955 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
956 : 0 : shadows = find_attribute ("shadows", attribute_names, attribute_values);
957 : 0 : symbol = find_attribute ("c:identifier", attribute_names, attribute_values);
958 : 0 : deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
959 : 0 : throws = find_attribute ("throws", attribute_names, attribute_values);
960 : 0 : set_property = find_attribute ("glib:set-property", attribute_names, attribute_values);
961 : 0 : get_property = find_attribute ("glib:get-property", attribute_names, attribute_values);
962 : :
963 [ # # ]: 0 : if (name == NULL)
964 : : {
965 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
966 : 0 : return FALSE;
967 : : }
968 [ # # # # ]: 0 : else if (strcmp (element_name, "callback") != 0 && symbol == NULL)
969 : : {
970 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "c:identifier");
971 : 0 : return FALSE;
972 : : }
973 : :
974 [ # # ]: 0 : if (shadows)
975 : 0 : name = shadows;
976 : :
977 : 0 : function = (GIIrNodeFunction *) gi_ir_node_new (GI_IR_NODE_FUNCTION,
978 : : ctx->current_module);
979 : :
980 : 0 : ((GIIrNode *)function)->name = g_strdup (name);
981 : 0 : function->symbol = g_strdup (symbol);
982 : 0 : function->parameters = NULL;
983 [ # # ]: 0 : if (deprecated)
984 : 0 : function->deprecated = TRUE;
985 : : else
986 : 0 : function->deprecated = FALSE;
987 : :
988 [ # # ]: 0 : if (strcmp (element_name, "method") == 0 ||
989 [ # # ]: 0 : strcmp (element_name, "constructor") == 0)
990 : : {
991 : 0 : function->is_method = TRUE;
992 : :
993 [ # # ]: 0 : if (strcmp (element_name, "constructor") == 0)
994 : 0 : function->is_constructor = TRUE;
995 : : else
996 : 0 : function->is_constructor = FALSE;
997 : :
998 [ # # ]: 0 : if (set_property != NULL)
999 : : {
1000 : 0 : function->is_setter = TRUE;
1001 : 0 : function->is_getter = FALSE;
1002 : 0 : function->property = g_strdup (set_property);
1003 : : }
1004 [ # # ]: 0 : else if (get_property != NULL)
1005 : : {
1006 : 0 : function->is_setter = FALSE;
1007 : 0 : function->is_getter = TRUE;
1008 : 0 : function->property = g_strdup (get_property);
1009 : : }
1010 : : else
1011 : : {
1012 : 0 : function->is_setter = FALSE;
1013 : 0 : function->is_getter = FALSE;
1014 : 0 : function->property = NULL;
1015 : : }
1016 : : }
1017 : : else
1018 : : {
1019 : 0 : function->is_method = FALSE;
1020 : 0 : function->is_setter = FALSE;
1021 : 0 : function->is_getter = FALSE;
1022 : 0 : function->is_constructor = FALSE;
1023 [ # # ]: 0 : if (strcmp (element_name, "callback") == 0)
1024 : 0 : ((GIIrNode *)function)->type = GI_IR_NODE_CALLBACK;
1025 : : }
1026 : :
1027 [ # # # # ]: 0 : if (throws && strcmp (throws, "1") == 0)
1028 : 0 : function->throws = TRUE;
1029 : : else
1030 : 0 : function->throws = FALSE;
1031 : :
1032 [ # # ]: 0 : if (ctx->node_stack == NULL)
1033 : : {
1034 : 0 : ctx->current_module->entries =
1035 : 0 : g_list_append (ctx->current_module->entries, function);
1036 : : }
1037 [ # # ]: 0 : else if (ctx->current_typed)
1038 : : {
1039 : : GIIrNodeField *field;
1040 : :
1041 : 0 : field = (GIIrNodeField *)ctx->current_typed;
1042 : 0 : field->callback = function;
1043 : : }
1044 : : else
1045 [ # # # # : 0 : switch (CURRENT_NODE (ctx)->type)
# # ]
1046 : : {
1047 : 0 : case GI_IR_NODE_INTERFACE:
1048 : : case GI_IR_NODE_OBJECT:
1049 : : {
1050 : : GIIrNodeInterface *iface;
1051 : :
1052 : 0 : iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
1053 : 0 : iface->members = g_list_append (iface->members, function);
1054 : : }
1055 : 0 : break;
1056 : 0 : case GI_IR_NODE_BOXED:
1057 : : {
1058 : : GIIrNodeBoxed *boxed;
1059 : :
1060 : 0 : boxed = (GIIrNodeBoxed *)CURRENT_NODE (ctx);
1061 : 0 : boxed->members = g_list_append (boxed->members, function);
1062 : : }
1063 : 0 : break;
1064 : 0 : case GI_IR_NODE_STRUCT:
1065 : : {
1066 : : GIIrNodeStruct *struct_;
1067 : :
1068 : 0 : struct_ = (GIIrNodeStruct *)CURRENT_NODE (ctx);
1069 : 0 : struct_->members = g_list_append (struct_->members, function); }
1070 : 0 : break;
1071 : 0 : case GI_IR_NODE_UNION:
1072 : : {
1073 : : GIIrNodeUnion *union_;
1074 : :
1075 : 0 : union_ = (GIIrNodeUnion *)CURRENT_NODE (ctx);
1076 : 0 : union_->members = g_list_append (union_->members, function);
1077 : : }
1078 : 0 : break;
1079 : 0 : case GI_IR_NODE_ENUM:
1080 : : case GI_IR_NODE_FLAGS:
1081 : : {
1082 : : GIIrNodeEnum *enum_;
1083 : :
1084 : 0 : enum_ = (GIIrNodeEnum *)CURRENT_NODE (ctx);
1085 : 0 : enum_->methods = g_list_append (enum_->methods, function);
1086 : : }
1087 : 0 : break;
1088 : 0 : default:
1089 : : g_assert_not_reached ();
1090 : : }
1091 : :
1092 : 0 : push_node(ctx, (GIIrNode *)function);
1093 : :
1094 : 0 : return TRUE;
1095 : : }
1096 : :
1097 : : static void
1098 : 0 : parse_property_transfer (GIIrNodeProperty *property,
1099 : : const char *transfer,
1100 : : ParseContext *ctx)
1101 : : {
1102 [ # # ]: 0 : if (transfer == NULL)
1103 : : {
1104 : : #if 0
1105 : : GIIrNodeInterface *iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
1106 : :
1107 : : g_debug ("required attribute 'transfer-ownership' is missing from "
1108 : : "property '%s' in type '%s.%s'. Assuming 'none'",
1109 : : property->node.name, ctx->namespace, iface->node.name);
1110 : : #endif
1111 : 0 : transfer = "none";
1112 : : }
1113 [ # # ]: 0 : if (strcmp (transfer, "none") == 0)
1114 : : {
1115 : 0 : property->transfer = FALSE;
1116 : 0 : property->shallow_transfer = FALSE;
1117 : : }
1118 [ # # ]: 0 : else if (strcmp (transfer, "container") == 0)
1119 : : {
1120 : 0 : property->transfer = FALSE;
1121 : 0 : property->shallow_transfer = TRUE;
1122 : : }
1123 [ # # ]: 0 : else if (strcmp (transfer, "full") == 0)
1124 : : {
1125 : 0 : property->transfer = TRUE;
1126 : 0 : property->shallow_transfer = FALSE;
1127 : : }
1128 : : else
1129 : : {
1130 : 0 : GIIrNodeInterface *iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
1131 : :
1132 : 0 : g_warning ("Unknown transfer-ownership value: '%s' for property '%s' in "
1133 : : "type '%s.%s'", transfer, property->node.name, ctx->namespace,
1134 : : iface->node.name);
1135 : : }
1136 : 0 : }
1137 : :
1138 : : static gboolean
1139 : 0 : parse_param_transfer (GIIrNodeParam *param, const char *transfer, const char *name,
1140 : : GError **error)
1141 : : {
1142 [ # # ]: 0 : if (transfer == NULL)
1143 : : {
1144 : 0 : g_set_error (error, G_MARKUP_ERROR,
1145 : : G_MARKUP_ERROR_INVALID_CONTENT,
1146 : : "required attribute 'transfer-ownership' missing");
1147 : 0 : return FALSE;
1148 : : }
1149 [ # # ]: 0 : else if (strcmp (transfer, "none") == 0)
1150 : : {
1151 : 0 : param->transfer = FALSE;
1152 : 0 : param->shallow_transfer = FALSE;
1153 : : }
1154 [ # # ]: 0 : else if (strcmp (transfer, "container") == 0)
1155 : : {
1156 : 0 : param->transfer = FALSE;
1157 : 0 : param->shallow_transfer = TRUE;
1158 : : }
1159 [ # # ]: 0 : else if (strcmp (transfer, "full") == 0)
1160 : : {
1161 : 0 : param->transfer = TRUE;
1162 : 0 : param->shallow_transfer = FALSE;
1163 : : }
1164 : : else
1165 : : {
1166 : 0 : g_set_error (error, G_MARKUP_ERROR,
1167 : : G_MARKUP_ERROR_INVALID_CONTENT,
1168 : : "invalid value for 'transfer-ownership': %s", transfer);
1169 : 0 : return FALSE;
1170 : : }
1171 : 0 : return TRUE;
1172 : : }
1173 : :
1174 : : static gboolean
1175 : 0 : start_instance_parameter (GMarkupParseContext *context,
1176 : : const char *element_name,
1177 : : const char **attribute_names,
1178 : : const char **attribute_values,
1179 : : ParseContext *ctx,
1180 : : GError **error)
1181 : : {
1182 : : const char *transfer;
1183 : : gboolean transfer_full;
1184 : :
1185 [ # # ]: 0 : if (!(strcmp (element_name, "instance-parameter") == 0 &&
1186 [ # # ]: 0 : ctx->state == STATE_FUNCTION_PARAMETERS))
1187 : 0 : return FALSE;
1188 : :
1189 : 0 : transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
1190 : :
1191 : 0 : state_switch (ctx, STATE_PASSTHROUGH);
1192 : :
1193 [ # # ]: 0 : if (g_strcmp0 (transfer, "full") == 0)
1194 : 0 : transfer_full = TRUE;
1195 [ # # ]: 0 : else if (g_strcmp0 (transfer, "none") == 0)
1196 : 0 : transfer_full = FALSE;
1197 : : else
1198 : : {
1199 : 0 : g_set_error (error, G_MARKUP_ERROR,
1200 : : G_MARKUP_ERROR_INVALID_CONTENT,
1201 : : "invalid value for 'transfer-ownership' for instance parameter: %s", transfer);
1202 : 0 : return FALSE;
1203 : : }
1204 : :
1205 [ # # # # ]: 0 : switch (CURRENT_NODE (ctx)->type)
1206 : : {
1207 : 0 : case GI_IR_NODE_FUNCTION:
1208 : : case GI_IR_NODE_CALLBACK:
1209 : : {
1210 : : GIIrNodeFunction *func;
1211 : :
1212 : 0 : func = (GIIrNodeFunction *)CURRENT_NODE (ctx);
1213 : 0 : func->instance_transfer_full = transfer_full;
1214 : : }
1215 : 0 : break;
1216 : 0 : case GI_IR_NODE_SIGNAL:
1217 : : {
1218 : : GIIrNodeSignal *signal;
1219 : :
1220 : 0 : signal = (GIIrNodeSignal *)CURRENT_NODE (ctx);
1221 : 0 : signal->instance_transfer_full = transfer_full;
1222 : : }
1223 : 0 : break;
1224 : 0 : case GI_IR_NODE_VFUNC:
1225 : : {
1226 : : GIIrNodeVFunc *vfunc;
1227 : :
1228 : 0 : vfunc = (GIIrNodeVFunc *)CURRENT_NODE (ctx);
1229 : 0 : vfunc->instance_transfer_full = transfer_full;
1230 : : }
1231 : 0 : break;
1232 : 0 : default:
1233 : : g_assert_not_reached ();
1234 : : }
1235 : :
1236 : 0 : return TRUE;
1237 : : }
1238 : :
1239 : : static gboolean
1240 : 0 : start_parameter (GMarkupParseContext *context,
1241 : : const char *element_name,
1242 : : const char **attribute_names,
1243 : : const char **attribute_values,
1244 : : ParseContext *ctx,
1245 : : GError **error)
1246 : : {
1247 : : const char *name;
1248 : : const char *direction;
1249 : : const char *retval;
1250 : : const char *optional;
1251 : : const char *caller_allocates;
1252 : : const char *allow_none;
1253 : : const char *transfer;
1254 : : const char *scope;
1255 : : const char *closure;
1256 : : const char *destroy;
1257 : : const char *skip;
1258 : : const char *nullable;
1259 : : GIIrNodeParam *param;
1260 : :
1261 [ # # ]: 0 : if (!(strcmp (element_name, "parameter") == 0 &&
1262 [ # # ]: 0 : ctx->state == STATE_FUNCTION_PARAMETERS))
1263 : 0 : return FALSE;
1264 : :
1265 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
1266 : 0 : direction = find_attribute ("direction", attribute_names, attribute_values);
1267 : 0 : retval = find_attribute ("retval", attribute_names, attribute_values);
1268 : 0 : optional = find_attribute ("optional", attribute_names, attribute_values);
1269 : 0 : allow_none = find_attribute ("allow-none", attribute_names, attribute_values);
1270 : 0 : caller_allocates = find_attribute ("caller-allocates", attribute_names, attribute_values);
1271 : 0 : transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
1272 : 0 : scope = find_attribute ("scope", attribute_names, attribute_values);
1273 : 0 : closure = find_attribute ("closure", attribute_names, attribute_values);
1274 : 0 : destroy = find_attribute ("destroy", attribute_names, attribute_values);
1275 : 0 : skip = find_attribute ("skip", attribute_names, attribute_values);
1276 : 0 : nullable = find_attribute ("nullable", attribute_names, attribute_values);
1277 : :
1278 [ # # ]: 0 : if (name == NULL)
1279 : 0 : name = "unknown";
1280 : :
1281 : 0 : param = (GIIrNodeParam *)gi_ir_node_new (GI_IR_NODE_PARAM,
1282 : : ctx->current_module);
1283 : :
1284 : 0 : ctx->current_typed = (GIIrNode*) param;
1285 : 0 : ctx->current_typed->name = g_strdup (name);
1286 : :
1287 : 0 : state_switch (ctx, STATE_FUNCTION_PARAMETER);
1288 : :
1289 [ # # # # ]: 0 : if (direction && strcmp (direction, "out") == 0)
1290 : : {
1291 : 0 : param->in = FALSE;
1292 : 0 : param->out = TRUE;
1293 [ # # ]: 0 : if (caller_allocates == NULL)
1294 : 0 : param->caller_allocates = FALSE;
1295 : : else
1296 : 0 : param->caller_allocates = strcmp (caller_allocates, "1") == 0;
1297 : : }
1298 [ # # # # ]: 0 : else if (direction && strcmp (direction, "inout") == 0)
1299 : : {
1300 : 0 : param->in = TRUE;
1301 : 0 : param->out = TRUE;
1302 : 0 : param->caller_allocates = FALSE;
1303 : : }
1304 : : else
1305 : : {
1306 : 0 : param->in = TRUE;
1307 : 0 : param->out = FALSE;
1308 : 0 : param->caller_allocates = FALSE;
1309 : : }
1310 : :
1311 [ # # # # ]: 0 : if (retval && strcmp (retval, "1") == 0)
1312 : 0 : param->retval = TRUE;
1313 : : else
1314 : 0 : param->retval = FALSE;
1315 : :
1316 [ # # # # ]: 0 : if (optional && strcmp (optional, "1") == 0)
1317 : 0 : param->optional = TRUE;
1318 : : else
1319 : 0 : param->optional = FALSE;
1320 : :
1321 [ # # # # ]: 0 : if (nullable && strcmp (nullable, "1") == 0)
1322 : 0 : param->nullable = TRUE;
1323 : : else
1324 : 0 : param->nullable = FALSE;
1325 : :
1326 [ # # # # ]: 0 : if (allow_none && strcmp (allow_none, "1") == 0)
1327 : : {
1328 [ # # ]: 0 : if (param->out)
1329 : 0 : param->optional = TRUE;
1330 : : else
1331 : 0 : param->nullable = TRUE;
1332 : : }
1333 : :
1334 [ # # # # ]: 0 : if (skip && strcmp (skip, "1") == 0)
1335 : 0 : param->skip = TRUE;
1336 : : else
1337 : 0 : param->skip = FALSE;
1338 : :
1339 [ # # ]: 0 : if (!parse_param_transfer (param, transfer, name, error))
1340 : 0 : return FALSE;
1341 : :
1342 [ # # # # ]: 0 : if (scope && strcmp (scope, "call") == 0)
1343 : 0 : param->scope = GI_SCOPE_TYPE_CALL;
1344 [ # # # # ]: 0 : else if (scope && strcmp (scope, "async") == 0)
1345 : 0 : param->scope = GI_SCOPE_TYPE_ASYNC;
1346 [ # # # # ]: 0 : else if (scope && strcmp (scope, "notified") == 0)
1347 : 0 : param->scope = GI_SCOPE_TYPE_NOTIFIED;
1348 [ # # # # ]: 0 : else if (scope && strcmp (scope, "forever") == 0)
1349 : 0 : param->scope = GI_SCOPE_TYPE_FOREVER;
1350 : : else
1351 : 0 : param->scope = GI_SCOPE_TYPE_INVALID;
1352 : :
1353 [ # # ]: 0 : param->closure = closure ? atoi (closure) : -1;
1354 [ # # ]: 0 : param->destroy = destroy ? atoi (destroy) : -1;
1355 : :
1356 : 0 : ((GIIrNode *)param)->name = g_strdup (name);
1357 : :
1358 [ # # # # ]: 0 : switch (CURRENT_NODE (ctx)->type)
1359 : : {
1360 : 0 : case GI_IR_NODE_FUNCTION:
1361 : : case GI_IR_NODE_CALLBACK:
1362 : : {
1363 : : GIIrNodeFunction *func;
1364 : :
1365 : 0 : func = (GIIrNodeFunction *)CURRENT_NODE (ctx);
1366 : 0 : func->parameters = g_list_append (func->parameters, param);
1367 : : }
1368 : 0 : break;
1369 : 0 : case GI_IR_NODE_SIGNAL:
1370 : : {
1371 : : GIIrNodeSignal *signal;
1372 : :
1373 : 0 : signal = (GIIrNodeSignal *)CURRENT_NODE (ctx);
1374 : 0 : signal->parameters = g_list_append (signal->parameters, param);
1375 : : }
1376 : 0 : break;
1377 : 0 : case GI_IR_NODE_VFUNC:
1378 : : {
1379 : : GIIrNodeVFunc *vfunc;
1380 : :
1381 : 0 : vfunc = (GIIrNodeVFunc *)CURRENT_NODE (ctx);
1382 : 0 : vfunc->parameters = g_list_append (vfunc->parameters, param);
1383 : : }
1384 : 0 : break;
1385 : 0 : default:
1386 : : g_assert_not_reached ();
1387 : : }
1388 : :
1389 : 0 : return TRUE;
1390 : : }
1391 : :
1392 : : static gboolean
1393 : 0 : start_field (GMarkupParseContext *context,
1394 : : const char *element_name,
1395 : : const char **attribute_names,
1396 : : const char **attribute_values,
1397 : : ParseContext *ctx,
1398 : : GError **error)
1399 : : {
1400 : : const char *name;
1401 : : const char *readable;
1402 : : const char *writable;
1403 : : const char *bits;
1404 : : const char *branch;
1405 : : GIIrNodeField *field;
1406 : : ParseState target_state;
1407 : : gboolean introspectable;
1408 : : guint64 parsed_bits;
1409 : :
1410 [ # # # # : 0 : switch (ctx->state)
# # ]
1411 : : {
1412 : 0 : case STATE_CLASS:
1413 : 0 : target_state = STATE_CLASS_FIELD;
1414 : 0 : break;
1415 : 0 : case STATE_BOXED:
1416 : 0 : target_state = STATE_BOXED_FIELD;
1417 : 0 : break;
1418 : 0 : case STATE_STRUCT:
1419 : 0 : target_state = STATE_STRUCT_FIELD;
1420 : 0 : break;
1421 : 0 : case STATE_UNION:
1422 : 0 : target_state = STATE_UNION_FIELD;
1423 : 0 : break;
1424 : 0 : case STATE_INTERFACE:
1425 : 0 : target_state = STATE_INTERFACE_FIELD;
1426 : 0 : break;
1427 : 0 : default:
1428 : 0 : return FALSE;
1429 : : }
1430 : :
1431 [ # # ]: 0 : if (strcmp (element_name, "field") != 0)
1432 : 0 : return FALSE;
1433 : :
1434 : 0 : g_assert (ctx->state != STATE_PASSTHROUGH);
1435 : :
1436 : : /* We handle introspectability specially here; we replace with just gpointer
1437 : : * for the type.
1438 : : */
1439 : 0 : introspectable = introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state);
1440 : :
1441 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
1442 : 0 : readable = find_attribute ("readable", attribute_names, attribute_values);
1443 : 0 : writable = find_attribute ("writable", attribute_names, attribute_values);
1444 : 0 : bits = find_attribute ("bits", attribute_names, attribute_values);
1445 : 0 : branch = find_attribute ("branch", attribute_names, attribute_values);
1446 : :
1447 [ # # ]: 0 : if (name == NULL)
1448 : : {
1449 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
1450 : 0 : return FALSE;
1451 : : }
1452 : :
1453 : 0 : field = (GIIrNodeField *)gi_ir_node_new (GI_IR_NODE_FIELD,
1454 : : ctx->current_module);
1455 [ # # ]: 0 : if (introspectable)
1456 : : {
1457 : 0 : ctx->current_typed = (GIIrNode*) field;
1458 : : }
1459 : : else
1460 : : {
1461 : 0 : field->type = parse_type (ctx, "gpointer");
1462 : : }
1463 : :
1464 : 0 : ((GIIrNode *)field)->name = g_strdup (name);
1465 : : /* Fields are assumed to be read-only.
1466 : : * (see also girwriter.py and generate.c)
1467 : : */
1468 [ # # # # ]: 0 : field->readable = readable == NULL || strcmp (readable, "0") == 0;
1469 [ # # # # ]: 0 : field->writable = writable != NULL && strcmp (writable, "1") == 0;
1470 : :
1471 [ # # ]: 0 : if (bits == NULL)
1472 : 0 : field->bits = 0;
1473 [ # # ]: 0 : else if (g_ascii_string_to_unsigned (bits, 10, 0, G_MAXUINT, &parsed_bits, error))
1474 : 0 : field->bits = parsed_bits;
1475 : : else
1476 : : {
1477 : 0 : gi_ir_node_free ((GIIrNode *) field);
1478 : 0 : return FALSE;
1479 : : }
1480 : :
1481 [ # # # # : 0 : switch (CURRENT_NODE (ctx)->type)
# # ]
1482 : : {
1483 : 0 : case GI_IR_NODE_OBJECT:
1484 : : {
1485 : : GIIrNodeInterface *iface;
1486 : :
1487 : 0 : iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
1488 : 0 : iface->members = g_list_append (iface->members, field);
1489 : : }
1490 : 0 : break;
1491 : 0 : case GI_IR_NODE_INTERFACE:
1492 : : {
1493 : : GIIrNodeInterface *iface;
1494 : :
1495 : 0 : iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
1496 : 0 : iface->members = g_list_append (iface->members, field);
1497 : : }
1498 : 0 : break;
1499 : 0 : case GI_IR_NODE_BOXED:
1500 : : {
1501 : : GIIrNodeBoxed *boxed;
1502 : :
1503 : 0 : boxed = (GIIrNodeBoxed *)CURRENT_NODE (ctx);
1504 : 0 : boxed->members = g_list_append (boxed->members, field);
1505 : : }
1506 : 0 : break;
1507 : 0 : case GI_IR_NODE_STRUCT:
1508 : : {
1509 : : GIIrNodeStruct *struct_;
1510 : :
1511 : 0 : struct_ = (GIIrNodeStruct *)CURRENT_NODE (ctx);
1512 : 0 : struct_->members = g_list_append (struct_->members, field);
1513 : : }
1514 : 0 : break;
1515 : 0 : case GI_IR_NODE_UNION:
1516 : : {
1517 : : GIIrNodeUnion *union_;
1518 : :
1519 : 0 : union_ = (GIIrNodeUnion *)CURRENT_NODE (ctx);
1520 : 0 : union_->members = g_list_append (union_->members, field);
1521 [ # # ]: 0 : if (branch)
1522 : : {
1523 : : GIIrNodeConstant *constant;
1524 : :
1525 : 0 : constant = (GIIrNodeConstant *) gi_ir_node_new (GI_IR_NODE_CONSTANT,
1526 : : ctx->current_module);
1527 : 0 : ((GIIrNode *)constant)->name = g_strdup (name);
1528 : 0 : constant->value = g_strdup (branch);
1529 : 0 : constant->type = union_->discriminator_type;
1530 : 0 : constant->deprecated = FALSE;
1531 : :
1532 : 0 : union_->discriminators = g_list_append (union_->discriminators, constant);
1533 : : }
1534 : : }
1535 : 0 : break;
1536 : 0 : default:
1537 : : g_assert_not_reached ();
1538 : : }
1539 : :
1540 : 0 : return TRUE;
1541 : : }
1542 : :
1543 : : static gboolean
1544 : 0 : start_alias (GMarkupParseContext *context,
1545 : : const char *element_name,
1546 : : const char **attribute_names,
1547 : : const char **attribute_values,
1548 : : ParseContext *ctx,
1549 : : GError **error)
1550 : : {
1551 : : const char *name;
1552 : :
1553 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
1554 [ # # ]: 0 : if (name == NULL)
1555 : : {
1556 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
1557 : 0 : return FALSE;
1558 : : }
1559 : :
1560 : 0 : ctx->current_alias = g_strdup (name);
1561 : 0 : state_switch (ctx, STATE_ALIAS);
1562 : :
1563 : 0 : return TRUE;
1564 : : }
1565 : :
1566 : : static gboolean
1567 : 0 : start_enum (GMarkupParseContext *context,
1568 : : const char *element_name,
1569 : : const char **attribute_names,
1570 : : const char **attribute_values,
1571 : : ParseContext *ctx,
1572 : : GError **error)
1573 : : {
1574 : : const char *name;
1575 : : const char *typename;
1576 : : const char *typeinit;
1577 : : const char *deprecated;
1578 : : const char *error_domain;
1579 : : GIIrNodeEnum *enum_;
1580 : :
1581 [ # # # # ]: 0 : if (!((strcmp (element_name, "enumeration") == 0 && ctx->state == STATE_NAMESPACE) ||
1582 [ # # # # ]: 0 : (strcmp (element_name, "bitfield") == 0 && ctx->state == STATE_NAMESPACE)))
1583 : 0 : return FALSE;
1584 : :
1585 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_ENUM))
1586 : 0 : return TRUE;
1587 : :
1588 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
1589 : 0 : typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1590 : 0 : typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1591 : 0 : error_domain = find_attribute ("glib:error-domain", attribute_names, attribute_values);
1592 : 0 : deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1593 : :
1594 [ # # ]: 0 : if (name == NULL)
1595 : : {
1596 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
1597 : 0 : return FALSE;
1598 : : }
1599 : :
1600 [ # # ]: 0 : if (strcmp (element_name, "enumeration") == 0)
1601 : 0 : enum_ = (GIIrNodeEnum *) gi_ir_node_new (GI_IR_NODE_ENUM,
1602 : : ctx->current_module);
1603 : : else
1604 : 0 : enum_ = (GIIrNodeEnum *) gi_ir_node_new (GI_IR_NODE_FLAGS,
1605 : : ctx->current_module);
1606 : 0 : ((GIIrNode *)enum_)->name = g_strdup (name);
1607 : 0 : enum_->gtype_name = g_strdup (typename);
1608 : 0 : enum_->gtype_init = g_strdup (typeinit);
1609 : 0 : enum_->error_domain = g_strdup (error_domain);
1610 : :
1611 [ # # ]: 0 : if (deprecated)
1612 : 0 : enum_->deprecated = TRUE;
1613 : : else
1614 : 0 : enum_->deprecated = FALSE;
1615 : :
1616 : 0 : push_node (ctx, (GIIrNode *) enum_);
1617 : 0 : ctx->current_module->entries =
1618 : 0 : g_list_append (ctx->current_module->entries, enum_);
1619 : :
1620 : 0 : return TRUE;
1621 : : }
1622 : :
1623 : : static gboolean
1624 : 0 : start_property (GMarkupParseContext *context,
1625 : : const char *element_name,
1626 : : const char **attribute_names,
1627 : : const char **attribute_values,
1628 : : ParseContext *ctx,
1629 : : GError **error)
1630 : : {
1631 : : ParseState target_state;
1632 : : const char *name;
1633 : : const char *readable;
1634 : : const char *writable;
1635 : : const char *construct;
1636 : : const char *construct_only;
1637 : : const char *transfer;
1638 : : const char *setter;
1639 : : const char *getter;
1640 : : GIIrNodeProperty *property;
1641 : : GIIrNodeInterface *iface;
1642 : :
1643 [ # # ]: 0 : if (!(strcmp (element_name, "property") == 0 &&
1644 [ # # ]: 0 : (ctx->state == STATE_CLASS ||
1645 [ # # ]: 0 : ctx->state == STATE_INTERFACE)))
1646 : 0 : return FALSE;
1647 : :
1648 [ # # ]: 0 : if (ctx->state == STATE_CLASS)
1649 : 0 : target_state = STATE_CLASS_PROPERTY;
1650 [ # # ]: 0 : else if (ctx->state == STATE_INTERFACE)
1651 : 0 : target_state = STATE_INTERFACE_PROPERTY;
1652 : : else
1653 : : g_assert_not_reached ();
1654 : :
1655 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state))
1656 : 0 : return TRUE;
1657 : :
1658 : :
1659 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
1660 : 0 : readable = find_attribute ("readable", attribute_names, attribute_values);
1661 : 0 : writable = find_attribute ("writable", attribute_names, attribute_values);
1662 : 0 : construct = find_attribute ("construct", attribute_names, attribute_values);
1663 : 0 : construct_only = find_attribute ("construct-only", attribute_names, attribute_values);
1664 : 0 : transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
1665 : 0 : setter = find_attribute ("setter", attribute_names, attribute_values);
1666 : 0 : getter = find_attribute ("getter", attribute_names, attribute_values);
1667 : :
1668 [ # # ]: 0 : if (name == NULL)
1669 : : {
1670 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
1671 : 0 : return FALSE;
1672 : : }
1673 : :
1674 : 0 : property = (GIIrNodeProperty *) gi_ir_node_new (GI_IR_NODE_PROPERTY,
1675 : : ctx->current_module);
1676 : 0 : ctx->current_typed = (GIIrNode*) property;
1677 : :
1678 : 0 : ((GIIrNode *)property)->name = g_strdup (name);
1679 : :
1680 : : /* Assume properties are readable */
1681 [ # # # # ]: 0 : if (readable == NULL || strcmp (readable, "1") == 0)
1682 : 0 : property->readable = TRUE;
1683 : : else
1684 : 0 : property->readable = FALSE;
1685 [ # # # # ]: 0 : if (writable && strcmp (writable, "1") == 0)
1686 : 0 : property->writable = TRUE;
1687 : : else
1688 : 0 : property->writable = FALSE;
1689 [ # # # # ]: 0 : if (construct && strcmp (construct, "1") == 0)
1690 : 0 : property->construct = TRUE;
1691 : : else
1692 : 0 : property->construct = FALSE;
1693 [ # # # # ]: 0 : if (construct_only && strcmp (construct_only, "1") == 0)
1694 : 0 : property->construct_only = TRUE;
1695 : : else
1696 : 0 : property->construct_only = FALSE;
1697 : :
1698 : 0 : property->setter = g_strdup (setter);
1699 : 0 : property->getter = g_strdup (getter);
1700 : :
1701 : 0 : parse_property_transfer (property, transfer, ctx);
1702 : :
1703 : 0 : iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
1704 : 0 : iface->members = g_list_append (iface->members, property);
1705 : :
1706 : 0 : return TRUE;
1707 : : }
1708 : :
1709 : : static int64_t
1710 : 0 : parse_value (const char *str)
1711 : : {
1712 : : char *shift_op;
1713 : :
1714 : : /* FIXME just a quick hack */
1715 : 0 : shift_op = strstr (str, "<<");
1716 : :
1717 [ # # ]: 0 : if (shift_op)
1718 : : {
1719 : : int64_t base, shift;
1720 : :
1721 : 0 : base = g_ascii_strtoll (str, NULL, 10);
1722 : 0 : shift = g_ascii_strtoll (shift_op + 3, NULL, 10);
1723 : :
1724 : 0 : return base << shift;
1725 : : }
1726 : : else
1727 : 0 : return g_ascii_strtoll (str, NULL, 10);
1728 : :
1729 : : return 0;
1730 : : }
1731 : :
1732 : : static gboolean
1733 : 0 : start_member (GMarkupParseContext *context,
1734 : : const char *element_name,
1735 : : const char **attribute_names,
1736 : : const char **attribute_values,
1737 : : ParseContext *ctx,
1738 : : GError **error)
1739 : : {
1740 : : const char *name;
1741 : : const char *value;
1742 : : const char *deprecated;
1743 : : const char *c_identifier;
1744 : : GIIrNodeEnum *enum_;
1745 : : GIIrNodeValue *value_;
1746 : :
1747 [ # # ]: 0 : if (!(strcmp (element_name, "member") == 0 &&
1748 [ # # ]: 0 : ctx->state == STATE_ENUM))
1749 : 0 : return FALSE;
1750 : :
1751 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
1752 : 0 : value = find_attribute ("value", attribute_names, attribute_values);
1753 : 0 : deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1754 : 0 : c_identifier = find_attribute ("c:identifier", attribute_names, attribute_values);
1755 : :
1756 [ # # ]: 0 : if (name == NULL)
1757 : : {
1758 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
1759 : 0 : return FALSE;
1760 : : }
1761 : :
1762 : 0 : value_ = (GIIrNodeValue *) gi_ir_node_new (GI_IR_NODE_VALUE,
1763 : : ctx->current_module);
1764 : :
1765 : 0 : ((GIIrNode *)value_)->name = g_strdup (name);
1766 : :
1767 : 0 : value_->value = parse_value (value);
1768 : :
1769 [ # # ]: 0 : if (deprecated)
1770 : 0 : value_->deprecated = TRUE;
1771 : : else
1772 : 0 : value_->deprecated = FALSE;
1773 : :
1774 : 0 : g_hash_table_insert (((GIIrNode *)value_)->attributes,
1775 : 0 : g_strdup ("c:identifier"),
1776 : 0 : g_strdup (c_identifier));
1777 : :
1778 : 0 : enum_ = (GIIrNodeEnum *)CURRENT_NODE (ctx);
1779 : 0 : enum_->values = g_list_append (enum_->values, value_);
1780 : :
1781 : 0 : return TRUE;
1782 : : }
1783 : :
1784 : : static gboolean
1785 : 0 : start_constant (GMarkupParseContext *context,
1786 : : const char *element_name,
1787 : : const char **attribute_names,
1788 : : const char **attribute_values,
1789 : : ParseContext *ctx,
1790 : : GError **error)
1791 : : {
1792 : : ParseState prev_state;
1793 : : ParseState target_state;
1794 : : const char *name;
1795 : : const char *value;
1796 : : const char *deprecated;
1797 : : GIIrNodeConstant *constant;
1798 : :
1799 [ # # ]: 0 : if (!(strcmp (element_name, "constant") == 0 &&
1800 [ # # ]: 0 : (ctx->state == STATE_NAMESPACE ||
1801 [ # # ]: 0 : ctx->state == STATE_CLASS ||
1802 [ # # ]: 0 : ctx->state == STATE_INTERFACE)))
1803 : 0 : return FALSE;
1804 : :
1805 [ # # # # ]: 0 : switch (ctx->state)
1806 : : {
1807 : 0 : case STATE_NAMESPACE:
1808 : 0 : target_state = STATE_NAMESPACE_CONSTANT;
1809 : 0 : break;
1810 : 0 : case STATE_CLASS:
1811 : 0 : target_state = STATE_CLASS_CONSTANT;
1812 : 0 : break;
1813 : 0 : case STATE_INTERFACE:
1814 : 0 : target_state = STATE_INTERFACE_CONSTANT;
1815 : 0 : break;
1816 : 0 : default:
1817 : : g_assert_not_reached ();
1818 : : }
1819 : :
1820 : 0 : prev_state = ctx->state;
1821 : :
1822 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state))
1823 : 0 : return TRUE;
1824 : :
1825 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
1826 : 0 : value = find_attribute ("value", attribute_names, attribute_values);
1827 : 0 : deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1828 : :
1829 [ # # ]: 0 : if (name == NULL)
1830 : : {
1831 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
1832 : 0 : return FALSE;
1833 : : }
1834 [ # # ]: 0 : else if (value == NULL)
1835 : : {
1836 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "value");
1837 : 0 : return FALSE;
1838 : : }
1839 : :
1840 : 0 : constant = (GIIrNodeConstant *) gi_ir_node_new (GI_IR_NODE_CONSTANT,
1841 : : ctx->current_module);
1842 : :
1843 : 0 : ((GIIrNode *)constant)->name = g_strdup (name);
1844 : 0 : constant->value = g_strdup (value);
1845 : :
1846 : 0 : ctx->current_typed = (GIIrNode*) constant;
1847 : :
1848 [ # # ]: 0 : if (deprecated)
1849 : 0 : constant->deprecated = TRUE;
1850 : : else
1851 : 0 : constant->deprecated = FALSE;
1852 : :
1853 [ # # ]: 0 : if (prev_state == STATE_NAMESPACE)
1854 : : {
1855 : 0 : push_node (ctx, (GIIrNode *) constant);
1856 : 0 : ctx->current_module->entries =
1857 : 0 : g_list_append (ctx->current_module->entries, constant);
1858 : : }
1859 : : else
1860 : : {
1861 : : GIIrNodeInterface *iface;
1862 : :
1863 : 0 : iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
1864 : 0 : iface->members = g_list_append (iface->members, constant);
1865 : : }
1866 : :
1867 : 0 : return TRUE;
1868 : : }
1869 : :
1870 : : static gboolean
1871 : 0 : start_interface (GMarkupParseContext *context,
1872 : : const char *element_name,
1873 : : const char **attribute_names,
1874 : : const char **attribute_values,
1875 : : ParseContext *ctx,
1876 : : GError **error)
1877 : : {
1878 : : const char *name;
1879 : : const char *typename;
1880 : : const char *typeinit;
1881 : : const char *deprecated;
1882 : : const char *glib_type_struct;
1883 : : GIIrNodeInterface *iface;
1884 : :
1885 [ # # ]: 0 : if (!(strcmp (element_name, "interface") == 0 &&
1886 [ # # ]: 0 : ctx->state == STATE_NAMESPACE))
1887 : 0 : return FALSE;
1888 : :
1889 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_INTERFACE))
1890 : 0 : return TRUE;
1891 : :
1892 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
1893 : 0 : typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1894 : 0 : typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1895 : 0 : glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
1896 : 0 : deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1897 : :
1898 [ # # ]: 0 : if (name == NULL)
1899 : : {
1900 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
1901 : 0 : return FALSE;
1902 : : }
1903 [ # # ]: 0 : else if (typename == NULL)
1904 : : {
1905 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
1906 : 0 : return FALSE;
1907 : : }
1908 [ # # ]: 0 : else if (typeinit == NULL)
1909 : : {
1910 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
1911 : 0 : return FALSE;
1912 : : }
1913 : :
1914 : 0 : iface = (GIIrNodeInterface *) gi_ir_node_new (GI_IR_NODE_INTERFACE,
1915 : : ctx->current_module);
1916 : 0 : ((GIIrNode *)iface)->name = g_strdup (name);
1917 : 0 : iface->gtype_name = g_strdup (typename);
1918 : 0 : iface->gtype_init = g_strdup (typeinit);
1919 : 0 : iface->glib_type_struct = g_strdup (glib_type_struct);
1920 [ # # ]: 0 : if (deprecated)
1921 : 0 : iface->deprecated = TRUE;
1922 : : else
1923 : 0 : iface->deprecated = FALSE;
1924 : :
1925 : 0 : push_node (ctx, (GIIrNode *) iface);
1926 : 0 : ctx->current_module->entries =
1927 : 0 : g_list_append (ctx->current_module->entries, iface);
1928 : :
1929 : 0 : return TRUE;
1930 : : }
1931 : :
1932 : : static gboolean
1933 : 0 : start_class (GMarkupParseContext *context,
1934 : : const char *element_name,
1935 : : const char **attribute_names,
1936 : : const char **attribute_values,
1937 : : ParseContext *ctx,
1938 : : GError **error)
1939 : : {
1940 : : const char *name;
1941 : : const char *parent;
1942 : : const char *glib_type_struct;
1943 : : const char *typename;
1944 : : const char *typeinit;
1945 : : const char *deprecated;
1946 : : const char *abstract;
1947 : : const char *fundamental;
1948 : : const char *final;
1949 : : const char *ref_func;
1950 : : const char *unref_func;
1951 : : const char *set_value_func;
1952 : : const char *get_value_func;
1953 : : GIIrNodeInterface *iface;
1954 : :
1955 [ # # ]: 0 : if (!(strcmp (element_name, "class") == 0 &&
1956 [ # # ]: 0 : ctx->state == STATE_NAMESPACE))
1957 : 0 : return FALSE;
1958 : :
1959 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_CLASS))
1960 : 0 : return TRUE;
1961 : :
1962 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
1963 : 0 : parent = find_attribute ("parent", attribute_names, attribute_values);
1964 : 0 : glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
1965 : 0 : typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1966 : 0 : typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1967 : 0 : deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1968 : 0 : abstract = find_attribute ("abstract", attribute_names, attribute_values);
1969 : 0 : final = find_attribute ("final", attribute_names, attribute_values);
1970 : 0 : fundamental = find_attribute ("glib:fundamental", attribute_names, attribute_values);
1971 : 0 : ref_func = find_attribute ("glib:ref-func", attribute_names, attribute_values);
1972 : 0 : unref_func = find_attribute ("glib:unref-func", attribute_names, attribute_values);
1973 : 0 : set_value_func = find_attribute ("glib:set-value-func", attribute_names, attribute_values);
1974 : 0 : get_value_func = find_attribute ("glib:get-value-func", attribute_names, attribute_values);
1975 : :
1976 [ # # ]: 0 : if (name == NULL)
1977 : : {
1978 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
1979 : 0 : return FALSE;
1980 : : }
1981 [ # # ]: 0 : else if (typename == NULL)
1982 : : {
1983 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
1984 : 0 : return FALSE;
1985 : : }
1986 [ # # # # ]: 0 : else if (typeinit == NULL && strcmp (typename, "GObject"))
1987 : : {
1988 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
1989 : 0 : return FALSE;
1990 : : }
1991 : :
1992 : 0 : iface = (GIIrNodeInterface *) gi_ir_node_new (GI_IR_NODE_OBJECT,
1993 : : ctx->current_module);
1994 : 0 : ((GIIrNode *)iface)->name = g_strdup (name);
1995 : 0 : iface->gtype_name = g_strdup (typename);
1996 : 0 : iface->gtype_init = g_strdup (typeinit);
1997 : 0 : iface->parent = g_strdup (parent);
1998 : 0 : iface->glib_type_struct = g_strdup (glib_type_struct);
1999 [ # # ]: 0 : if (deprecated)
2000 : 0 : iface->deprecated = TRUE;
2001 : : else
2002 : 0 : iface->deprecated = FALSE;
2003 : :
2004 [ # # # # ]: 0 : iface->abstract = abstract && strcmp (abstract, "1") == 0;
2005 [ # # # # ]: 0 : iface->final_ = final && strcmp (final, "1") == 0;
2006 : :
2007 [ # # ]: 0 : if (fundamental)
2008 : 0 : iface->fundamental = TRUE;
2009 [ # # ]: 0 : if (ref_func)
2010 : 0 : iface->ref_func = g_strdup (ref_func);
2011 [ # # ]: 0 : if (unref_func)
2012 : 0 : iface->unref_func = g_strdup (unref_func);
2013 [ # # ]: 0 : if (set_value_func)
2014 : 0 : iface->set_value_func = g_strdup (set_value_func);
2015 [ # # ]: 0 : if (get_value_func)
2016 : 0 : iface->get_value_func = g_strdup (get_value_func);
2017 : :
2018 : 0 : push_node (ctx, (GIIrNode *) iface);
2019 : 0 : ctx->current_module->entries =
2020 : 0 : g_list_append (ctx->current_module->entries, iface);
2021 : :
2022 : 0 : return TRUE;
2023 : : }
2024 : :
2025 : : static gboolean
2026 : 0 : start_type (GMarkupParseContext *context,
2027 : : const char *element_name,
2028 : : const char **attribute_names,
2029 : : const char **attribute_values,
2030 : : ParseContext *ctx,
2031 : : GError **error)
2032 : : {
2033 : : const char *name;
2034 : : const char *ctype;
2035 : 0 : gboolean in_alias = FALSE;
2036 : : gboolean is_array;
2037 : : gboolean is_varargs;
2038 : : GIIrNodeType *typenode;
2039 : :
2040 : 0 : is_array = strcmp (element_name, "array") == 0;
2041 : 0 : is_varargs = strcmp (element_name, "varargs") == 0;
2042 : :
2043 [ # # # # : 0 : if (!(is_array || is_varargs || (strcmp (element_name, "type") == 0)))
# # ]
2044 : 0 : return FALSE;
2045 : :
2046 [ # # ]: 0 : if (ctx->state == STATE_TYPE)
2047 : : {
2048 : 0 : ctx->type_depth++;
2049 : 0 : ctx->type_stack = g_list_prepend (ctx->type_stack, ctx->type_parameters);
2050 : 0 : ctx->type_parameters = NULL;
2051 : : }
2052 [ # # ]: 0 : else if (ctx->state == STATE_FUNCTION_PARAMETER ||
2053 [ # # ]: 0 : ctx->state == STATE_FUNCTION_RETURN ||
2054 [ # # ]: 0 : ctx->state == STATE_STRUCT_FIELD ||
2055 [ # # ]: 0 : ctx->state == STATE_UNION_FIELD ||
2056 [ # # ]: 0 : ctx->state == STATE_CLASS_PROPERTY ||
2057 [ # # ]: 0 : ctx->state == STATE_CLASS_FIELD ||
2058 [ # # ]: 0 : ctx->state == STATE_INTERFACE_FIELD ||
2059 [ # # ]: 0 : ctx->state == STATE_INTERFACE_PROPERTY ||
2060 [ # # ]: 0 : ctx->state == STATE_BOXED_FIELD ||
2061 [ # # ]: 0 : ctx->state == STATE_NAMESPACE_CONSTANT ||
2062 [ # # ]: 0 : ctx->state == STATE_CLASS_CONSTANT ||
2063 [ # # ]: 0 : ctx->state == STATE_INTERFACE_CONSTANT ||
2064 [ # # ]: 0 : ctx->state == STATE_ALIAS
2065 : : )
2066 : : {
2067 [ # # ]: 0 : if (ctx->state == STATE_ALIAS)
2068 : 0 : in_alias = TRUE;
2069 : 0 : state_switch (ctx, STATE_TYPE);
2070 : 0 : ctx->type_depth = 1;
2071 : 0 : ctx->type_stack = NULL;
2072 : 0 : ctx->type_parameters = NULL;
2073 : : }
2074 : :
2075 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
2076 : :
2077 [ # # # # ]: 0 : if (in_alias && ctx->current_alias)
2078 : : {
2079 : : char *key;
2080 : : char *value;
2081 : :
2082 [ # # ]: 0 : if (name == NULL)
2083 : : {
2084 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
2085 : 0 : return FALSE;
2086 : : }
2087 : :
2088 : 0 : key = g_strdup_printf ("%s.%s", ctx->namespace, ctx->current_alias);
2089 [ # # ]: 0 : if (!strchr (name, '.'))
2090 : : {
2091 : 0 : const BasicTypeInfo *basic = parse_basic (name);
2092 [ # # ]: 0 : if (!basic)
2093 : : {
2094 : : /* For non-basic types, re-qualify the interface */
2095 : 0 : value = g_strdup_printf ("%s.%s", ctx->namespace, name);
2096 : : }
2097 : : else
2098 : : {
2099 : 0 : value = g_strdup (name);
2100 : : }
2101 : : }
2102 : : else
2103 : 0 : value = g_strdup (name);
2104 : :
2105 : 0 : g_hash_table_replace (ctx->aliases, key, value);
2106 : :
2107 : 0 : return TRUE;
2108 : : }
2109 [ # # # # ]: 0 : else if (!ctx->current_module || in_alias)
2110 : 0 : return TRUE;
2111 : :
2112 [ # # ]: 0 : if (!ctx->current_typed)
2113 : : {
2114 : 0 : g_set_error (error,
2115 : : G_MARKUP_ERROR,
2116 : : G_MARKUP_ERROR_INVALID_CONTENT,
2117 : : "The element <type> is invalid here");
2118 : 0 : return FALSE;
2119 : : }
2120 : :
2121 [ # # ]: 0 : if (is_varargs)
2122 : 0 : return TRUE;
2123 : :
2124 [ # # ]: 0 : if (is_array)
2125 : : {
2126 : : const char *zero;
2127 : : const char *len;
2128 : : const char *size;
2129 : :
2130 : 0 : typenode = (GIIrNodeType *)gi_ir_node_new (GI_IR_NODE_TYPE,
2131 : : ctx->current_module);
2132 : :
2133 : 0 : typenode->tag = GI_TYPE_TAG_ARRAY;
2134 : 0 : typenode->is_pointer = TRUE;
2135 : 0 : typenode->is_array = TRUE;
2136 : :
2137 [ # # # # ]: 0 : if (name && strcmp (name, "GLib.Array") == 0) {
2138 : 0 : typenode->array_type = GI_ARRAY_TYPE_ARRAY;
2139 [ # # # # ]: 0 : } else if (name && strcmp (name, "GLib.ByteArray") == 0) {
2140 : 0 : typenode->array_type = GI_ARRAY_TYPE_BYTE_ARRAY;
2141 [ # # # # ]: 0 : } else if (name && strcmp (name, "GLib.PtrArray") == 0) {
2142 : 0 : typenode->array_type = GI_ARRAY_TYPE_PTR_ARRAY;
2143 : : } else {
2144 : 0 : typenode->array_type = GI_ARRAY_TYPE_C;
2145 : : }
2146 : :
2147 [ # # ]: 0 : if (typenode->array_type == GI_ARRAY_TYPE_C) {
2148 : : guint64 parsed_uint;
2149 : :
2150 : 0 : zero = find_attribute ("zero-terminated", attribute_names, attribute_values);
2151 : 0 : len = find_attribute ("length", attribute_names, attribute_values);
2152 : 0 : size = find_attribute ("fixed-size", attribute_names, attribute_values);
2153 : :
2154 : 0 : typenode->has_length = len != NULL;
2155 [ # # ]: 0 : if (!typenode->has_length)
2156 : 0 : typenode->length = -1;
2157 [ # # ]: 0 : else if (g_ascii_string_to_unsigned (len, 10, 0, G_MAXUINT, &parsed_uint, error))
2158 : 0 : typenode->length = parsed_uint;
2159 : : else
2160 : : {
2161 : 0 : gi_ir_node_free ((GIIrNode *) typenode);
2162 : 0 : return FALSE;
2163 : : }
2164 : :
2165 : 0 : typenode->has_size = size != NULL;
2166 [ # # ]: 0 : if (!typenode->has_size)
2167 : 0 : typenode->size = -1;
2168 [ # # ]: 0 : else if (g_ascii_string_to_unsigned (size, 10, 0, G_MAXSIZE, &parsed_uint, error))
2169 : 0 : typenode->size = parsed_uint;
2170 : : else
2171 : : {
2172 : 0 : gi_ir_node_free ((GIIrNode *) typenode);
2173 : 0 : return FALSE;
2174 : : }
2175 : :
2176 [ # # ]: 0 : if (zero)
2177 : 0 : typenode->zero_terminated = strcmp(zero, "1") == 0;
2178 : : else
2179 : : /* If neither zero-terminated nor length nor fixed-size is given, assume zero-terminated. */
2180 [ # # # # ]: 0 : typenode->zero_terminated = !(typenode->has_length || typenode->has_size);
2181 : :
2182 [ # # # # ]: 0 : if (typenode->has_size && ctx->current_typed->type == GI_IR_NODE_FIELD)
2183 : 0 : typenode->is_pointer = FALSE;
2184 : : } else {
2185 : 0 : typenode->zero_terminated = FALSE;
2186 : 0 : typenode->has_length = FALSE;
2187 : 0 : typenode->length = -1;
2188 : 0 : typenode->has_size = FALSE;
2189 : 0 : typenode->size = -1;
2190 : : }
2191 : : }
2192 : : else
2193 : : {
2194 : : int pointer_depth;
2195 : :
2196 [ # # ]: 0 : if (name == NULL)
2197 : : {
2198 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
2199 : 0 : return FALSE;
2200 : : }
2201 : :
2202 : 0 : pointer_depth = 0;
2203 : 0 : ctype = find_attribute ("c:type", attribute_names, attribute_values);
2204 [ # # ]: 0 : if (ctype != NULL)
2205 : : {
2206 : 0 : const char *cp = ctype + strlen(ctype) - 1;
2207 [ # # # # ]: 0 : while (cp > ctype && *cp-- == '*')
2208 : 0 : pointer_depth++;
2209 : :
2210 [ # # # # : 0 : if (g_str_has_prefix (ctype, "gpointer")
# # # # ]
2211 [ # # # # : 0 : || g_str_has_prefix (ctype, "gconstpointer"))
# # # # ]
2212 : 0 : pointer_depth++;
2213 : : }
2214 : :
2215 [ # # ]: 0 : if (ctx->current_typed->type == GI_IR_NODE_PARAM &&
2216 [ # # # # ]: 0 : ((GIIrNodeParam *)ctx->current_typed)->out &&
2217 : : pointer_depth > 0)
2218 : 0 : pointer_depth--;
2219 : :
2220 : 0 : typenode = parse_type (ctx, name);
2221 : :
2222 : : /* A "pointer" structure is one where the c:type is a typedef that
2223 : : * to a pointer to a structure; we used to call them "disguised"
2224 : : * structures as well.
2225 : : */
2226 [ # # ]: 0 : if (typenode->tag == GI_TYPE_TAG_INTERFACE)
2227 : : {
2228 : 0 : gboolean is_pointer = FALSE;
2229 : 0 : gboolean is_disguised = FALSE;
2230 : :
2231 : 0 : is_pointer_or_disguised_structure (ctx, typenode->giinterface,
2232 : : &is_pointer,
2233 : : &is_disguised);
2234 : :
2235 [ # # # # ]: 0 : if (is_pointer || is_disguised)
2236 : 0 : pointer_depth++;
2237 : : }
2238 : :
2239 [ # # ]: 0 : if (pointer_depth > 0)
2240 : 0 : typenode->is_pointer = TRUE;
2241 : : }
2242 : :
2243 : 0 : ctx->type_parameters = g_list_append (ctx->type_parameters, typenode);
2244 : :
2245 : 0 : return TRUE;
2246 : : }
2247 : :
2248 : : static void
2249 : 0 : end_type_top (ParseContext *ctx)
2250 : : {
2251 : : GIIrNodeType *typenode;
2252 : :
2253 [ # # ]: 0 : if (!ctx->type_parameters)
2254 : 0 : goto out;
2255 : :
2256 : 0 : typenode = (GIIrNodeType*)ctx->type_parameters->data;
2257 : :
2258 : : /* Default to pointer for unspecified containers */
2259 [ # # ]: 0 : if (typenode->tag == GI_TYPE_TAG_ARRAY ||
2260 [ # # ]: 0 : typenode->tag == GI_TYPE_TAG_GLIST ||
2261 [ # # ]: 0 : typenode->tag == GI_TYPE_TAG_GSLIST)
2262 : : {
2263 [ # # ]: 0 : if (typenode->parameter_type1 == NULL)
2264 : 0 : typenode->parameter_type1 = parse_type (ctx, "gpointer");
2265 : : }
2266 [ # # ]: 0 : else if (typenode->tag == GI_TYPE_TAG_GHASH)
2267 : : {
2268 [ # # ]: 0 : if (typenode->parameter_type1 == NULL)
2269 : : {
2270 : 0 : typenode->parameter_type1 = parse_type (ctx, "gpointer");
2271 : 0 : typenode->parameter_type2 = parse_type (ctx, "gpointer");
2272 : : }
2273 : : }
2274 : :
2275 [ # # # # : 0 : switch (ctx->current_typed->type)
# ]
2276 : : {
2277 : 0 : case GI_IR_NODE_PARAM:
2278 : : {
2279 : 0 : GIIrNodeParam *param = (GIIrNodeParam *)ctx->current_typed;
2280 : 0 : param->type = typenode;
2281 : : }
2282 : 0 : break;
2283 : 0 : case GI_IR_NODE_FIELD:
2284 : : {
2285 : 0 : GIIrNodeField *field = (GIIrNodeField *)ctx->current_typed;
2286 : 0 : field->type = typenode;
2287 : : }
2288 : 0 : break;
2289 : 0 : case GI_IR_NODE_PROPERTY:
2290 : : {
2291 : 0 : GIIrNodeProperty *property = (GIIrNodeProperty *) ctx->current_typed;
2292 : 0 : property->type = typenode;
2293 : : }
2294 : 0 : break;
2295 : 0 : case GI_IR_NODE_CONSTANT:
2296 : : {
2297 : 0 : GIIrNodeConstant *constant = (GIIrNodeConstant *)ctx->current_typed;
2298 : 0 : constant->type = typenode;
2299 : : }
2300 : 0 : break;
2301 : 0 : default:
2302 : 0 : g_printerr("current node is %d\n", CURRENT_NODE (ctx)->type);
2303 : : g_assert_not_reached ();
2304 : : }
2305 : 0 : g_list_free (ctx->type_parameters);
2306 : :
2307 : 0 : out:
2308 : 0 : ctx->type_depth = 0;
2309 : 0 : ctx->type_parameters = NULL;
2310 : 0 : ctx->current_typed = NULL;
2311 : 0 : }
2312 : :
2313 : : static void
2314 : 0 : end_type_recurse (ParseContext *ctx)
2315 : : {
2316 : : GIIrNodeType *parent;
2317 : 0 : GIIrNodeType *param = NULL;
2318 : :
2319 : 0 : parent = (GIIrNodeType *) ((GList*)ctx->type_stack->data)->data;
2320 [ # # ]: 0 : if (ctx->type_parameters)
2321 : 0 : param = (GIIrNodeType *) ctx->type_parameters->data;
2322 : :
2323 [ # # ]: 0 : if (parent->tag == GI_TYPE_TAG_ARRAY ||
2324 [ # # ]: 0 : parent->tag == GI_TYPE_TAG_GLIST ||
2325 [ # # ]: 0 : parent->tag == GI_TYPE_TAG_GSLIST)
2326 : : {
2327 : 0 : g_assert (param != NULL);
2328 : :
2329 [ # # ]: 0 : if (parent->parameter_type1 == NULL)
2330 : 0 : parent->parameter_type1 = param;
2331 : : else
2332 : : g_assert_not_reached ();
2333 : : }
2334 [ # # ]: 0 : else if (parent->tag == GI_TYPE_TAG_GHASH)
2335 : : {
2336 : 0 : g_assert (param != NULL);
2337 : :
2338 [ # # ]: 0 : if (parent->parameter_type1 == NULL)
2339 : 0 : parent->parameter_type1 = param;
2340 [ # # ]: 0 : else if (parent->parameter_type2 == NULL)
2341 : 0 : parent->parameter_type2 = param;
2342 : : else
2343 : : g_assert_not_reached ();
2344 : : }
2345 : 0 : g_list_free (ctx->type_parameters);
2346 : 0 : ctx->type_parameters = (GList *)ctx->type_stack->data;
2347 : 0 : ctx->type_stack = g_list_delete_link (ctx->type_stack, ctx->type_stack);
2348 : 0 : }
2349 : :
2350 : : static void
2351 : 0 : end_type (ParseContext *ctx)
2352 : : {
2353 [ # # ]: 0 : if (ctx->type_depth == 1)
2354 : : {
2355 : 0 : end_type_top (ctx);
2356 : 0 : state_switch (ctx, ctx->prev_state);
2357 : : }
2358 : : else
2359 : : {
2360 : 0 : end_type_recurse (ctx);
2361 : 0 : ctx->type_depth--;
2362 : : }
2363 : 0 : }
2364 : :
2365 : : static gboolean
2366 : 0 : start_attribute (GMarkupParseContext *context,
2367 : : const char *element_name,
2368 : : const char **attribute_names,
2369 : : const char **attribute_values,
2370 : : ParseContext *ctx,
2371 : : GError **error)
2372 : : {
2373 : : const char *name;
2374 : : const char *value;
2375 : : GIIrNode *curnode;
2376 : :
2377 [ # # # # ]: 0 : if (strcmp (element_name, "attribute") != 0 || ctx->node_stack == NULL)
2378 : 0 : return FALSE;
2379 : :
2380 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
2381 : 0 : value = find_attribute ("value", attribute_names, attribute_values);
2382 : :
2383 [ # # ]: 0 : if (name == NULL)
2384 : : {
2385 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
2386 : 0 : return FALSE;
2387 : : }
2388 [ # # ]: 0 : if (value == NULL)
2389 : : {
2390 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "value");
2391 : 0 : return FALSE;
2392 : : }
2393 : :
2394 : 0 : state_switch (ctx, STATE_ATTRIBUTE);
2395 : :
2396 : 0 : curnode = CURRENT_NODE (ctx);
2397 : :
2398 [ # # # # ]: 0 : if (ctx->current_typed && ctx->current_typed->type == GI_IR_NODE_PARAM)
2399 : : {
2400 : 0 : g_hash_table_insert (ctx->current_typed->attributes, g_strdup (name), g_strdup (value));
2401 : : }
2402 : : else
2403 : : {
2404 : 0 : g_hash_table_insert (curnode->attributes, g_strdup (name), g_strdup (value));
2405 : : }
2406 : :
2407 : 0 : return TRUE;
2408 : : }
2409 : :
2410 : : static gboolean
2411 : 0 : start_return_value (GMarkupParseContext *context,
2412 : : const char *element_name,
2413 : : const char **attribute_names,
2414 : : const char **attribute_values,
2415 : : ParseContext *ctx,
2416 : : GError **error)
2417 : : {
2418 : : GIIrNodeParam *param;
2419 : : const char *transfer;
2420 : : const char *skip;
2421 : : const char *nullable;
2422 : :
2423 [ # # ]: 0 : if (!(strcmp (element_name, "return-value") == 0 &&
2424 [ # # ]: 0 : ctx->state == STATE_FUNCTION))
2425 : 0 : return FALSE;
2426 : :
2427 : 0 : param = (GIIrNodeParam *)gi_ir_node_new (GI_IR_NODE_PARAM,
2428 : : ctx->current_module);
2429 : 0 : param->in = FALSE;
2430 : 0 : param->out = FALSE;
2431 : 0 : param->retval = TRUE;
2432 : :
2433 : 0 : ctx->current_typed = (GIIrNode*) param;
2434 : :
2435 : 0 : state_switch (ctx, STATE_FUNCTION_RETURN);
2436 : :
2437 : 0 : skip = find_attribute ("skip", attribute_names, attribute_values);
2438 [ # # # # ]: 0 : if (skip && strcmp (skip, "1") == 0)
2439 : 0 : param->skip = TRUE;
2440 : : else
2441 : 0 : param->skip = FALSE;
2442 : :
2443 : 0 : transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
2444 [ # # ]: 0 : if (!parse_param_transfer (param, transfer, NULL, error))
2445 : 0 : return FALSE;
2446 : :
2447 : 0 : nullable = find_attribute ("nullable", attribute_names, attribute_values);
2448 [ # # # # ]: 0 : if (nullable && g_str_equal (nullable, "1"))
2449 : 0 : param->nullable = TRUE;
2450 : :
2451 [ # # # # ]: 0 : switch (CURRENT_NODE (ctx)->type)
2452 : : {
2453 : 0 : case GI_IR_NODE_FUNCTION:
2454 : : case GI_IR_NODE_CALLBACK:
2455 : : {
2456 : 0 : GIIrNodeFunction *func = (GIIrNodeFunction *)CURRENT_NODE (ctx);
2457 : 0 : func->result = param;
2458 : : }
2459 : 0 : break;
2460 : 0 : case GI_IR_NODE_SIGNAL:
2461 : : {
2462 : 0 : GIIrNodeSignal *signal = (GIIrNodeSignal *)CURRENT_NODE (ctx);
2463 : 0 : signal->result = param;
2464 : : }
2465 : 0 : break;
2466 : 0 : case GI_IR_NODE_VFUNC:
2467 : : {
2468 : 0 : GIIrNodeVFunc *vfunc = (GIIrNodeVFunc *)CURRENT_NODE (ctx);
2469 : 0 : vfunc->result = param;
2470 : : }
2471 : 0 : break;
2472 : 0 : default:
2473 : : g_assert_not_reached ();
2474 : : }
2475 : :
2476 : 0 : return TRUE;
2477 : : }
2478 : :
2479 : : static gboolean
2480 : 0 : start_implements (GMarkupParseContext *context,
2481 : : const char *element_name,
2482 : : const char **attribute_names,
2483 : : const char **attribute_values,
2484 : : ParseContext *ctx,
2485 : : GError **error)
2486 : : {
2487 : : GIIrNodeInterface *iface;
2488 : : const char *name;
2489 : :
2490 [ # # ]: 0 : if (strcmp (element_name, "implements") != 0 ||
2491 [ # # ]: 0 : !(ctx->state == STATE_CLASS))
2492 : 0 : return FALSE;
2493 : :
2494 : 0 : state_switch (ctx, STATE_IMPLEMENTS);
2495 : :
2496 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
2497 [ # # ]: 0 : if (name == NULL)
2498 : : {
2499 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
2500 : 0 : return FALSE;
2501 : : }
2502 : :
2503 : 0 : iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
2504 : 0 : iface->interfaces = g_list_append (iface->interfaces, g_strdup (name));
2505 : :
2506 : 0 : return TRUE;
2507 : : }
2508 : :
2509 : : static gboolean
2510 : 0 : start_glib_signal (GMarkupParseContext *context,
2511 : : const char *element_name,
2512 : : const char **attribute_names,
2513 : : const char **attribute_values,
2514 : : ParseContext *ctx,
2515 : : GError **error)
2516 : : {
2517 : : const char *name;
2518 : : const char *when;
2519 : : const char *no_recurse;
2520 : : const char *detailed;
2521 : : const char *action;
2522 : : const char *no_hooks;
2523 : : const char *has_class_closure;
2524 : : GIIrNodeInterface *iface;
2525 : : GIIrNodeSignal *signal;
2526 : :
2527 [ # # ]: 0 : if (!(strcmp (element_name, "glib:signal") == 0 &&
2528 [ # # ]: 0 : (ctx->state == STATE_CLASS ||
2529 [ # # ]: 0 : ctx->state == STATE_INTERFACE)))
2530 : 0 : return FALSE;
2531 : :
2532 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
2533 : 0 : return TRUE;
2534 : :
2535 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
2536 : 0 : when = find_attribute ("when", attribute_names, attribute_values);
2537 : 0 : no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values);
2538 : 0 : detailed = find_attribute ("detailed", attribute_names, attribute_values);
2539 : 0 : action = find_attribute ("action", attribute_names, attribute_values);
2540 : 0 : no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values);
2541 : 0 : has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values);
2542 : :
2543 [ # # ]: 0 : if (name == NULL)
2544 : : {
2545 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
2546 : 0 : return FALSE;
2547 : : }
2548 : 0 : signal = (GIIrNodeSignal *)gi_ir_node_new (GI_IR_NODE_SIGNAL,
2549 : : ctx->current_module);
2550 : :
2551 : 0 : ((GIIrNode *)signal)->name = g_strdup (name);
2552 : :
2553 : 0 : signal->run_first = FALSE;
2554 : 0 : signal->run_last = FALSE;
2555 : 0 : signal->run_cleanup = FALSE;
2556 [ # # # # ]: 0 : if (when == NULL || g_ascii_strcasecmp (when, "LAST") == 0)
2557 : 0 : signal->run_last = TRUE;
2558 [ # # ]: 0 : else if (g_ascii_strcasecmp (when, "FIRST") == 0)
2559 : 0 : signal->run_first = TRUE;
2560 : : else
2561 : 0 : signal->run_cleanup = TRUE;
2562 : :
2563 [ # # # # ]: 0 : if (no_recurse && strcmp (no_recurse, "1") == 0)
2564 : 0 : signal->no_recurse = TRUE;
2565 : : else
2566 : 0 : signal->no_recurse = FALSE;
2567 [ # # # # ]: 0 : if (detailed && strcmp (detailed, "1") == 0)
2568 : 0 : signal->detailed = TRUE;
2569 : : else
2570 : 0 : signal->detailed = FALSE;
2571 [ # # # # ]: 0 : if (action && strcmp (action, "1") == 0)
2572 : 0 : signal->action = TRUE;
2573 : : else
2574 : 0 : signal->action = FALSE;
2575 [ # # # # ]: 0 : if (no_hooks && strcmp (no_hooks, "1") == 0)
2576 : 0 : signal->no_hooks = TRUE;
2577 : : else
2578 : 0 : signal->no_hooks = FALSE;
2579 [ # # # # ]: 0 : if (has_class_closure && strcmp (has_class_closure, "1") == 0)
2580 : 0 : signal->has_class_closure = TRUE;
2581 : : else
2582 : 0 : signal->has_class_closure = FALSE;
2583 : :
2584 : 0 : iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
2585 : 0 : iface->members = g_list_append (iface->members, signal);
2586 : :
2587 : 0 : push_node (ctx, (GIIrNode *)signal);
2588 : :
2589 : 0 : return TRUE;
2590 : : }
2591 : :
2592 : : static gboolean
2593 : 0 : start_vfunc (GMarkupParseContext *context,
2594 : : const char *element_name,
2595 : : const char **attribute_names,
2596 : : const char **attribute_values,
2597 : : ParseContext *ctx,
2598 : : GError **error)
2599 : : {
2600 : : const char *name;
2601 : : const char *must_chain_up;
2602 : : const char *override;
2603 : : const char *is_class_closure;
2604 : : const char *offset;
2605 : : const char *invoker;
2606 : : const char *throws;
2607 : : GIIrNodeInterface *iface;
2608 : : GIIrNodeVFunc *vfunc;
2609 : : guint64 parsed_offset;
2610 : :
2611 [ # # ]: 0 : if (!(strcmp (element_name, "virtual-method") == 0 &&
2612 [ # # ]: 0 : (ctx->state == STATE_CLASS ||
2613 [ # # ]: 0 : ctx->state == STATE_INTERFACE)))
2614 : 0 : return FALSE;
2615 : :
2616 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
2617 : 0 : return TRUE;
2618 : :
2619 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
2620 : 0 : must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);
2621 : 0 : override = find_attribute ("override", attribute_names, attribute_values);
2622 : 0 : is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
2623 : 0 : offset = find_attribute ("offset", attribute_names, attribute_values);
2624 : 0 : invoker = find_attribute ("invoker", attribute_names, attribute_values);
2625 : 0 : throws = find_attribute ("throws", attribute_names, attribute_values);
2626 : :
2627 [ # # ]: 0 : if (name == NULL)
2628 : : {
2629 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
2630 : 0 : return FALSE;
2631 : : }
2632 : :
2633 : 0 : vfunc = (GIIrNodeVFunc *)gi_ir_node_new (GI_IR_NODE_VFUNC,
2634 : : ctx->current_module);
2635 : :
2636 : 0 : ((GIIrNode *)vfunc)->name = g_strdup (name);
2637 : :
2638 [ # # # # ]: 0 : if (must_chain_up && strcmp (must_chain_up, "1") == 0)
2639 : 0 : vfunc->must_chain_up = TRUE;
2640 : : else
2641 : 0 : vfunc->must_chain_up = FALSE;
2642 : :
2643 [ # # # # ]: 0 : if (override && strcmp (override, "always") == 0)
2644 : : {
2645 : 0 : vfunc->must_be_implemented = TRUE;
2646 : 0 : vfunc->must_not_be_implemented = FALSE;
2647 : : }
2648 [ # # # # ]: 0 : else if (override && strcmp (override, "never") == 0)
2649 : : {
2650 : 0 : vfunc->must_be_implemented = FALSE;
2651 : 0 : vfunc->must_not_be_implemented = TRUE;
2652 : : }
2653 : : else
2654 : : {
2655 : 0 : vfunc->must_be_implemented = FALSE;
2656 : 0 : vfunc->must_not_be_implemented = FALSE;
2657 : : }
2658 : :
2659 [ # # # # ]: 0 : if (is_class_closure && strcmp (is_class_closure, "1") == 0)
2660 : 0 : vfunc->is_class_closure = TRUE;
2661 : : else
2662 : 0 : vfunc->is_class_closure = FALSE;
2663 : :
2664 [ # # # # ]: 0 : if (throws && strcmp (throws, "1") == 0)
2665 : 0 : vfunc->throws = TRUE;
2666 : : else
2667 : 0 : vfunc->throws = FALSE;
2668 : :
2669 [ # # ]: 0 : if (offset == NULL)
2670 : 0 : vfunc->offset = 0xFFFF;
2671 [ # # ]: 0 : else if (g_ascii_string_to_unsigned (offset, 10, 0, G_MAXSIZE, &parsed_offset, error))
2672 : 0 : vfunc->offset = parsed_offset;
2673 : : else
2674 : : {
2675 : 0 : gi_ir_node_free ((GIIrNode *) vfunc);
2676 : 0 : return FALSE;
2677 : : }
2678 : :
2679 : 0 : vfunc->invoker = g_strdup (invoker);
2680 : :
2681 : 0 : iface = (GIIrNodeInterface *)CURRENT_NODE (ctx);
2682 : 0 : iface->members = g_list_append (iface->members, vfunc);
2683 : :
2684 : 0 : push_node (ctx, (GIIrNode *)vfunc);
2685 : :
2686 : 0 : return TRUE;
2687 : : }
2688 : :
2689 : : static gboolean
2690 : 0 : start_struct (GMarkupParseContext *context,
2691 : : const char *element_name,
2692 : : const char **attribute_names,
2693 : : const char **attribute_values,
2694 : : ParseContext *ctx,
2695 : : GError **error)
2696 : : {
2697 : : const char *name;
2698 : : const char *deprecated;
2699 : : const char *disguised;
2700 : : const char *opaque;
2701 : : const char *pointer;
2702 : : const char *gtype_name;
2703 : : const char *gtype_init;
2704 : : const char *gtype_struct;
2705 : : const char *foreign;
2706 : : const char *copy_func;
2707 : : const char *free_func;
2708 : : GIIrNodeStruct *struct_;
2709 : :
2710 [ # # ]: 0 : if (!(strcmp (element_name, "record") == 0 &&
2711 [ # # ]: 0 : (ctx->state == STATE_NAMESPACE ||
2712 [ # # ]: 0 : ctx->state == STATE_UNION ||
2713 [ # # ]: 0 : ctx->state == STATE_STRUCT ||
2714 [ # # ]: 0 : ctx->state == STATE_CLASS)))
2715 : 0 : return FALSE;
2716 : :
2717 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_STRUCT))
2718 : 0 : return TRUE;
2719 : :
2720 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
2721 : 0 : deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
2722 : 0 : disguised = find_attribute ("disguised", attribute_names, attribute_values);
2723 : 0 : pointer = find_attribute ("pointer", attribute_names, attribute_values);
2724 : 0 : opaque = find_attribute ("opaque", attribute_names, attribute_values);
2725 : 0 : gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values);
2726 : 0 : gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values);
2727 : 0 : gtype_struct = find_attribute ("glib:is-gtype-struct-for", attribute_names, attribute_values);
2728 : 0 : foreign = find_attribute ("foreign", attribute_names, attribute_values);
2729 : 0 : copy_func = find_attribute ("copy-function", attribute_names, attribute_values);
2730 : 0 : free_func = find_attribute ("free-function", attribute_names, attribute_values);
2731 : :
2732 [ # # # # ]: 0 : if (name == NULL && ctx->node_stack == NULL)
2733 : : {
2734 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
2735 : 0 : return FALSE;
2736 : : }
2737 [ # # # # ]: 0 : if ((gtype_name == NULL && gtype_init != NULL))
2738 : : {
2739 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
2740 : 0 : return FALSE;
2741 : : }
2742 [ # # # # ]: 0 : if ((gtype_name != NULL && gtype_init == NULL))
2743 : : {
2744 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
2745 : 0 : return FALSE;
2746 : : }
2747 : :
2748 : 0 : struct_ = (GIIrNodeStruct *) gi_ir_node_new (GI_IR_NODE_STRUCT,
2749 : : ctx->current_module);
2750 : :
2751 [ # # ]: 0 : ((GIIrNode *)struct_)->name = g_strdup (name ? name : "");
2752 [ # # ]: 0 : if (deprecated)
2753 : 0 : struct_->deprecated = TRUE;
2754 : : else
2755 : 0 : struct_->deprecated = FALSE;
2756 : :
2757 [ # # ]: 0 : if (g_strcmp0 (disguised, "1") == 0)
2758 : 0 : struct_->disguised = TRUE;
2759 : :
2760 [ # # ]: 0 : if (g_strcmp0 (pointer, "1") == 0)
2761 : 0 : struct_->pointer = TRUE;
2762 : :
2763 [ # # ]: 0 : if (g_strcmp0 (opaque, "1") == 0)
2764 : 0 : struct_->opaque = TRUE;
2765 : :
2766 : 0 : struct_->is_gtype_struct = gtype_struct != NULL;
2767 : :
2768 : 0 : struct_->gtype_name = g_strdup (gtype_name);
2769 : 0 : struct_->gtype_init = g_strdup (gtype_init);
2770 : :
2771 : 0 : struct_->foreign = (g_strcmp0 (foreign, "1") == 0);
2772 : :
2773 : 0 : struct_->copy_func = g_strdup (copy_func);
2774 : 0 : struct_->free_func = g_strdup (free_func);
2775 : :
2776 [ # # ]: 0 : if (ctx->node_stack == NULL)
2777 : 0 : ctx->current_module->entries =
2778 : 0 : g_list_append (ctx->current_module->entries, struct_);
2779 : 0 : push_node (ctx, (GIIrNode *)struct_);
2780 : 0 : return TRUE;
2781 : : }
2782 : :
2783 : : static gboolean
2784 : 0 : start_union (GMarkupParseContext *context,
2785 : : const char *element_name,
2786 : : const char **attribute_names,
2787 : : const char **attribute_values,
2788 : : ParseContext *ctx,
2789 : : GError **error)
2790 : : {
2791 : : const char *name;
2792 : : const char *deprecated;
2793 : : const char *typename;
2794 : : const char *typeinit;
2795 : : const char *copy_func;
2796 : : const char *free_func;
2797 : : GIIrNodeUnion *union_;
2798 : :
2799 [ # # ]: 0 : if (!(strcmp (element_name, "union") == 0 &&
2800 [ # # ]: 0 : (ctx->state == STATE_NAMESPACE ||
2801 [ # # ]: 0 : ctx->state == STATE_UNION ||
2802 [ # # ]: 0 : ctx->state == STATE_STRUCT ||
2803 [ # # ]: 0 : ctx->state == STATE_CLASS)))
2804 : 0 : return FALSE;
2805 : :
2806 [ # # ]: 0 : if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_UNION))
2807 : 0 : return TRUE;
2808 : :
2809 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
2810 : 0 : deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
2811 : 0 : typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
2812 : 0 : typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
2813 : 0 : copy_func = find_attribute ("copy-function", attribute_names, attribute_values);
2814 : 0 : free_func = find_attribute ("free-function", attribute_names, attribute_values);
2815 : :
2816 [ # # # # ]: 0 : if (name == NULL && ctx->node_stack == NULL)
2817 : : {
2818 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
2819 : 0 : return FALSE;
2820 : : }
2821 : :
2822 : 0 : union_ = (GIIrNodeUnion *) gi_ir_node_new (GI_IR_NODE_UNION,
2823 : : ctx->current_module);
2824 : :
2825 [ # # ]: 0 : ((GIIrNode *)union_)->name = g_strdup (name ? name : "");
2826 : 0 : union_->gtype_name = g_strdup (typename);
2827 : 0 : union_->gtype_init = g_strdup (typeinit);
2828 : 0 : union_->copy_func = g_strdup (copy_func);
2829 : 0 : union_->free_func = g_strdup (free_func);
2830 [ # # ]: 0 : if (deprecated)
2831 : 0 : union_->deprecated = TRUE;
2832 : : else
2833 : 0 : union_->deprecated = FALSE;
2834 : :
2835 [ # # ]: 0 : if (ctx->node_stack == NULL)
2836 : 0 : ctx->current_module->entries =
2837 : 0 : g_list_append (ctx->current_module->entries, union_);
2838 : 0 : push_node (ctx, (GIIrNode *)union_);
2839 : 0 : return TRUE;
2840 : : }
2841 : :
2842 : : static gboolean
2843 : 0 : start_discriminator (GMarkupParseContext *context,
2844 : : const char *element_name,
2845 : : const char **attribute_names,
2846 : : const char **attribute_values,
2847 : : ParseContext *ctx,
2848 : : GError **error)
2849 : : {
2850 : : const char *type;
2851 : : const char *offset;
2852 : : guint64 parsed_offset;
2853 : :
2854 [ # # ]: 0 : if (!(strcmp (element_name, "discriminator") == 0 &&
2855 [ # # ]: 0 : ctx->state == STATE_UNION))
2856 : 0 : return FALSE;
2857 : :
2858 : 0 : type = find_attribute ("type", attribute_names, attribute_values);
2859 : 0 : offset = find_attribute ("offset", attribute_names, attribute_values);
2860 [ # # ]: 0 : if (type == NULL)
2861 : : {
2862 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "type");
2863 : 0 : return FALSE;
2864 : : }
2865 [ # # ]: 0 : else if (offset == NULL)
2866 : : {
2867 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "offset");
2868 : 0 : return FALSE;
2869 : : }
2870 : :
2871 : 0 : ((GIIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type
2872 : 0 : = parse_type (ctx, type);
2873 : :
2874 [ # # ]: 0 : if (g_ascii_string_to_unsigned (offset, 10, 0, G_MAXSIZE, &parsed_offset, error))
2875 : 0 : ((GIIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset = parsed_offset;
2876 : : else
2877 : 0 : return FALSE;
2878 : :
2879 : 0 : return TRUE;
2880 : : }
2881 : :
2882 : : static gboolean
2883 : 0 : parse_include (GMarkupParseContext *context,
2884 : : ParseContext *ctx,
2885 : : const char *name,
2886 : : const char *version)
2887 : : {
2888 : 0 : GError *error = NULL;
2889 : : char *buffer;
2890 : : gsize length;
2891 : : char *girpath, *girname;
2892 : : GIIrModule *module;
2893 : : GList *l;
2894 : :
2895 [ # # ]: 0 : for (l = ctx->parser->parsed_modules; l; l = l->next)
2896 : : {
2897 : 0 : GIIrModule *m = l->data;
2898 : :
2899 [ # # ]: 0 : if (strcmp (m->name, name) == 0)
2900 : : {
2901 [ # # ]: 0 : if (strcmp (m->version, version) == 0)
2902 : : {
2903 : 0 : ctx->include_modules = g_list_prepend (ctx->include_modules, m);
2904 : :
2905 : 0 : return TRUE;
2906 : : }
2907 : : else
2908 : : {
2909 : 0 : g_printerr ("Module '%s' imported with conflicting versions '%s' and '%s'\n",
2910 : : name, m->version, version);
2911 : 0 : return FALSE;
2912 : : }
2913 : : }
2914 : : }
2915 : :
2916 : 0 : girname = g_strdup_printf ("%s-%s.gir", name, version);
2917 : 0 : girpath = locate_gir (ctx->parser, girname);
2918 : :
2919 [ # # ]: 0 : if (girpath == NULL)
2920 : : {
2921 : 0 : g_printerr ("Could not find GIR file '%s'; check XDG_DATA_DIRS or use --includedir\n",
2922 : : girname);
2923 : 0 : g_free (girname);
2924 : 0 : return FALSE;
2925 : : }
2926 : 0 : g_free (girname);
2927 : :
2928 : 0 : g_debug ("Parsing include %s", girpath);
2929 : :
2930 [ # # ]: 0 : if (!g_file_get_contents (girpath, &buffer, &length, &error))
2931 : : {
2932 : 0 : g_printerr ("%s: %s\n", girpath, error->message);
2933 : 0 : g_clear_error (&error);
2934 : 0 : g_free (girpath);
2935 : 0 : return FALSE;
2936 : : }
2937 : :
2938 : 0 : module = gi_ir_parser_parse_string (ctx->parser, name, girpath, buffer, length, &error);
2939 : 0 : g_free (buffer);
2940 [ # # ]: 0 : if (error != NULL)
2941 : : {
2942 : : int line_number, char_number;
2943 : 0 : g_markup_parse_context_get_position (context, &line_number, &char_number);
2944 : 0 : g_printerr ("%s:%d:%d: error: %s\n", girpath, line_number, char_number, error->message);
2945 : 0 : g_clear_error (&error);
2946 : 0 : g_free (girpath);
2947 : 0 : return FALSE;
2948 : : }
2949 : 0 : g_free (girpath);
2950 : :
2951 : 0 : ctx->include_modules = g_list_append (ctx->include_modules,
2952 : : module);
2953 : :
2954 : 0 : return TRUE;
2955 : : }
2956 : :
2957 : : static void
2958 : 0 : start_element_handler (GMarkupParseContext *context,
2959 : : const char *element_name,
2960 : : const char **attribute_names,
2961 : : const char **attribute_values,
2962 : : gpointer user_data,
2963 : : GError **error)
2964 : : {
2965 : 0 : ParseContext *ctx = user_data;
2966 : :
2967 [ # # ]: 0 : if (ctx->parser->logged_levels & G_LOG_LEVEL_DEBUG)
2968 : : {
2969 : 0 : GString *tags = g_string_new ("");
2970 : : int i;
2971 [ # # ]: 0 : for (i = 0; attribute_names[i]; i++)
2972 : 0 : g_string_append_printf (tags, "%s=\"%s\" ",
2973 : 0 : attribute_names[i],
2974 : 0 : attribute_values[i]);
2975 : :
2976 [ # # ]: 0 : if (i)
2977 : : {
2978 : 0 : g_string_insert_c (tags, 0, ' ');
2979 : 0 : g_string_truncate (tags, tags->len - 1);
2980 : : }
2981 : 0 : g_debug ("<%s%s>", element_name, tags->str);
2982 : 0 : g_string_free (tags, TRUE);
2983 : : }
2984 : :
2985 [ # # ]: 0 : if (ctx->state == STATE_PASSTHROUGH)
2986 : : {
2987 : 0 : ctx->unknown_depth += 1;
2988 : 0 : return;
2989 : : }
2990 : :
2991 [ # # # # : 0 : switch (element_name[0])
# # # # #
# # # # #
# # # ]
2992 : : {
2993 : 0 : case 'a':
2994 [ # # # # ]: 0 : if (ctx->state == STATE_NAMESPACE && strcmp (element_name, "alias") == 0)
2995 : : {
2996 : 0 : state_switch (ctx, STATE_ALIAS);
2997 : 0 : goto out;
2998 : : }
2999 [ # # ]: 0 : if (start_type (context, element_name,
3000 : : attribute_names, attribute_values,
3001 : : ctx, error))
3002 : 0 : goto out;
3003 [ # # ]: 0 : else if (start_attribute (context, element_name,
3004 : : attribute_names, attribute_values,
3005 : : ctx, error))
3006 : 0 : goto out;
3007 : 0 : break;
3008 : 0 : case 'b':
3009 [ # # ]: 0 : if (start_enum (context, element_name,
3010 : : attribute_names, attribute_values,
3011 : : ctx, error))
3012 : 0 : goto out;
3013 : 0 : break;
3014 : 0 : case 'c':
3015 [ # # ]: 0 : if (start_function (context, element_name,
3016 : : attribute_names, attribute_values,
3017 : : ctx, error))
3018 : 0 : goto out;
3019 [ # # ]: 0 : else if (start_constant (context, element_name,
3020 : : attribute_names, attribute_values,
3021 : : ctx, error))
3022 : 0 : goto out;
3023 [ # # ]: 0 : else if (start_class (context, element_name,
3024 : : attribute_names, attribute_values,
3025 : : ctx, error))
3026 : 0 : goto out;
3027 : 0 : break;
3028 : :
3029 : 0 : case 'd':
3030 [ # # ]: 0 : if (start_discriminator (context, element_name,
3031 : : attribute_names, attribute_values,
3032 : : ctx, error))
3033 : 0 : goto out;
3034 [ # # # # ]: 0 : if (strcmp ("doc", element_name) == 0 || strcmp ("doc-deprecated", element_name) == 0 ||
3035 [ # # # # ]: 0 : strcmp ("doc-stability", element_name) == 0 || strcmp ("doc-version", element_name) == 0 ||
3036 [ # # ]: 0 : strcmp ("docsection", element_name) == 0)
3037 : : {
3038 : 0 : state_switch (ctx, STATE_PASSTHROUGH);
3039 : 0 : goto out;
3040 : : }
3041 : 0 : break;
3042 : :
3043 : 0 : case 'e':
3044 [ # # ]: 0 : if (start_enum (context, element_name,
3045 : : attribute_names, attribute_values,
3046 : : ctx, error))
3047 : 0 : goto out;
3048 : 0 : break;
3049 : :
3050 : 0 : case 'f':
3051 [ # # ]: 0 : if (strcmp ("function-macro", element_name) == 0)
3052 : : {
3053 : 0 : state_switch (ctx, STATE_PASSTHROUGH);
3054 : 0 : goto out;
3055 : : }
3056 [ # # ]: 0 : else if (start_function (context, element_name,
3057 : : attribute_names, attribute_values,
3058 : : ctx, error))
3059 : 0 : goto out;
3060 [ # # ]: 0 : else if (start_field (context, element_name,
3061 : : attribute_names, attribute_values,
3062 : : ctx, error))
3063 : 0 : goto out;
3064 : 0 : break;
3065 : :
3066 : 0 : case 'g':
3067 [ # # ]: 0 : if (start_glib_boxed (context, element_name,
3068 : : attribute_names, attribute_values,
3069 : : ctx, error))
3070 : 0 : goto out;
3071 [ # # ]: 0 : else if (start_glib_signal (context, element_name,
3072 : : attribute_names, attribute_values,
3073 : : ctx, error))
3074 : 0 : goto out;
3075 : 0 : break;
3076 : :
3077 : 0 : case 'i':
3078 [ # # ]: 0 : if (strcmp (element_name, "include") == 0 &&
3079 [ # # ]: 0 : ctx->state == STATE_REPOSITORY)
3080 : : {
3081 : : const char *name;
3082 : : const char *version;
3083 : :
3084 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
3085 : 0 : version = find_attribute ("version", attribute_names, attribute_values);
3086 : :
3087 [ # # ]: 0 : if (name == NULL)
3088 : : {
3089 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
3090 : 0 : break;
3091 : : }
3092 [ # # ]: 0 : if (version == NULL)
3093 : : {
3094 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "version");
3095 : 0 : break;
3096 : : }
3097 : :
3098 [ # # ]: 0 : if (!parse_include (context, ctx, name, version))
3099 : : {
3100 : 0 : g_set_error (error,
3101 : : G_MARKUP_ERROR,
3102 : : G_MARKUP_ERROR_INVALID_CONTENT,
3103 : : "Failed to parse included gir %s-%s",
3104 : : name,
3105 : : version);
3106 : 0 : return;
3107 : : }
3108 : :
3109 : 0 : ctx->dependencies = g_list_prepend (ctx->dependencies,
3110 : 0 : g_strdup_printf ("%s-%s", name, version));
3111 : :
3112 : :
3113 : 0 : state_switch (ctx, STATE_INCLUDE);
3114 : 0 : goto out;
3115 : : }
3116 [ # # ]: 0 : if (start_interface (context, element_name,
3117 : : attribute_names, attribute_values,
3118 : : ctx, error))
3119 : 0 : goto out;
3120 [ # # ]: 0 : else if (start_implements (context, element_name,
3121 : : attribute_names, attribute_values,
3122 : : ctx, error))
3123 : 0 : goto out;
3124 [ # # ]: 0 : else if (start_instance_parameter (context, element_name,
3125 : : attribute_names, attribute_values,
3126 : : ctx, error))
3127 : 0 : goto out;
3128 [ # # ]: 0 : else if (strcmp (element_name, "c:include") == 0)
3129 : : {
3130 : 0 : state_switch (ctx, STATE_C_INCLUDE);
3131 : 0 : goto out;
3132 : : }
3133 : 0 : break;
3134 : :
3135 : 0 : case 'm':
3136 [ # # ]: 0 : if (start_function (context, element_name,
3137 : : attribute_names, attribute_values,
3138 : : ctx, error))
3139 : 0 : goto out;
3140 [ # # ]: 0 : else if (start_member (context, element_name,
3141 : : attribute_names, attribute_values,
3142 : : ctx, error))
3143 : 0 : goto out;
3144 : 0 : break;
3145 : :
3146 : 0 : case 'n':
3147 [ # # # # ]: 0 : if (strcmp (element_name, "namespace") == 0 && ctx->state == STATE_REPOSITORY)
3148 : : {
3149 : : const char *name, *version, *shared_library, *cprefix;
3150 : :
3151 [ # # ]: 0 : if (ctx->current_module != NULL)
3152 : : {
3153 : 0 : g_set_error (error,
3154 : : G_MARKUP_ERROR,
3155 : : G_MARKUP_ERROR_INVALID_CONTENT,
3156 : : "Only one <namespace/> element is currently allowed per <repository/>");
3157 : 0 : goto out;
3158 : : }
3159 : :
3160 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
3161 : 0 : version = find_attribute ("version", attribute_names, attribute_values);
3162 : 0 : shared_library = find_attribute ("shared-library", attribute_names, attribute_values);
3163 : 0 : cprefix = find_attribute ("c:identifier-prefixes", attribute_names, attribute_values);
3164 : : /* Backwards compatibility; vala currently still generates this */
3165 [ # # ]: 0 : if (cprefix == NULL)
3166 : 0 : cprefix = find_attribute ("c:prefix", attribute_names, attribute_values);
3167 : :
3168 [ # # ]: 0 : if (name == NULL)
3169 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
3170 [ # # ]: 0 : else if (version == NULL)
3171 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "version");
3172 : : else
3173 : : {
3174 : : GList *l;
3175 : :
3176 [ # # ]: 0 : if (strcmp (name, ctx->namespace) != 0)
3177 : 0 : g_set_error (error,
3178 : : G_MARKUP_ERROR,
3179 : : G_MARKUP_ERROR_INVALID_CONTENT,
3180 : : "<namespace/> name element '%s' doesn't match file name '%s'",
3181 : : name, ctx->namespace);
3182 : :
3183 : 0 : ctx->current_module = gi_ir_module_new (name, version, shared_library, cprefix);
3184 : :
3185 : 0 : ctx->current_module->aliases = ctx->aliases;
3186 : 0 : ctx->aliases = NULL;
3187 : 0 : ctx->current_module->disguised_structures = ctx->disguised_structures;
3188 : 0 : ctx->current_module->pointer_structures = ctx->pointer_structures;
3189 : 0 : ctx->disguised_structures = NULL;
3190 : 0 : ctx->pointer_structures = NULL;
3191 : :
3192 [ # # ]: 0 : for (l = ctx->include_modules; l; l = l->next)
3193 : 0 : gi_ir_module_add_include_module (ctx->current_module, l->data);
3194 : :
3195 : 0 : g_list_free (ctx->include_modules);
3196 : 0 : ctx->include_modules = NULL;
3197 : :
3198 : 0 : ctx->modules = g_list_append (ctx->modules, ctx->current_module);
3199 : 0 : ctx->current_module->dependencies = ctx->dependencies;
3200 : :
3201 : 0 : state_switch (ctx, STATE_NAMESPACE);
3202 : 0 : goto out;
3203 : : }
3204 : : }
3205 : 0 : break;
3206 : :
3207 : 0 : case 'p':
3208 [ # # ]: 0 : if (start_property (context, element_name,
3209 : : attribute_names, attribute_values,
3210 : : ctx, error))
3211 : 0 : goto out;
3212 [ # # ]: 0 : else if (strcmp (element_name, "parameters") == 0 &&
3213 [ # # ]: 0 : ctx->state == STATE_FUNCTION)
3214 : : {
3215 : 0 : state_switch (ctx, STATE_FUNCTION_PARAMETERS);
3216 : :
3217 : 0 : goto out;
3218 : : }
3219 [ # # ]: 0 : else if (start_parameter (context, element_name,
3220 : : attribute_names, attribute_values,
3221 : : ctx, error))
3222 : 0 : goto out;
3223 [ # # ]: 0 : else if (strcmp (element_name, "prerequisite") == 0 &&
3224 [ # # ]: 0 : ctx->state == STATE_INTERFACE)
3225 : : {
3226 : : const char *name;
3227 : :
3228 : 0 : name = find_attribute ("name", attribute_names, attribute_values);
3229 : :
3230 : 0 : state_switch (ctx, STATE_PREREQUISITE);
3231 : :
3232 [ # # ]: 0 : if (name == NULL)
3233 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "name");
3234 : : else
3235 : : {
3236 : : GIIrNodeInterface *iface;
3237 : :
3238 : 0 : iface = (GIIrNodeInterface *)CURRENT_NODE(ctx);
3239 : 0 : iface->prerequisites = g_list_append (iface->prerequisites, g_strdup (name));
3240 : : }
3241 : 0 : goto out;
3242 : : }
3243 [ # # ]: 0 : else if (strcmp (element_name, "package") == 0 &&
3244 [ # # ]: 0 : ctx->state == STATE_REPOSITORY)
3245 : : {
3246 : 0 : state_switch (ctx, STATE_PACKAGE);
3247 : 0 : goto out;
3248 : : }
3249 : 0 : break;
3250 : :
3251 : 0 : case 'r':
3252 [ # # # # ]: 0 : if (strcmp (element_name, "repository") == 0 && ctx->state == STATE_START)
3253 : : {
3254 : : const char *version;
3255 : :
3256 : 0 : version = find_attribute ("version", attribute_names, attribute_values);
3257 : :
3258 [ # # ]: 0 : if (version == NULL)
3259 : 0 : MISSING_ATTRIBUTE (context, error, element_name, "version");
3260 [ # # ]: 0 : else if (strcmp (version, SUPPORTED_GIR_VERSION) != 0)
3261 : 0 : g_set_error (error,
3262 : : G_MARKUP_ERROR,
3263 : : G_MARKUP_ERROR_INVALID_CONTENT,
3264 : : "Unsupported version '%s'",
3265 : : version);
3266 : : else
3267 : 0 : state_switch (ctx, STATE_REPOSITORY);
3268 : :
3269 : 0 : goto out;
3270 : : }
3271 [ # # ]: 0 : else if (start_return_value (context, element_name,
3272 : : attribute_names, attribute_values,
3273 : : ctx, error))
3274 : 0 : goto out;
3275 [ # # ]: 0 : else if (start_struct (context, element_name,
3276 : : attribute_names, attribute_values,
3277 : : ctx, error))
3278 : 0 : goto out;
3279 : 0 : break;
3280 : :
3281 : 0 : case 's':
3282 [ # # ]: 0 : if (strcmp ("source-position", element_name) == 0)
3283 : : {
3284 : 0 : state_switch (ctx, STATE_PASSTHROUGH);
3285 : 0 : goto out;
3286 : : }
3287 : 0 : break;
3288 : 0 : case 'u':
3289 [ # # ]: 0 : if (start_union (context, element_name,
3290 : : attribute_names, attribute_values,
3291 : : ctx, error))
3292 : 0 : goto out;
3293 : 0 : break;
3294 : :
3295 : 0 : case 't':
3296 [ # # ]: 0 : if (start_type (context, element_name,
3297 : : attribute_names, attribute_values,
3298 : : ctx, error))
3299 : 0 : goto out;
3300 : 0 : break;
3301 : :
3302 : 0 : case 'v':
3303 [ # # ]: 0 : if (start_vfunc (context, element_name,
3304 : : attribute_names, attribute_values,
3305 : : ctx, error))
3306 : 0 : goto out;
3307 [ # # ]: 0 : if (start_type (context, element_name,
3308 : : attribute_names, attribute_values,
3309 : : ctx, error))
3310 : 0 : goto out;
3311 : 0 : break;
3312 : 0 : default:
3313 : 0 : break;
3314 : : }
3315 : :
3316 [ # # # # ]: 0 : if (*error == NULL && ctx->state != STATE_PASSTHROUGH)
3317 : : {
3318 : : int line_number, char_number;
3319 : 0 : g_markup_parse_context_get_position (context, &line_number, &char_number);
3320 [ # # # # : 0 : if (!g_str_has_prefix (element_name, "c:"))
# # # # ]
3321 : 0 : g_printerr ("%s:%d:%d: warning: element %s from state %d is unknown, ignoring\n",
3322 : : ctx->file_path, line_number, char_number, element_name,
3323 : 0 : ctx->state);
3324 : 0 : state_switch (ctx, STATE_PASSTHROUGH);
3325 : : }
3326 : :
3327 : 0 : out:
3328 [ # # ]: 0 : if (*error)
3329 : : {
3330 : : int line_number, char_number;
3331 : 0 : g_markup_parse_context_get_position (context, &line_number, &char_number);
3332 : :
3333 : 0 : g_printerr ("%s:%d:%d: error: %s\n", ctx->file_path, line_number, char_number, (*error)->message);
3334 : : }
3335 : : }
3336 : :
3337 : : static gboolean
3338 : 0 : require_one_of_end_elements (GMarkupParseContext *context,
3339 : : ParseContext *ctx,
3340 : : const char *actual_name,
3341 : : GError **error,
3342 : : ...)
3343 : : {
3344 : : va_list args;
3345 : : int line_number, char_number;
3346 : : const char *expected;
3347 : 0 : gboolean matched = FALSE;
3348 : :
3349 : 0 : va_start (args, error);
3350 : :
3351 [ # # ]: 0 : while ((expected = va_arg (args, const char*)) != NULL)
3352 : : {
3353 [ # # ]: 0 : if (strcmp (expected, actual_name) == 0)
3354 : : {
3355 : 0 : matched = TRUE;
3356 : 0 : break;
3357 : : }
3358 : : }
3359 : :
3360 : 0 : va_end (args);
3361 : :
3362 [ # # ]: 0 : if (matched)
3363 : 0 : return TRUE;
3364 : :
3365 : 0 : g_markup_parse_context_get_position (context, &line_number, &char_number);
3366 : 0 : g_set_error (error,
3367 : : G_MARKUP_ERROR,
3368 : : G_MARKUP_ERROR_INVALID_CONTENT,
3369 : : "Unexpected end tag '%s' on line %d char %d; current state=%d (prev=%d)",
3370 : : actual_name,
3371 : 0 : line_number, char_number, ctx->state, ctx->prev_state);
3372 : 0 : return FALSE;
3373 : : }
3374 : :
3375 : : static gboolean
3376 : 0 : state_switch_end_struct_or_union (GMarkupParseContext *context,
3377 : : ParseContext *ctx,
3378 : : const char *element_name,
3379 : : GError **error)
3380 : : {
3381 : 0 : pop_node (ctx);
3382 [ # # ]: 0 : if (ctx->node_stack == NULL)
3383 : : {
3384 : 0 : state_switch (ctx, STATE_NAMESPACE);
3385 : : }
3386 : : else
3387 : : {
3388 [ # # ]: 0 : if (CURRENT_NODE (ctx)->type == GI_IR_NODE_STRUCT)
3389 : 0 : state_switch (ctx, STATE_STRUCT);
3390 [ # # ]: 0 : else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_UNION)
3391 : 0 : state_switch (ctx, STATE_UNION);
3392 [ # # ]: 0 : else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_OBJECT)
3393 : 0 : state_switch (ctx, STATE_CLASS);
3394 : : else
3395 : : {
3396 : : int line_number, char_number;
3397 : 0 : g_markup_parse_context_get_position (context, &line_number, &char_number);
3398 : 0 : g_set_error (error,
3399 : : G_MARKUP_ERROR,
3400 : : G_MARKUP_ERROR_INVALID_CONTENT,
3401 : : "Unexpected end tag '%s' on line %d char %d",
3402 : : element_name,
3403 : : line_number, char_number);
3404 : 0 : return FALSE;
3405 : : }
3406 : : }
3407 : 0 : return TRUE;
3408 : : }
3409 : :
3410 : : static gboolean
3411 : 0 : require_end_element (GMarkupParseContext *context,
3412 : : ParseContext *ctx,
3413 : : const char *expected_name,
3414 : : const char *actual_name,
3415 : : GError **error)
3416 : : {
3417 : 0 : return require_one_of_end_elements (context, ctx, actual_name, error, expected_name, NULL);
3418 : : }
3419 : :
3420 : : static void
3421 : 0 : end_element_handler (GMarkupParseContext *context,
3422 : : const char *element_name,
3423 : : gpointer user_data,
3424 : : GError **error)
3425 : : {
3426 : 0 : ParseContext *ctx = user_data;
3427 : :
3428 : 0 : g_debug ("</%s>", element_name);
3429 : :
3430 [ # # # # : 0 : switch (ctx->state)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
3431 : : {
3432 : 0 : case STATE_START:
3433 : : case STATE_END:
3434 : : /* no need to GError here, GMarkup already catches this */
3435 : 0 : break;
3436 : :
3437 : 0 : case STATE_REPOSITORY:
3438 : 0 : state_switch (ctx, STATE_END);
3439 : 0 : break;
3440 : :
3441 : 0 : case STATE_INCLUDE:
3442 [ # # ]: 0 : if (require_end_element (context, ctx, "include", element_name, error))
3443 : : {
3444 : 0 : state_switch (ctx, STATE_REPOSITORY);
3445 : : }
3446 : 0 : break;
3447 : :
3448 : 0 : case STATE_C_INCLUDE:
3449 [ # # ]: 0 : if (require_end_element (context, ctx, "c:include", element_name, error))
3450 : : {
3451 : 0 : state_switch (ctx, STATE_REPOSITORY);
3452 : : }
3453 : 0 : break;
3454 : :
3455 : 0 : case STATE_PACKAGE:
3456 [ # # ]: 0 : if (require_end_element (context, ctx, "package", element_name, error))
3457 : : {
3458 : 0 : state_switch (ctx, STATE_REPOSITORY);
3459 : : }
3460 : 0 : break;
3461 : :
3462 : 0 : case STATE_NAMESPACE:
3463 [ # # ]: 0 : if (require_end_element (context, ctx, "namespace", element_name, error))
3464 : : {
3465 : 0 : ctx->current_module = NULL;
3466 : 0 : state_switch (ctx, STATE_REPOSITORY);
3467 : : }
3468 : 0 : break;
3469 : :
3470 : 0 : case STATE_ALIAS:
3471 [ # # ]: 0 : if (require_end_element (context, ctx, "alias", element_name, error))
3472 : : {
3473 : 0 : g_free (ctx->current_alias);
3474 : 0 : ctx->current_alias = NULL;
3475 : 0 : state_switch (ctx, STATE_NAMESPACE);
3476 : : }
3477 : 0 : break;
3478 : :
3479 : 0 : case STATE_FUNCTION_RETURN:
3480 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3481 : 0 : break;
3482 [ # # ]: 0 : if (require_end_element (context, ctx, "return-value", element_name, error))
3483 : : {
3484 : 0 : state_switch (ctx, STATE_FUNCTION);
3485 : : }
3486 : 0 : break;
3487 : :
3488 : 0 : case STATE_FUNCTION_PARAMETERS:
3489 [ # # ]: 0 : if (require_end_element (context, ctx, "parameters", element_name, error))
3490 : : {
3491 : 0 : state_switch (ctx, STATE_FUNCTION);
3492 : : }
3493 : 0 : break;
3494 : :
3495 : 0 : case STATE_FUNCTION_PARAMETER:
3496 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3497 : 0 : break;
3498 [ # # ]: 0 : if (require_end_element (context, ctx, "parameter", element_name, error))
3499 : : {
3500 : 0 : state_switch (ctx, STATE_FUNCTION_PARAMETERS);
3501 : : }
3502 : 0 : break;
3503 : :
3504 : 0 : case STATE_FUNCTION:
3505 : : {
3506 : 0 : pop_node (ctx);
3507 [ # # ]: 0 : if (ctx->node_stack == NULL)
3508 : : {
3509 : 0 : state_switch (ctx, STATE_NAMESPACE);
3510 : : }
3511 : : else
3512 : : {
3513 : 0 : g_debug("case STATE_FUNCTION %d", CURRENT_NODE (ctx)->type);
3514 [ # # ]: 0 : if (ctx->in_embedded_state != STATE_NONE)
3515 : : {
3516 : 0 : state_switch (ctx, ctx->in_embedded_state);
3517 : 0 : ctx->in_embedded_state = STATE_NONE;
3518 : : }
3519 [ # # ]: 0 : else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_INTERFACE)
3520 : 0 : state_switch (ctx, STATE_INTERFACE);
3521 [ # # ]: 0 : else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_OBJECT)
3522 : 0 : state_switch (ctx, STATE_CLASS);
3523 [ # # ]: 0 : else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_BOXED)
3524 : 0 : state_switch (ctx, STATE_BOXED);
3525 [ # # ]: 0 : else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_STRUCT)
3526 : 0 : state_switch (ctx, STATE_STRUCT);
3527 [ # # ]: 0 : else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_UNION)
3528 : 0 : state_switch (ctx, STATE_UNION);
3529 [ # # ]: 0 : else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_ENUM ||
3530 [ # # ]: 0 : CURRENT_NODE (ctx)->type == GI_IR_NODE_FLAGS)
3531 : 0 : state_switch (ctx, STATE_ENUM);
3532 : : else
3533 : : {
3534 : : int line_number, char_number;
3535 : 0 : g_markup_parse_context_get_position (context, &line_number, &char_number);
3536 : 0 : g_set_error (error,
3537 : : G_MARKUP_ERROR,
3538 : : G_MARKUP_ERROR_INVALID_CONTENT,
3539 : : "Unexpected end tag '%s' on line %d char %d",
3540 : : element_name,
3541 : : line_number, char_number);
3542 : : }
3543 : : }
3544 : : }
3545 : 0 : break;
3546 : :
3547 : 0 : case STATE_CLASS_FIELD:
3548 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3549 : 0 : break;
3550 [ # # ]: 0 : if (require_end_element (context, ctx, "field", element_name, error))
3551 : : {
3552 : 0 : state_switch (ctx, STATE_CLASS);
3553 : : }
3554 : 0 : break;
3555 : :
3556 : 0 : case STATE_CLASS_PROPERTY:
3557 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3558 : 0 : break;
3559 [ # # ]: 0 : if (require_end_element (context, ctx, "property", element_name, error))
3560 : : {
3561 : 0 : state_switch (ctx, STATE_CLASS);
3562 : : }
3563 : 0 : break;
3564 : :
3565 : 0 : case STATE_CLASS:
3566 [ # # ]: 0 : if (require_end_element (context, ctx, "class", element_name, error))
3567 : : {
3568 : 0 : pop_node (ctx);
3569 : 0 : state_switch (ctx, STATE_NAMESPACE);
3570 : : }
3571 : 0 : break;
3572 : :
3573 : 0 : case STATE_INTERFACE_PROPERTY:
3574 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3575 : 0 : break;
3576 [ # # ]: 0 : if (require_end_element (context, ctx, "property", element_name, error))
3577 : : {
3578 : 0 : state_switch (ctx, STATE_INTERFACE);
3579 : : }
3580 : 0 : break;
3581 : :
3582 : 0 : case STATE_INTERFACE_FIELD:
3583 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3584 : 0 : break;
3585 [ # # ]: 0 : if (require_end_element (context, ctx, "field", element_name, error))
3586 : : {
3587 : 0 : state_switch (ctx, STATE_INTERFACE);
3588 : : }
3589 : 0 : break;
3590 : :
3591 : 0 : case STATE_INTERFACE:
3592 [ # # ]: 0 : if (require_end_element (context, ctx, "interface", element_name, error))
3593 : : {
3594 : 0 : pop_node (ctx);
3595 : 0 : state_switch (ctx, STATE_NAMESPACE);
3596 : : }
3597 : 0 : break;
3598 : :
3599 : 0 : case STATE_ENUM:
3600 [ # # ]: 0 : if (strcmp ("member", element_name) == 0)
3601 : 0 : break;
3602 [ # # ]: 0 : else if (strcmp ("function", element_name) == 0)
3603 : 0 : break;
3604 [ # # ]: 0 : else if (require_one_of_end_elements (context, ctx,
3605 : : element_name, error, "enumeration",
3606 : : "bitfield", NULL))
3607 : : {
3608 : 0 : pop_node (ctx);
3609 : 0 : state_switch (ctx, STATE_NAMESPACE);
3610 : : }
3611 : 0 : break;
3612 : :
3613 : 0 : case STATE_BOXED:
3614 [ # # ]: 0 : if (require_end_element (context, ctx, "glib:boxed", element_name, error))
3615 : : {
3616 : 0 : pop_node (ctx);
3617 : 0 : state_switch (ctx, STATE_NAMESPACE);
3618 : : }
3619 : 0 : break;
3620 : :
3621 : 0 : case STATE_BOXED_FIELD:
3622 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3623 : 0 : break;
3624 [ # # ]: 0 : if (require_end_element (context, ctx, "field", element_name, error))
3625 : : {
3626 : 0 : state_switch (ctx, STATE_BOXED);
3627 : : }
3628 : 0 : break;
3629 : :
3630 : 0 : case STATE_STRUCT_FIELD:
3631 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3632 : 0 : break;
3633 [ # # ]: 0 : if (require_end_element (context, ctx, "field", element_name, error))
3634 : : {
3635 : 0 : state_switch (ctx, STATE_STRUCT);
3636 : : }
3637 : 0 : break;
3638 : :
3639 : 0 : case STATE_STRUCT:
3640 [ # # ]: 0 : if (require_end_element (context, ctx, "record", element_name, error))
3641 : : {
3642 : 0 : state_switch_end_struct_or_union (context, ctx, element_name, error);
3643 : : }
3644 : 0 : break;
3645 : :
3646 : 0 : case STATE_UNION_FIELD:
3647 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3648 : 0 : break;
3649 [ # # ]: 0 : if (require_end_element (context, ctx, "field", element_name, error))
3650 : : {
3651 : 0 : state_switch (ctx, STATE_UNION);
3652 : : }
3653 : 0 : break;
3654 : :
3655 : 0 : case STATE_UNION:
3656 [ # # ]: 0 : if (require_end_element (context, ctx, "union", element_name, error))
3657 : : {
3658 : 0 : state_switch_end_struct_or_union (context, ctx, element_name, error);
3659 : : }
3660 : 0 : break;
3661 : 0 : case STATE_IMPLEMENTS:
3662 [ # # ]: 0 : if (strcmp ("interface", element_name) == 0)
3663 : 0 : break;
3664 [ # # ]: 0 : if (require_end_element (context, ctx, "implements", element_name, error))
3665 : 0 : state_switch (ctx, STATE_CLASS);
3666 : 0 : break;
3667 : 0 : case STATE_PREREQUISITE:
3668 [ # # ]: 0 : if (require_end_element (context, ctx, "prerequisite", element_name, error))
3669 : 0 : state_switch (ctx, STATE_INTERFACE);
3670 : 0 : break;
3671 : 0 : case STATE_NAMESPACE_CONSTANT:
3672 : : case STATE_CLASS_CONSTANT:
3673 : : case STATE_INTERFACE_CONSTANT:
3674 [ # # ]: 0 : if (strcmp ("type", element_name) == 0)
3675 : 0 : break;
3676 [ # # ]: 0 : if (require_end_element (context, ctx, "constant", element_name, error))
3677 : : {
3678 [ # # # # ]: 0 : switch (ctx->state)
3679 : : {
3680 : 0 : case STATE_NAMESPACE_CONSTANT:
3681 : 0 : pop_node (ctx);
3682 : 0 : state_switch (ctx, STATE_NAMESPACE);
3683 : 0 : break;
3684 : 0 : case STATE_CLASS_CONSTANT:
3685 : 0 : state_switch (ctx, STATE_CLASS);
3686 : 0 : break;
3687 : 0 : case STATE_INTERFACE_CONSTANT:
3688 : 0 : state_switch (ctx, STATE_INTERFACE);
3689 : 0 : break;
3690 : 0 : default:
3691 : : g_assert_not_reached ();
3692 : : break;
3693 : : }
3694 : : }
3695 : 0 : break;
3696 : 0 : case STATE_TYPE:
3697 [ # # # # ]: 0 : if ((strcmp ("type", element_name) == 0) || (strcmp ("array", element_name) == 0) ||
3698 [ # # ]: 0 : (strcmp ("varargs", element_name) == 0))
3699 : : {
3700 : 0 : end_type (ctx);
3701 : : }
3702 : 0 : break;
3703 : 0 : case STATE_ATTRIBUTE:
3704 [ # # ]: 0 : if (strcmp ("attribute", element_name) == 0)
3705 : : {
3706 : 0 : state_switch (ctx, ctx->prev_state);
3707 : : }
3708 : 0 : break;
3709 : :
3710 : 0 : case STATE_PASSTHROUGH:
3711 : 0 : ctx->unknown_depth -= 1;
3712 : 0 : g_assert (ctx->unknown_depth >= 0);
3713 [ # # ]: 0 : if (ctx->unknown_depth == 0)
3714 : 0 : state_switch (ctx, ctx->prev_state);
3715 : 0 : break;
3716 : 0 : default:
3717 : 0 : g_error ("Unhandled state %d in end_element_handler", ctx->state);
3718 : : }
3719 : 0 : }
3720 : :
3721 : : static void
3722 : 0 : text_handler (GMarkupParseContext *context,
3723 : : const char *text,
3724 : : gsize text_len,
3725 : : gpointer user_data,
3726 : : GError **error)
3727 : : {
3728 : : /* FIXME warn about non-whitespace text */
3729 : 0 : }
3730 : :
3731 : : static void
3732 : 0 : cleanup (GMarkupParseContext *context,
3733 : : GError *error,
3734 : : void *user_data)
3735 : : {
3736 : 0 : ParseContext *ctx = user_data;
3737 : : GList *m;
3738 : :
3739 [ # # ]: 0 : for (m = ctx->modules; m; m = m->next)
3740 : 0 : gi_ir_module_free (m->data);
3741 : 0 : g_list_free (ctx->modules);
3742 : 0 : ctx->modules = NULL;
3743 : :
3744 : 0 : ctx->current_module = NULL;
3745 : 0 : }
3746 : :
3747 : : /**
3748 : : * gi_ir_parser_parse_string:
3749 : : * @parser: a #GIIrParser
3750 : : * @namespace: the namespace of the string
3751 : : * @filename: (nullable) (type filename): Path to parsed file, or `NULL`
3752 : : * @buffer: (array length=length): the data containing the XML
3753 : : * @length: length of the data, in bytes
3754 : : * @error: return location for a [type@GLib.Error], or `NULL`
3755 : : *
3756 : : * Parse a string that holds a complete GIR XML file, and return a list of a
3757 : : * a [class@GIRepository.IrModule] for each `<namespace/>` element within the
3758 : : * file.
3759 : : *
3760 : : * Returns: (transfer none): a new [class@GIRepository.IrModule]
3761 : : * Since: 2.80
3762 : : */
3763 : : GIIrModule *
3764 : 0 : gi_ir_parser_parse_string (GIIrParser *parser,
3765 : : const char *namespace,
3766 : : const char *filename,
3767 : : const char *buffer,
3768 : : gssize length,
3769 : : GError **error)
3770 : : {
3771 : 0 : ParseContext ctx = { 0 };
3772 : : GMarkupParseContext *context;
3773 : :
3774 : 0 : ctx.parser = parser;
3775 : 0 : ctx.state = STATE_START;
3776 : 0 : ctx.file_path = filename;
3777 : 0 : ctx.namespace = namespace;
3778 : 0 : ctx.include_modules = NULL;
3779 : 0 : ctx.aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
3780 : 0 : ctx.disguised_structures = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
3781 : 0 : ctx.pointer_structures = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
3782 : 0 : ctx.type_depth = 0;
3783 : 0 : ctx.dependencies = NULL;
3784 : 0 : ctx.current_module = NULL;
3785 : :
3786 : 0 : context = g_markup_parse_context_new (&firstpass_parser, 0, &ctx, NULL);
3787 : :
3788 [ # # ]: 0 : if (!g_markup_parse_context_parse (context, buffer, length, error))
3789 : 0 : goto out;
3790 : :
3791 [ # # ]: 0 : if (!g_markup_parse_context_end_parse (context, error))
3792 : 0 : goto out;
3793 : :
3794 : 0 : g_markup_parse_context_free (context);
3795 : :
3796 : 0 : ctx.state = STATE_START;
3797 : 0 : context = g_markup_parse_context_new (&markup_parser, 0, &ctx, NULL);
3798 [ # # ]: 0 : if (!g_markup_parse_context_parse (context, buffer, length, error))
3799 : 0 : goto out;
3800 : :
3801 [ # # ]: 0 : if (!g_markup_parse_context_end_parse (context, error))
3802 : 0 : goto out;
3803 : :
3804 : 0 : parser->parsed_modules = g_list_concat (g_list_copy (ctx.modules),
3805 : : parser->parsed_modules);
3806 : :
3807 : 0 : out:
3808 : :
3809 [ # # ]: 0 : if (ctx.modules == NULL)
3810 : : {
3811 : : /* An error occurred before we created a module, so we haven't
3812 : : * transferred ownership of these hash tables to the module.
3813 : : */
3814 : 0 : g_clear_pointer (&ctx.aliases, g_hash_table_unref);
3815 : 0 : g_clear_pointer (&ctx.disguised_structures, g_hash_table_unref);
3816 : 0 : g_clear_pointer (&ctx.pointer_structures, g_hash_table_unref);
3817 : 0 : g_list_free (ctx.include_modules);
3818 : : }
3819 : :
3820 : 0 : g_markup_parse_context_free (context);
3821 : :
3822 [ # # ]: 0 : if (ctx.modules)
3823 : 0 : return ctx.modules->data;
3824 : :
3825 [ # # # # ]: 0 : if (error && *error == NULL)
3826 : 0 : g_set_error (error,
3827 : : G_MARKUP_ERROR,
3828 : : G_MARKUP_ERROR_INVALID_CONTENT,
3829 : : "Expected namespace element in the gir file");
3830 : 0 : return NULL;
3831 : : }
3832 : :
3833 : : /**
3834 : : * gi_ir_parser_parse_file:
3835 : : * @parser: a #GIIrParser
3836 : : * @filename: (type filename): filename to parse
3837 : : * @error: return location for a [type@GLib.Error], or `NULL`
3838 : : *
3839 : : * Parse the given GIR XML file, and return a list of a
3840 : : * [class@GIRepository.IrModule] for each `<namespace/>` element within the
3841 : : * file.
3842 : : *
3843 : : * Returns: (transfer container): a newly allocated list of
3844 : : * [class@GIRepository.IrModule]s. The modules themselves
3845 : : * are owned by the `GIIrParser` and will be freed along with the parser.
3846 : : * Since: 2.80
3847 : : */
3848 : : GIIrModule *
3849 : 0 : gi_ir_parser_parse_file (GIIrParser *parser,
3850 : : const char *filename,
3851 : : GError **error)
3852 : : {
3853 : : char *buffer;
3854 : : gsize length;
3855 : : GIIrModule *module;
3856 : : char *dash;
3857 : : char *namespace;
3858 : :
3859 [ # # # # : 0 : if (!g_str_has_suffix (filename, ".gir"))
# # # # ]
3860 : : {
3861 : 0 : g_set_error (error,
3862 : : G_MARKUP_ERROR,
3863 : : G_MARKUP_ERROR_INVALID_CONTENT,
3864 : : "Expected filename to end with '.gir'");
3865 : 0 : return NULL;
3866 : : }
3867 : :
3868 : 0 : g_debug ("[parsing] filename %s", filename);
3869 : :
3870 : 0 : namespace = g_path_get_basename (filename);
3871 : 0 : namespace[strlen(namespace)-4] = '\0';
3872 : :
3873 : : /* Remove version */
3874 : 0 : dash = strstr (namespace, "-");
3875 [ # # ]: 0 : if (dash != NULL)
3876 : 0 : *dash = '\0';
3877 : :
3878 [ # # ]: 0 : if (!g_file_get_contents (filename, &buffer, &length, error))
3879 : : {
3880 : 0 : g_free (namespace);
3881 : :
3882 : 0 : return NULL;
3883 : : }
3884 : :
3885 : 0 : module = gi_ir_parser_parse_string (parser, namespace, filename, buffer, length, error);
3886 : :
3887 : 0 : g_free (namespace);
3888 : :
3889 : 0 : g_free (buffer);
3890 : :
3891 : 0 : return module;
3892 : : }
3893 : :
3894 : :
|