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