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