summaryrefslogtreecommitdiff
path: root/gobject-introspection
diff options
context:
space:
mode:
authorJuerg Billeter <j@bitron.ch>2007-10-26 20:59:25 +0000
committerJürg Billeter <juergbi@src.gnome.org>2007-10-26 20:59:25 +0000
commitb70d052df1bf77610071dbe63f2172d8fd03aaa4 (patch)
tree8bc6345ed694ed71c3e0be8a9626f67bc0526f25 /gobject-introspection
parent2f09eebafae54d18cc599e7b73137caddc63ede6 (diff)
downloadvala-b70d052df1bf77610071dbe63f2172d8fd03aaa4.tar.gz
add gen-introspect from gobject-introspection git
2007-10-26 Juerg Billeter <j@bitron.ch> * configure.ac, gobject-introspection/Makefile.am, gobject-introspection/clexer.l, gobject-introspection/cparser.y, gobject-introspection/gen-introspect.c, gobject-introspection/gen-introspect.h: add gen-introspect from gobject-introspection git svn path=/trunk/; revision=660
Diffstat (limited to 'gobject-introspection')
-rw-r--r--gobject-introspection/Makefile.am19
-rw-r--r--gobject-introspection/clexer.l246
-rw-r--r--gobject-introspection/cparser.y1215
-rw-r--r--gobject-introspection/gen-introspect.c1323
-rw-r--r--gobject-introspection/gen-introspect.h157
5 files changed, 2960 insertions, 0 deletions
diff --git a/gobject-introspection/Makefile.am b/gobject-introspection/Makefile.am
index c59842419..2b982289d 100644
--- a/gobject-introspection/Makefile.am
+++ b/gobject-introspection/Makefile.am
@@ -22,4 +22,23 @@ libgidl_la_LIBADD = \
$(GLIB_LIBS) \
$(NULL)
+pkglibexecdir = $(libdir)/vala
+pkglibexec_PROGRAMS = gen-introspect
+
+BUILT_SOURCES = cparser.h
+AM_YFLAGS = -d
+
+gen_introspect_SOURCES = \
+ clexer.l \
+ cparser.y \
+ gen-introspect.c \
+ gen-introspect.h \
+ $(NULL)
+
+gen_introspect_LDADD = \
+ $(GLIB_LIBS) \
+ $(GMODULE_LIBS) \
+ libgidl.la \
+ $(NULL)
+
EXTRA_DIST = gidl.vapi
diff --git a/gobject-introspection/clexer.l b/gobject-introspection/clexer.l
new file mode 100644
index 000000000..9218ae7fc
--- /dev/null
+++ b/gobject-introspection/clexer.l
@@ -0,0 +1,246 @@
+/* GObject introspection: C lexer
+ *
+ * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it>
+ * Copyright (c) 2007 Jürg Billeter <j@bitron.ch>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include <ctype.h>
+#include <stdio.h>
+
+#include "gen-introspect.h"
+#include "cparser.h"
+
+int lineno;
+
+static int yywrap (void);
+static void skip_comment (void);
+static void process_directive (void);
+static int check_identifier (const char *);
+%}
+
+intsuffix ([uU][lL]?)|([lL][uU]?)
+fracconst ([0-9]*\.[0-9]+)|([0-9]+\.)
+exppart [eE][-+]?[0-9]+
+floatsuffix [fFlL]
+chartext ([^'])|(\\.)
+stringtext ([^"])|(\\.)
+
+%%
+
+"\n" { ++lineno; }
+[\t\f\v\r ]+ { /* Ignore whitespace. */ }
+
+"/*" { skip_comment(); }
+"//".* { }
+
+"#define "[a-zA-Z_][a-zA-Z_0-9]*"(" { yyless (yyleng - 1); return FUNCTION_MACRO; }
+"#define "[a-zA-Z_][a-zA-Z_0-9]* { return OBJECT_MACRO; }
+
+"#" { process_directive(); }
+
+"{" { return '{'; }
+"<%" { return '{'; }
+"}" { return '}'; }
+"%>" { return '}'; }
+"[" { return '['; }
+"<:" { return '['; }
+"]" { return ']'; }
+":>" { return ']'; }
+"(" { return '('; }
+")" { return ')'; }
+";" { return ';'; }
+":" { return ':'; }
+"..." { return ELLIPSIS; }
+"?" { return '?'; }
+"." { return '.'; }
+"+" { return '+'; }
+"-" { return '-'; }
+"*" { return '*'; }
+"/" { return '/'; }
+"%" { return '%'; }
+"^" { return '^'; }
+"&" { return '&'; }
+"|" { return '|'; }
+"~" { return '~'; }
+"!" { return '!'; }
+"=" { return '='; }
+"<" { return '<'; }
+">" { return '>'; }
+"+=" { return ADDEQ; }
+"-=" { return SUBEQ; }
+"*=" { return MULEQ; }
+"/=" { return DIVEQ; }
+"%=" { return MODEQ; }
+"^=" { return XOREQ; }
+"&=" { return ANDEQ; }
+"|=" { return OREQ; }
+"<<" { return SL; }
+">>" { return SR; }
+"<<=" { return SLEQ; }
+">>=" { return SREQ; }
+"==" { return EQ; }
+"!=" { return NOTEQ; }
+"<=" { return LTEQ; }
+">=" { return GTEQ; }
+"&&" { return ANDAND; }
+"||" { return OROR; }
+"++" { return PLUSPLUS; }
+"--" { return MINUSMINUS; }
+"," { return ','; }
+"->" { return ARROW; }
+
+[a-zA-Z_][a-zA-Z_0-9]* { if (the_igenerator->macro_scan) return IDENTIFIER; else REJECT; }
+
+"auto" { return AUTO; }
+"break" { return BREAK; }
+"case" { return CASE; }
+"char" { return CHAR; }
+"const" { return CONST; }
+"continue" { return CONTINUE; }
+"default" { return DEFAULT; }
+"do" { return DO; }
+"double" { return DOUBLE; }
+"else" { return ELSE; }
+"enum" { return ENUM; }
+"extern" { return EXTERN; }
+"float" { return FLOAT; }
+"for" { return FOR; }
+"goto" { return GOTO; }
+"if" { return IF; }
+"inline" { return INLINE; }
+"int" { return INT; }
+"long" { return LONG; }
+"register" { return REGISTER; }
+"restrict" { return RESTRICT; }
+"return" { return RETURN; }
+"short" { return SHORT; }
+"signed" { return SIGNED; }
+"sizeof" { return SIZEOF; }
+"static" { return STATIC; }
+"struct" { return STRUCT; }
+"switch" { return SWITCH; }
+"typedef" { return TYPEDEF; }
+"union" { return UNION; }
+"unsigned" { return UNSIGNED; }
+"void" { return VOID; }
+"volatile" { return VOLATILE; }
+"while" { return WHILE; }
+
+[a-zA-Z_][a-zA-Z_0-9]* { return check_identifier(yytext); }
+
+"0"[xX][0-9a-fA-F]+{intsuffix}? { return INTEGER; }
+"0"[0-7]+{intsuffix}? { return INTEGER; }
+[0-9]+{intsuffix}? { return INTEGER; }
+
+{fracconst}{exppart}?{floatsuffix}? { return FLOATING; }
+[0-9]+{exppart}{floatsuffix}? { return FLOATING; }
+
+"'"{chartext}*"'" { return CHARACTER; }
+"L'"{chartext}*"'" { return CHARACTER; }
+
+"\""{stringtext}*"\"" { return STRING; }
+"L\""{stringtext}*"\"" { return STRING; }
+
+. { fprintf(stderr, "%d: unexpected character `%c'\n", lineno, yytext[0]); }
+
+%%
+
+static int yywrap (void)
+{
+ return 1;
+}
+
+static void skip_comment (void)
+{
+ int c1, c2;
+
+ c1 = input();
+ c2 = input();
+
+ while (c2 != EOF && !(c1 == '*' && c2 == '/')) {
+ if (c1 == '\n')
+ ++lineno;
+ c1 = c2;
+ c2 = input();
+ }
+}
+
+static int check_identifier (const char *s)
+{
+ /*
+ * This function checks if `s' is a type name or an
+ * identifier.
+ */
+
+ if (g_igenerator_is_typedef (the_igenerator, s)) {
+ return TYPEDEF_NAME;
+ } else if (strcmp (s, "__builtin_va_list") == 0) {
+ return TYPEDEF_NAME;
+ }
+
+ return IDENTIFIER;
+}
+
+static void process_directive (void)
+{
+ /* extract current filename from #line directives */
+ GString *filename_builder;
+ gboolean in_string;
+
+ in_string = FALSE;
+ filename_builder = g_string_new ("");
+
+ int c = input ();
+ while (c != EOF && c != '\n') {
+ if (!in_string) {
+ if (c == '\"') {
+ in_string = TRUE;
+ }
+ } else {
+ if (c == '\"') {
+ in_string = FALSE;
+ } else if (c == '\\') {
+ g_string_append_c (filename_builder, c);
+ c = input ();
+ g_string_append_c (filename_builder, c);
+ } else {
+ g_string_append_c (filename_builder, c);
+ }
+ }
+ c = input ();
+ }
+ ++lineno;
+
+ if (filename_builder->len > 0) {
+ char *filename = g_strcompress (filename_builder->str);
+ g_free (the_igenerator->current_filename);
+ the_igenerator->current_filename = g_path_get_basename (filename);
+ g_free (filename);
+ }
+
+ g_string_free (filename_builder, TRUE);
+}
+
diff --git a/gobject-introspection/cparser.y b/gobject-introspection/cparser.y
new file mode 100644
index 000000000..a1f87be36
--- /dev/null
+++ b/gobject-introspection/cparser.y
@@ -0,0 +1,1215 @@
+/* GObject introspection: C parser
+ *
+ * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it>
+ * Copyright (c) 2007 Jürg Billeter <j@bitron.ch>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gen-introspect.h"
+
+extern FILE *yyin;
+extern int lineno;
+extern char *yytext;
+
+extern int yylex (void);
+static void yyerror(const char *s);
+
+static int last_enum_value = -1;
+static GHashTable *const_table = NULL;
+
+/* use specified type as base type of symbol */
+static void csymbol_merge_type (CSymbol *symbol, CType *type)
+{
+ CType **foundation_type = &(symbol->base_type);
+ while (*foundation_type != NULL) {
+ foundation_type = &((*foundation_type)->base_type);
+ }
+ *foundation_type = ctype_copy (type);
+}
+%}
+
+%error-verbose
+%union {
+ char *str;
+ GList *list;
+ CSymbol *symbol;
+ CType *ctype;
+ StorageClassSpecifier storage_class_specifier;
+ TypeQualifier type_qualifier;
+ FunctionSpecifier function_specifier;
+ UnaryOperator unary_operator;
+}
+
+%token <str> IDENTIFIER "identifier"
+%token <str> TYPEDEF_NAME "typedef-name"
+
+%token INTEGER FLOATING CHARACTER STRING
+
+%token ELLIPSIS ADDEQ SUBEQ MULEQ DIVEQ MODEQ XOREQ ANDEQ OREQ SL SR
+%token SLEQ SREQ EQ NOTEQ LTEQ GTEQ ANDAND OROR PLUSPLUS MINUSMINUS ARROW
+
+%token AUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM
+%token EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT RETURN SHORT
+%token SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE
+%token WHILE
+
+%token FUNCTION_MACRO OBJECT_MACRO
+
+%start translation_unit
+
+%type <ctype> declaration_specifiers
+%type <ctype> enum_specifier
+%type <ctype> pointer
+%type <ctype> specifier_qualifier_list
+%type <ctype> struct_or_union
+%type <ctype> struct_or_union_specifier
+%type <ctype> type_specifier
+%type <str> identifier
+%type <str> typedef_name
+%type <str> identifier_or_typedef_name
+%type <symbol> abstract_declarator
+%type <symbol> init_declarator
+%type <symbol> declarator
+%type <symbol> enumerator
+%type <symbol> direct_abstract_declarator
+%type <symbol> direct_declarator
+%type <symbol> parameter_declaration
+%type <symbol> struct_declarator
+%type <list> enumerator_list
+%type <list> identifier_list
+%type <list> init_declarator_list
+%type <list> parameter_type_list
+%type <list> parameter_list
+%type <list> struct_declaration
+%type <list> struct_declaration_list
+%type <list> struct_declarator_list
+%type <storage_class_specifier> storage_class_specifier
+%type <type_qualifier> type_qualifier
+%type <type_qualifier> type_qualifier_list
+%type <function_specifier> function_specifier
+%type <symbol> expression
+%type <symbol> constant_expression
+%type <symbol> conditional_expression
+%type <symbol> logical_and_expression
+%type <symbol> logical_or_expression
+%type <symbol> inclusive_or_expression
+%type <symbol> exclusive_or_expression
+%type <symbol> multiplicative_expression
+%type <symbol> additive_expression
+%type <symbol> shift_expression
+%type <symbol> relational_expression
+%type <symbol> equality_expression
+%type <symbol> and_expression
+%type <symbol> cast_expression
+%type <symbol> assignment_expression
+%type <symbol> unary_expression
+%type <symbol> postfix_expression
+%type <symbol> primary_expression
+%type <unary_operator> unary_operator
+%type <str> function_macro
+%type <str> object_macro
+
+%%
+
+/* A.2.1 Expressions. */
+
+primary_expression
+ : identifier
+ {
+ $$ = g_hash_table_lookup (const_table, $1);
+ if ($$ == NULL) {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ }
+ | INTEGER
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
+ $$->const_int = strtol (yytext + 2, NULL, 16);
+ } else if (g_str_has_prefix (yytext, "0") && strlen (yytext) > 1) {
+ $$->const_int = strtol (yytext + 1, NULL, 8);
+ } else {
+ $$->const_int = atoi (yytext);
+ }
+ }
+ | CHARACTER
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | FLOATING
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | STRING
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ yytext[strlen (yytext) - 1] = '\0';
+ $$->const_string = g_strcompress (yytext + 1);
+ }
+ | '(' expression ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+identifier
+ : IDENTIFIER
+ {
+ $$ = g_strdup (yytext);
+ }
+ ;
+
+identifier_or_typedef_name
+ : identifier
+ | typedef_name
+ ;
+
+postfix_expression
+ : primary_expression
+ | postfix_expression '[' expression ']'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression '(' argument_expression_list ')'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression '(' ')'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression '.' identifier_or_typedef_name
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression ARROW identifier_or_typedef_name
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression PLUSPLUS
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression MINUSMINUS
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+argument_expression_list
+ : assignment_expression
+ | argument_expression_list ',' assignment_expression
+ ;
+
+unary_expression
+ : postfix_expression
+ | PLUSPLUS unary_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | MINUSMINUS unary_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | unary_operator cast_expression
+ {
+ switch ($1) {
+ case UNARY_PLUS:
+ $$ = $2;
+ break;
+ case UNARY_MINUS:
+ $$ = $2;
+ $$->const_int = -$2->const_int;
+ break;
+ case UNARY_BITWISE_COMPLEMENT:
+ $$ = $2;
+ $$->const_int = ~$2->const_int;
+ break;
+ case UNARY_LOGICAL_NEGATION:
+ $$ = $2;
+ $$->const_int = !csymbol_get_const_boolean ($2);
+ break;
+ default:
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ break;
+ }
+ }
+ | SIZEOF unary_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | SIZEOF '(' type_name ')'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+unary_operator
+ : '&'
+ {
+ $$ = UNARY_ADDRESS_OF;
+ }
+ | '*'
+ {
+ $$ = UNARY_POINTER_INDIRECTION;
+ }
+ | '+'
+ {
+ $$ = UNARY_PLUS;
+ }
+ | '-'
+ {
+ $$ = UNARY_MINUS;
+ }
+ | '~'
+ {
+ $$ = UNARY_BITWISE_COMPLEMENT;
+ }
+ | '!'
+ {
+ $$ = UNARY_LOGICAL_NEGATION;
+ }
+ ;
+
+cast_expression
+ : unary_expression
+ | '(' type_name ')' cast_expression
+ {
+ $$ = $4;
+ }
+ ;
+
+multiplicative_expression
+ : cast_expression
+ | multiplicative_expression '*' cast_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int * $3->const_int;
+ }
+ | multiplicative_expression '/' cast_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ if ($3->const_int != 0) {
+ $$->const_int = $1->const_int / $3->const_int;
+ }
+ }
+ | multiplicative_expression '%' cast_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int % $3->const_int;
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression
+ | additive_expression '+' multiplicative_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int + $3->const_int;
+ }
+ | additive_expression '-' multiplicative_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int - $3->const_int;
+ }
+ ;
+
+shift_expression
+ : additive_expression
+ | shift_expression SL additive_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int << $3->const_int;
+ }
+ | shift_expression SR additive_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int >> $3->const_int;
+ }
+ ;
+
+relational_expression
+ : shift_expression
+ | relational_expression '<' shift_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int < $3->const_int;
+ }
+ | relational_expression '>' shift_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int > $3->const_int;
+ }
+ | relational_expression LTEQ shift_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int <= $3->const_int;
+ }
+ | relational_expression GTEQ shift_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int >= $3->const_int;
+ }
+ ;
+
+equality_expression
+ : relational_expression
+ | equality_expression EQ relational_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int == $3->const_int;
+ }
+ | equality_expression NOTEQ relational_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int != $3->const_int;
+ }
+ ;
+
+and_expression
+ : equality_expression
+ | and_expression '&' equality_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int & $3->const_int;
+ }
+ ;
+
+exclusive_or_expression
+ : and_expression
+ | exclusive_or_expression '^' and_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int ^ $3->const_int;
+ }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression
+ | inclusive_or_expression '|' exclusive_or_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int | $3->const_int;
+ }
+ ;
+
+logical_and_expression
+ : inclusive_or_expression
+ | logical_and_expression ANDAND inclusive_or_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = csymbol_get_const_boolean ($1) && csymbol_get_const_boolean ($3);
+ }
+ ;
+
+logical_or_expression
+ : logical_and_expression
+ | logical_or_expression OROR logical_and_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = csymbol_get_const_boolean ($1) || csymbol_get_const_boolean ($3);
+ }
+ ;
+
+conditional_expression
+ : logical_or_expression
+ | logical_or_expression '?' expression ':' conditional_expression
+ {
+ $$ = csymbol_get_const_boolean ($1) ? $3 : $5;
+ }
+ ;
+
+assignment_expression
+ : conditional_expression
+ | unary_expression assignment_operator assignment_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+assignment_operator
+ : '='
+ | MULEQ
+ | DIVEQ
+ | MODEQ
+ | ADDEQ
+ | SUBEQ
+ | SLEQ
+ | SREQ
+ | ANDEQ
+ | XOREQ
+ | OREQ
+ ;
+
+expression
+ : assignment_expression
+ | expression ',' assignment_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+constant_expression
+ : conditional_expression
+ ;
+
+/* A.2.2 Declarations. */
+
+declaration
+ : declaration_specifiers init_declarator_list ';'
+ {
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ CSymbol *sym = l->data;
+ csymbol_merge_type (sym, $1);
+ if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
+ sym->type = CSYMBOL_TYPE_TYPEDEF;
+ } else if (sym->base_type->type == CTYPE_FUNCTION) {
+ sym->type = CSYMBOL_TYPE_FUNCTION;
+ } else {
+ sym->type = CSYMBOL_TYPE_OBJECT;
+ }
+ g_igenerator_add_symbol (the_igenerator, sym);
+ }
+ }
+ | declaration_specifiers ';'
+ ;
+
+declaration_specifiers
+ : storage_class_specifier declaration_specifiers
+ {
+ $$ = $2;
+ $$->storage_class_specifier |= $1;
+ }
+ | storage_class_specifier
+ {
+ $$ = ctype_new (CTYPE_INVALID);
+ $$->storage_class_specifier |= $1;
+ }
+ | type_specifier declaration_specifiers
+ {
+ $$ = $1;
+ $$->base_type = $2;
+ }
+ | type_specifier
+ | type_qualifier declaration_specifiers
+ {
+ $$ = $2;
+ $$->type_qualifier |= $1;
+ }
+ | type_qualifier
+ {
+ $$ = ctype_new (CTYPE_INVALID);
+ $$->type_qualifier |= $1;
+ }
+ | function_specifier declaration_specifiers
+ {
+ $$ = $2;
+ $$->function_specifier |= $1;
+ }
+ | function_specifier
+ {
+ $$ = ctype_new (CTYPE_INVALID);
+ $$->function_specifier |= $1;
+ }
+ ;
+
+init_declarator_list
+ : init_declarator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | init_declarator_list ',' init_declarator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+init_declarator
+ : declarator
+ | declarator '=' initializer
+ ;
+
+storage_class_specifier
+ : TYPEDEF
+ {
+ $$ = STORAGE_CLASS_TYPEDEF;
+ }
+ | EXTERN
+ {
+ $$ = STORAGE_CLASS_EXTERN;
+ }
+ | STATIC
+ {
+ $$ = STORAGE_CLASS_STATIC;
+ }
+ | AUTO
+ {
+ $$ = STORAGE_CLASS_AUTO;
+ }
+ | REGISTER
+ {
+ $$ = STORAGE_CLASS_REGISTER;
+ }
+ ;
+
+type_specifier
+ : VOID
+ {
+ $$ = ctype_new (CTYPE_VOID);
+ }
+ | CHAR
+ {
+ $$ = cbasic_type_new ("char");
+ }
+ | SHORT
+ {
+ $$ = cbasic_type_new ("short");
+ }
+ | INT
+ {
+ $$ = cbasic_type_new ("int");
+ }
+ | LONG
+ {
+ $$ = cbasic_type_new ("long");
+ }
+ | FLOAT
+ {
+ $$ = cbasic_type_new ("float");
+ }
+ | DOUBLE
+ {
+ $$ = cbasic_type_new ("double");
+ }
+ | SIGNED
+ {
+ $$ = cbasic_type_new ("signed");
+ }
+ | UNSIGNED
+ {
+ $$ = cbasic_type_new ("unsigned");
+ }
+ | struct_or_union_specifier
+ | enum_specifier
+ | typedef_name
+ {
+ $$ = ctypedef_new ($1);
+ }
+ ;
+
+struct_or_union_specifier
+ : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
+ {
+ $$ = $1;
+ $$->name = $2;
+ $$->child_list = $4;
+
+ CSymbol *sym = csymbol_new (CSYMBOL_TYPE_INVALID);
+ if ($$->type == CTYPE_STRUCT) {
+ sym->type = CSYMBOL_TYPE_STRUCT;
+ } else if ($$->type == CTYPE_UNION) {
+ sym->type = CSYMBOL_TYPE_UNION;
+ } else {
+ g_assert_not_reached ();
+ }
+ sym->ident = g_strdup ($$->name);
+ sym->base_type = ctype_copy ($$);
+ g_igenerator_add_symbol (the_igenerator, sym);
+ }
+ | struct_or_union '{' struct_declaration_list '}'
+ {
+ $$ = $1;
+ $$->child_list = $3;
+ }
+ | struct_or_union identifier_or_typedef_name
+ {
+ $$ = $1;
+ $$->name = $2;
+ }
+ ;
+
+struct_or_union
+ : STRUCT
+ {
+ $$ = cstruct_new (NULL);
+ }
+ | UNION
+ {
+ $$ = cunion_new (NULL);
+ }
+ ;
+
+struct_declaration_list
+ : struct_declaration
+ | struct_declaration_list struct_declaration
+ {
+ $$ = g_list_concat ($1, $2);
+ }
+ ;
+
+struct_declaration
+ : specifier_qualifier_list struct_declarator_list ';'
+ {
+ GList *l;
+ $$ = NULL;
+ for (l = $2; l != NULL; l = l->next) {
+ CSymbol *sym = l->data;
+ if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
+ sym->type = CSYMBOL_TYPE_TYPEDEF;
+ }
+ csymbol_merge_type (sym, $1);
+ $$ = g_list_append ($$, sym);
+ }
+ }
+ ;
+
+specifier_qualifier_list
+ : type_specifier specifier_qualifier_list
+ {
+ $$ = $1;
+ $$->base_type = $2;
+ }
+ | type_specifier
+ | type_qualifier specifier_qualifier_list
+ {
+ $$ = $2;
+ $$->type_qualifier |= $1;
+ }
+ | type_qualifier
+ {
+ $$ = ctype_new (CTYPE_INVALID);
+ $$->type_qualifier |= $1;
+ }
+ ;
+
+struct_declarator_list
+ : struct_declarator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | struct_declarator_list ',' struct_declarator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+struct_declarator
+ : declarator
+ | ':' constant_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | declarator ':' constant_expression
+ ;
+
+enum_specifier
+ : ENUM identifier_or_typedef_name '{' enumerator_list '}'
+ {
+ $$ = cenum_new ($2);
+ $$->child_list = $4;
+ last_enum_value = -1;
+ }
+ | ENUM '{' enumerator_list '}'
+ {
+ $$ = cenum_new (NULL);
+ $$->child_list = $3;
+ last_enum_value = -1;
+ }
+ | ENUM identifier_or_typedef_name '{' enumerator_list ',' '}'
+ {
+ $$ = cenum_new ($2);
+ $$->child_list = $4;
+ last_enum_value = -1;
+ }
+ | ENUM '{' enumerator_list ',' '}'
+ {
+ $$ = cenum_new (NULL);
+ $$->child_list = $3;
+ last_enum_value = -1;
+ }
+ | ENUM identifier_or_typedef_name
+ {
+ $$ = cenum_new ($2);
+ }
+ ;
+
+enumerator_list
+ : enumerator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | enumerator_list ',' enumerator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+enumerator
+ : identifier
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_OBJECT);
+ $$->ident = $1;
+ $$->const_int_set = TRUE;
+ $$->const_int = ++last_enum_value;
+ g_hash_table_insert (const_table, $$->ident, $$);
+ }
+ | identifier '=' constant_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_OBJECT);
+ $$->ident = $1;
+ $$->const_int_set = TRUE;
+ $$->const_int = $3->const_int;
+ last_enum_value = $$->const_int;
+ g_hash_table_insert (const_table, $$->ident, $$);
+ }
+ ;
+
+type_qualifier
+ : CONST
+ {
+ $$ = TYPE_QUALIFIER_CONST;
+ }
+ | RESTRICT
+ {
+ $$ = TYPE_QUALIFIER_RESTRICT;
+ }
+ | VOLATILE
+ {
+ $$ = TYPE_QUALIFIER_VOLATILE;
+ }
+ ;
+
+function_specifier
+ : INLINE
+ {
+ $$ = FUNCTION_INLINE;
+ }
+ ;
+
+declarator
+ : pointer direct_declarator
+ {
+ $$ = $2;
+ csymbol_merge_type ($$, $1);
+ }
+ | direct_declarator
+ ;
+
+direct_declarator
+ : identifier
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ $$->ident = $1;
+ }
+ | '(' declarator ')'
+ {
+ $$ = $2;
+ }
+ | direct_declarator '[' assignment_expression ']'
+ {
+ $$ = $1;
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | direct_declarator '[' ']'
+ {
+ $$ = $1;
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | direct_declarator '(' parameter_type_list ')'
+ {
+ CType *func = cfunction_new ();
+ // ignore (void) parameter list
+ if ($3 != NULL && ($3->next != NULL || ((CSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
+ func->child_list = $3;
+ }
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ | direct_declarator '(' identifier_list ')'
+ {
+ CType *func = cfunction_new ();
+ func->child_list = $3;
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ | direct_declarator '(' ')'
+ {
+ CType *func = cfunction_new ();
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ ;
+
+pointer
+ : '*' type_qualifier_list
+ {
+ $$ = cpointer_new (NULL);
+ $$->type_qualifier = $2;
+ }
+ | '*'
+ {
+ $$ = cpointer_new (NULL);
+ }
+ | '*' type_qualifier_list pointer
+ {
+ $$ = cpointer_new ($3);
+ $$->type_qualifier = $2;
+ }
+ | '*' pointer
+ {
+ $$ = cpointer_new ($2);
+ }
+ ;
+
+type_qualifier_list
+ : type_qualifier
+ | type_qualifier_list type_qualifier
+ {
+ $$ = $1 | $2;
+ }
+ ;
+
+parameter_type_list
+ : parameter_list
+ | parameter_list ',' ELLIPSIS
+ ;
+
+parameter_list
+ : parameter_declaration
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | parameter_list ',' parameter_declaration
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+parameter_declaration
+ : declaration_specifiers declarator
+ {
+ $$ = $2;
+ csymbol_merge_type ($$, $1);
+ }
+ | declaration_specifiers abstract_declarator
+ {
+ $$ = $2;
+ csymbol_merge_type ($$, $1);
+ }
+ | declaration_specifiers
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ $$->base_type = $1;
+ }
+ ;
+
+identifier_list
+ : identifier
+ {
+ CSymbol *sym = csymbol_new (CSYMBOL_TYPE_INVALID);
+ sym->ident = $1;
+ $$ = g_list_append (NULL, sym);
+ }
+ | identifier_list ',' identifier
+ {
+ CSymbol *sym = csymbol_new (CSYMBOL_TYPE_INVALID);
+ sym->ident = $3;
+ $$ = g_list_append ($1, sym);
+ }
+ ;
+
+type_name
+ : specifier_qualifier_list
+ | specifier_qualifier_list abstract_declarator
+ ;
+
+abstract_declarator
+ : pointer
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, $1);
+ }
+ | direct_abstract_declarator
+ | pointer direct_abstract_declarator
+ {
+ $$ = $2;
+ csymbol_merge_type ($$, $1);
+ }
+ ;
+
+direct_abstract_declarator
+ : '(' abstract_declarator ')'
+ {
+ $$ = $2;
+ }
+ | '[' ']'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | '[' assignment_expression ']'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | direct_abstract_declarator '[' ']'
+ {
+ $$ = $1;
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | direct_abstract_declarator '[' assignment_expression ']'
+ {
+ $$ = $1;
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | '(' ')'
+ {
+ CType *func = cfunction_new ();
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, func);
+ }
+ | '(' parameter_type_list ')'
+ {
+ CType *func = cfunction_new ();
+ // ignore (void) parameter list
+ if ($2 != NULL && ($2->next != NULL || ((CSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
+ func->child_list = $2;
+ }
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, func);
+ }
+ | direct_abstract_declarator '(' ')'
+ {
+ CType *func = cfunction_new ();
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ | direct_abstract_declarator '(' parameter_type_list ')'
+ {
+ CType *func = cfunction_new ();
+ // ignore (void) parameter list
+ if ($3 != NULL && ($3->next != NULL || ((CSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
+ func->child_list = $3;
+ }
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ ;
+
+typedef_name
+ : TYPEDEF_NAME
+ {
+ $$ = g_strdup (yytext);
+ }
+ ;
+
+initializer
+ : assignment_expression
+ | '{' initializer_list '}'
+ | '{' initializer_list ',' '}'
+ ;
+
+initializer_list
+ : initializer
+ | initializer_list ',' initializer
+ ;
+
+/* A.2.3 Statements. */
+
+statement
+ : labeled_statement
+ | compound_statement
+ | expression_statement
+ | selection_statement
+ | iteration_statement
+ | jump_statement
+ ;
+
+labeled_statement
+ : identifier_or_typedef_name ':' statement
+ | CASE constant_expression ':' statement
+ | DEFAULT ':' statement
+ ;
+
+compound_statement
+ : '{' '}'
+ | '{' block_item_list '}'
+ ;
+
+block_item_list
+ : block_item
+ | block_item_list block_item
+ ;
+
+block_item
+ : declaration
+ | statement
+ ;
+
+expression_statement
+ : ';'
+ | expression ';'
+ ;
+
+selection_statement
+ : IF '(' expression ')' statement
+ | IF '(' expression ')' statement ELSE statement
+ | SWITCH '(' expression ')' statement
+ ;
+
+iteration_statement
+ : WHILE '(' expression ')' statement
+ | DO statement WHILE '(' expression ')' ';'
+ | FOR '(' ';' ';' ')' statement
+ | FOR '(' expression ';' ';' ')' statement
+ | FOR '(' ';' expression ';' ')' statement
+ | FOR '(' expression ';' expression ';' ')' statement
+ | FOR '(' ';' ';' expression ')' statement
+ | FOR '(' expression ';' ';' expression ')' statement
+ | FOR '(' ';' expression ';' expression ')' statement
+ | FOR '(' expression ';' expression ';' expression ')' statement
+ ;
+
+jump_statement
+ : GOTO identifier_or_typedef_name ';'
+ | CONTINUE ';'
+ | BREAK ';'
+ | RETURN ';'
+ | RETURN expression ';'
+ ;
+
+/* A.2.4 External definitions. */
+
+translation_unit
+ : external_declaration
+ | translation_unit external_declaration
+ ;
+
+external_declaration
+ : function_definition
+ | declaration
+ | macro
+ ;
+
+function_definition
+ : declaration_specifiers declarator declaration_list compound_statement
+ | declaration_specifiers declarator compound_statement
+ ;
+
+declaration_list
+ : declaration
+ | declaration_list declaration
+ ;
+
+/* Macros */
+
+function_macro
+ : FUNCTION_MACRO
+ {
+ $$ = g_strdup (yytext + strlen ("#define "));
+ }
+ ;
+
+object_macro
+ : OBJECT_MACRO
+ {
+ $$ = g_strdup (yytext + strlen ("#define "));
+ }
+ ;
+
+function_macro_define
+ : function_macro '(' identifier_list ')'
+ ;
+
+object_macro_define
+ : object_macro constant_expression
+ {
+ if ($2->const_int_set || $2->const_string != NULL) {
+ $2->ident = $1;
+ g_igenerator_add_symbol (the_igenerator, $2);
+ }
+ }
+ ;
+
+macro
+ : function_macro_define
+ | object_macro_define
+ | error
+ ;
+
+%%
+
+static void
+yyerror(const char *s)
+{
+ /* ignore errors while doing a macro scan as not all object macros
+ * have valid expressions */
+ if (!the_igenerator->macro_scan) {
+ fprintf(stderr, "%d: %s\n", lineno, s);
+ }
+}
+
+void g_igenerator_parse (GIGenerator *igenerator, FILE *f)
+{
+ yyin = f;
+ if (yyin == NULL) {
+ return;
+ }
+
+ const_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ lineno = 1;
+ yyparse();
+
+ g_hash_table_unref (const_table);
+ const_table = NULL;
+
+ fclose (yyin);
+ yyin = NULL;
+}
+
diff --git a/gobject-introspection/gen-introspect.c b/gobject-introspection/gen-introspect.c
new file mode 100644
index 000000000..5edb5ef96
--- /dev/null
+++ b/gobject-introspection/gen-introspect.c
@@ -0,0 +1,1323 @@
+/* GObject introspection: gen-introspect
+ *
+ * Copyright (C) 2007 Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ * Jürg Billeter <j@bitron.ch>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+#include <gmodule.h>
+#include "gen-introspect.h"
+#include "gidlmodule.h"
+#include "gidlnode.h"
+
+typedef GType (*TypeFunction) (void);
+
+static void node_generate (GIGenerator *igenerator, GIdlNode *node);
+static void g_igenerator_parse_macros (GIGenerator *igenerator);
+
+static int g_idl_node_cmp (GIdlNode *a, GIdlNode *b)
+{
+ if (a->type < b->type) {
+ return -1;
+ } else if (a->type > b->type) {
+ return 1;
+ } else {
+ return strcmp (a->name, b->name);
+ }
+}
+
+GIGenerator *g_igenerator_new (void)
+{
+ GIGenerator *igenerator = g_new0 (GIGenerator, 1);
+ igenerator->namespace = "";
+ igenerator->lower_case_namespace = g_strdup ("");
+ igenerator->typedef_table = g_hash_table_new (g_str_hash, g_str_equal);
+ igenerator->struct_or_union_or_enum_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ igenerator->type_map = g_hash_table_new (g_str_hash, g_str_equal);
+ igenerator->type_by_lower_case_prefix = g_hash_table_new (g_str_hash, g_str_equal);
+
+ the_igenerator = igenerator;
+
+ return igenerator;
+}
+
+static void g_igenerator_write_inline (GIGenerator *igenerator, const char *s)
+{
+ fprintf (stdout, s);
+}
+
+static void g_igenerator_write (GIGenerator *igenerator, const char *s)
+{
+ int i;
+ for (i = 0; i < igenerator->indent; i++) {
+ fprintf (stdout, "\t");
+ }
+
+ g_igenerator_write_inline (igenerator, s);
+}
+
+static void g_igenerator_write_indent (GIGenerator *igenerator, const char *s)
+{
+ g_igenerator_write (igenerator, s);
+ igenerator->indent++;
+}
+
+static void g_igenerator_write_unindent (GIGenerator *igenerator, const char *s)
+{
+ igenerator->indent--;
+ g_igenerator_write (igenerator, s);
+}
+
+static void field_generate (GIGenerator *igenerator, GIdlNodeField *node)
+{
+ char *markup = g_markup_printf_escaped ("<field name=\"%s\" type=\"%s\"/>\n", node->node.name, node->type->unparsed);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+}
+
+static void value_generate (GIGenerator *igenerator, GIdlNodeValue *node)
+{
+ char *markup = g_markup_printf_escaped ("<member name=\"%s\" value=\"%d\"/>\n", node->node.name, node->value);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+}
+
+static void constant_generate (GIGenerator *igenerator, GIdlNodeConstant *node)
+{
+ char *markup = g_markup_printf_escaped ("<constant name=\"%s\" type=\"%s\" value=\"%s\"/>\n", node->node.name, node->type->unparsed, node->value);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+}
+
+static void property_generate (GIGenerator *igenerator, GIdlNodeProperty *node)
+{
+ char *markup = g_markup_printf_escaped ("<property name=\"%s\" type=\"%s\"/>\n", node->node.name, node->type->unparsed);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+}
+
+static void function_generate (GIGenerator *igenerator, GIdlNodeFunction *node)
+{
+ char *markup;
+ const char *tag_name;
+ if (node->node.type == G_IDL_NODE_CALLBACK) {
+ tag_name = "callback";
+ markup = g_markup_printf_escaped ("<callback name=\"%s\">\n", node->node.name);
+ } else if (node->is_constructor) {
+ tag_name = "constructor";
+ markup = g_markup_printf_escaped ("<constructor name=\"%s\" symbol=\"%s\">\n", node->node.name, node->symbol);
+ } else if (node->is_method) {
+ tag_name = "method";
+ markup = g_markup_printf_escaped ("<method name=\"%s\" symbol=\"%s\">\n", node->node.name, node->symbol);
+ } else {
+ tag_name = "function";
+ markup = g_markup_printf_escaped ("<function name=\"%s\" symbol=\"%s\">\n", node->node.name, node->symbol);
+ }
+
+ g_igenerator_write_indent (igenerator, markup);
+ g_free (markup);
+ markup = g_markup_printf_escaped ("<return-type type=\"%s\"/>\n", node->result->type->unparsed);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+ if (node->parameters != NULL) {
+ GList *l;
+ g_igenerator_write_indent (igenerator, "<parameters>\n");
+ for (l = node->parameters; l != NULL; l = l->next) {
+ GIdlNodeParam *param = l->data;
+ markup = g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n", param->node.name, param->type->unparsed);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+ }
+ g_igenerator_write_unindent (igenerator, "</parameters>\n");
+ }
+ markup = g_strdup_printf ("</%s>\n", tag_name);
+ g_igenerator_write_unindent (igenerator, markup);
+ g_free (markup);
+}
+
+static void vfunc_generate (GIGenerator *igenerator, GIdlNodeVFunc *node)
+{
+ char *markup = g_markup_printf_escaped ("<vfunc name=\"%s\">\n", node->node.name);
+ g_igenerator_write_indent (igenerator, markup);
+ g_free (markup);
+ markup = g_markup_printf_escaped ("<return-type type=\"%s\"/>\n", node->result->type->unparsed);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+ if (node->parameters != NULL) {
+ GList *l;
+ g_igenerator_write_indent (igenerator, "<parameters>\n");
+ for (l = node->parameters; l != NULL; l = l->next) {
+ GIdlNodeParam *param = l->data;
+ markup = g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n", param->node.name, param->type->unparsed);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+ }
+ g_igenerator_write_unindent (igenerator, "</parameters>\n");
+ }
+ g_igenerator_write_unindent (igenerator, "</vfunc>\n");
+}
+
+static void signal_generate (GIGenerator *igenerator, GIdlNodeSignal *node)
+{
+ char *markup;
+ const char *when = "LAST";
+ if (node->run_first) {
+ when = "FIRST";
+ } else if (node->run_cleanup) {
+ when = "CLEANUP";
+ }
+ markup = g_markup_printf_escaped ("<signal name=\"%s\" when=\"%s\">\n", node->node.name, when);
+ g_igenerator_write_indent (igenerator, markup);
+ g_free (markup);
+ markup = g_markup_printf_escaped ("<return-type type=\"%s\"/>\n", node->result->type->unparsed);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+ if (node->parameters != NULL) {
+ GList *l;
+ g_igenerator_write_indent (igenerator, "<parameters>\n");
+ for (l = node->parameters; l != NULL; l = l->next) {
+ GIdlNodeParam *param = l->data;
+ markup = g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n", param->node.name, param->type->unparsed);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+ }
+ g_igenerator_write_unindent (igenerator, "</parameters>\n");
+ }
+ g_igenerator_write_unindent (igenerator, "</signal>\n");
+}
+
+static void interface_generate (GIGenerator *igenerator, GIdlNodeInterface *node)
+{
+ GList *l;
+ char *markup;
+ if (node->node.type == G_IDL_NODE_OBJECT) {
+ markup = g_markup_printf_escaped ("<object name=\"%s\" parent=\"%s\" type-name=\"%s\" get-type=\"%s\">\n", node->node.name, node->parent, node->gtype_name, node->gtype_init);
+ } else if (node->node.type == G_IDL_NODE_INTERFACE) {
+ markup = g_markup_printf_escaped ("<interface name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n", node->node.name, node->gtype_name, node->gtype_init);
+ }
+
+ g_igenerator_write_indent (igenerator, markup);
+ g_free (markup);
+ if (node->node.type == G_IDL_NODE_OBJECT && node->interfaces != NULL) {
+ GList *l;
+ g_igenerator_write_indent (igenerator, "<implements>\n");
+ for (l = node->interfaces; l != NULL; l = l->next) {
+ markup = g_markup_printf_escaped ("<interface name=\"%s\"/>\n", (char *) l->data);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+ }
+ g_igenerator_write_unindent (igenerator, "</implements>\n");
+ } else if (node->node.type == G_IDL_NODE_INTERFACE && node->prerequisites != NULL) {
+ GList *l;
+ g_igenerator_write_indent (igenerator, "<requires>\n");
+ for (l = node->prerequisites; l != NULL; l = l->next) {
+ markup = g_markup_printf_escaped ("<interface name=\"%s\"/>\n", (char *) l->data);
+ g_igenerator_write (igenerator, markup);
+ g_free (markup);
+ }
+ g_igenerator_write_unindent (igenerator, "</requires>\n");
+ }
+
+ for (l = node->members; l != NULL; l = l->next) {
+ node_generate (igenerator, l->data);
+ }
+
+ if (node->node.type == G_IDL_NODE_OBJECT) {
+ g_igenerator_write_unindent (igenerator, "</object>\n");
+ } else if (node->node.type == G_IDL_NODE_INTERFACE) {
+ g_igenerator_write_unindent (igenerator, "</interface>\n");
+ }
+}
+
+static void struct_generate (GIGenerator *igenerator, GIdlNodeStruct *node)
+{
+ GList *l;
+ char *markup = g_markup_printf_escaped ("<struct name=\"%s\">\n", node->node.name);
+ g_igenerator_write_indent (igenerator, markup);
+ g_free (markup);
+ for (l = node->members; l != NULL; l = l->next) {
+ node_generate (igenerator, l->data);
+ }
+ g_igenerator_write_unindent (igenerator, "</struct>\n");
+}
+
+static void union_generate (GIGenerator *igenerator, GIdlNodeUnion *node)
+{
+ GList *l;
+ char *markup = g_markup_printf_escaped ("<union name=\"%s\">\n", node->node.name);
+ g_igenerator_write_indent (igenerator, markup);
+ g_free (markup);
+ for (l = node->members; l != NULL; l = l->next) {
+ node_generate (igenerator, l->data);
+ }
+ g_igenerator_write_unindent (igenerator, "</union>\n");
+}
+
+static void boxed_generate (GIGenerator *igenerator, GIdlNodeBoxed *node)
+{
+ GList *l;
+ char *markup = g_markup_printf_escaped ("<boxed name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n", node->node.name, node->gtype_name, node->gtype_init);
+ g_igenerator_write_indent (igenerator, markup);
+ g_free (markup);
+ for (l = node->members; l != NULL; l = l->next) {
+ node_generate (igenerator, l->data);
+ }
+ g_igenerator_write_unindent (igenerator, "</boxed>\n");
+}
+
+static void enum_generate (GIGenerator *igenerator, GIdlNodeEnum *node)
+{
+ GList *l;
+ char *markup;
+ const char *tag_name = NULL;
+
+ if (node->node.type == G_IDL_NODE_ENUM) {
+ tag_name = "enum";
+ } else if (node->node.type == G_IDL_NODE_FLAGS) {
+ tag_name = "flags";
+ }
+ markup = g_markup_printf_escaped ("<%s name=\"%s\">\n", tag_name, node->node.name);
+ g_igenerator_write_indent (igenerator, markup);
+ g_free (markup);
+
+ for (l = node->values; l != NULL; l = l->next) {
+ node_generate (igenerator, l->data);
+ }
+
+ markup = g_strdup_printf ("</%s>\n", tag_name);
+ g_igenerator_write_unindent (igenerator, markup);
+ g_free (markup);
+}
+
+static void node_generate (GIGenerator *igenerator, GIdlNode *node)
+{
+ switch (node->type) {
+ case G_IDL_NODE_FUNCTION:
+ case G_IDL_NODE_CALLBACK:
+ function_generate (igenerator, (GIdlNodeFunction *) node);
+ break;
+ case G_IDL_NODE_VFUNC:
+ vfunc_generate (igenerator, (GIdlNodeVFunc *) node);
+ break;
+ case G_IDL_NODE_OBJECT:
+ case G_IDL_NODE_INTERFACE:
+ interface_generate (igenerator, (GIdlNodeInterface *) node);
+ break;
+ case G_IDL_NODE_STRUCT:
+ struct_generate (igenerator, (GIdlNodeStruct *) node);
+ break;
+ case G_IDL_NODE_UNION:
+ union_generate (igenerator, (GIdlNodeUnion *) node);
+ break;
+ case G_IDL_NODE_BOXED:
+ boxed_generate (igenerator, (GIdlNodeBoxed *) node);
+ break;
+ case G_IDL_NODE_ENUM:
+ case G_IDL_NODE_FLAGS:
+ enum_generate (igenerator, (GIdlNodeEnum *) node);
+ break;
+ case G_IDL_NODE_PROPERTY:
+ property_generate (igenerator, (GIdlNodeProperty *) node);
+ break;
+ case G_IDL_NODE_FIELD:
+ field_generate (igenerator, (GIdlNodeField *) node);
+ break;
+ case G_IDL_NODE_SIGNAL:
+ signal_generate (igenerator, (GIdlNodeSignal *) node);
+ break;
+ case G_IDL_NODE_VALUE:
+ value_generate (igenerator, (GIdlNodeValue *) node);
+ break;
+ case G_IDL_NODE_CONSTANT:
+ constant_generate (igenerator, (GIdlNodeConstant *) node);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void module_generate (GIGenerator *igenerator, GIdlModule *module)
+{
+ GList *l;
+ char *markup = g_markup_printf_escaped ("<namespace name=\"%s\">\n", module->name);
+ g_igenerator_write_indent (igenerator, markup);
+ g_free (markup);
+ for (l = module->entries; l != NULL; l = l->next) {
+ node_generate (igenerator, l->data);
+ }
+ g_igenerator_write_unindent (igenerator, "</namespace>\n");
+}
+
+static GIdlNodeType *get_type_from_type_id (GType type_id)
+{
+ GIdlNodeType *gitype = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
+
+ GType type_fundamental = g_type_fundamental (type_id);
+
+ if (type_fundamental == G_TYPE_STRING) {
+ gitype->unparsed = g_strdup ("char*");
+ } else if (type_id == G_TYPE_STRV) {
+ gitype->unparsed = g_strdup ("char*[]");
+ } else if (type_fundamental == G_TYPE_INTERFACE || type_fundamental == G_TYPE_BOXED || type_fundamental == G_TYPE_OBJECT) {
+ gitype->unparsed = g_strdup_printf ("%s*", g_type_name (type_id));
+ } else if (type_fundamental == G_TYPE_PARAM) {
+ gitype->unparsed = g_strdup ("GParamSpec*");
+ } else {
+ gitype->unparsed = g_strdup (g_type_name (type_id));
+ }
+
+ return gitype;
+}
+
+static char *str_replace (const char *str, const char *needle, const char *replacement)
+{
+ char **strings = g_strsplit (str, needle, 0);
+ char *result = g_strjoinv (replacement, strings);
+ g_strfreev (strings);
+ return result;
+}
+
+static void g_igenerator_process_properties (GIGenerator *igenerator, GIdlNodeInterface *ginode, GType type_id)
+{
+ int i;
+ guint n_properties;
+ GParamSpec **properties;
+
+ if (ginode->node.type == G_IDL_NODE_OBJECT) {
+ GObjectClass *type_class = g_type_class_ref (type_id);
+ properties = g_object_class_list_properties (type_class, &n_properties);
+ } else if (ginode->node.type == G_IDL_NODE_INTERFACE) {
+ GTypeInterface *iface = g_type_default_interface_ref (type_id);
+ properties = g_object_interface_list_properties (iface, &n_properties);
+ } else {
+ g_assert_not_reached ();
+ }
+
+ for (i = 0; i < n_properties; i++) {
+ /* ignore inherited properties */
+ if (properties[i]->owner_type != type_id) {
+ continue;
+ }
+ GIdlNodeProperty *giprop = (GIdlNodeProperty *) g_idl_node_new (G_IDL_NODE_PROPERTY);
+ giprop->node.name = properties[i]->name;
+ ginode->members = g_list_insert_sorted (ginode->members, giprop, (GCompareFunc) g_idl_node_cmp);
+ giprop->type = get_type_from_type_id (properties[i]->value_type);
+ }
+}
+
+static void g_igenerator_process_signals (GIGenerator *igenerator, GIdlNodeInterface *ginode, GType type_id)
+{
+ int i, j;
+ guint n_signal_ids;
+ guint *signal_ids = g_signal_list_ids (type_id, &n_signal_ids);
+
+ for (i = 0; i < n_signal_ids; i++) {
+ GSignalQuery signal_query;
+ g_signal_query (signal_ids[i], &signal_query);
+ GIdlNodeSignal *gisig = (GIdlNodeSignal *) g_idl_node_new (G_IDL_NODE_SIGNAL);
+ gisig->node.name = g_strdup (signal_query.signal_name);
+ ginode->members = g_list_insert_sorted (ginode->members, gisig, (GCompareFunc) g_idl_node_cmp);
+
+ gisig->run_first = (signal_query.signal_flags & G_SIGNAL_RUN_FIRST) != 0;
+ gisig->run_last = (signal_query.signal_flags & G_SIGNAL_RUN_LAST) != 0;
+ gisig->run_cleanup = (signal_query.signal_flags & G_SIGNAL_RUN_CLEANUP) != 0;
+
+ /* add sender parameter */
+ GIdlNodeParam *giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gisig->parameters = g_list_append (gisig->parameters, giparam);
+ giparam->node.name = g_strdup ("object");
+ giparam->type = get_type_from_type_id (type_id);
+
+ for (j = 0; j < signal_query.n_params; j++) {
+ giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gisig->parameters = g_list_append (gisig->parameters, giparam);
+ giparam->node.name = g_strdup_printf ("p%d", j);
+ giparam->type = get_type_from_type_id (signal_query.param_types[j]);
+ }
+ gisig->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gisig->result->type = get_type_from_type_id (signal_query.return_type);
+ }
+}
+
+static void g_igenerator_process_types (GIGenerator *igenerator)
+{
+ int i;
+ GList *lib_l;
+
+ /* ensure to initialize GObject */
+ g_type_class_ref (G_TYPE_OBJECT);
+
+ for (lib_l = igenerator->libraries; lib_l != NULL; lib_l = lib_l->next) {
+ GList *l;
+ GModule *module = g_module_open (lib_l->data, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+ if (module == NULL) {
+ g_critical ("Couldn't open module: %s", (char *) lib_l->data);
+ continue;
+ }
+ for (l = igenerator->get_type_symbols; l != NULL; l = l->next) {
+ char *get_type_symbol = l->data;
+ TypeFunction type_fun;
+ if (!g_module_symbol (module, get_type_symbol, (gpointer*) &type_fun)) {
+ continue;
+ }
+ GType type_id = type_fun ();
+ GType type_fundamental = g_type_fundamental (type_id);
+ char *lower_case_prefix = str_replace (g_strndup (get_type_symbol, strlen (get_type_symbol) - strlen ("_get_type")), "_", "");
+ if (type_fundamental == G_TYPE_OBJECT) {
+ char *alt_lower_case_prefix;
+ GIdlNodeInterface *ginode = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_OBJECT);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, ginode, (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix, lower_case_prefix, ginode);
+ alt_lower_case_prefix = g_ascii_strdown (ginode->node.name, -1);
+ if (strcmp (alt_lower_case_prefix, lower_case_prefix) != 0) {
+ /* alternative prefix sometimes necessary, for example for GdkWindow */
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix, alt_lower_case_prefix, ginode);
+ } else {
+ g_free (alt_lower_case_prefix);
+ }
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = get_type_symbol;
+ ginode->parent = g_strdup (g_type_name (g_type_parent (type_id)));
+
+ guint n_type_interfaces;
+ GType *type_interfaces = g_type_interfaces (type_id, &n_type_interfaces);
+ for (i = 0; i < n_type_interfaces; i++) {
+ char *iface_name = g_strdup (g_type_name (type_interfaces[i]));
+ /* workaround for AtkImplementorIface */
+ if (g_str_has_suffix (iface_name, "Iface")) {
+ iface_name[strlen (iface_name) - strlen ("Iface")] = '\0';
+ }
+ ginode->interfaces = g_list_append (ginode->interfaces, iface_name);
+ }
+
+ g_igenerator_process_properties (igenerator, ginode, type_id);
+ g_igenerator_process_signals (igenerator, ginode, type_id);
+ } else if (type_fundamental == G_TYPE_INTERFACE) {
+ GIdlNodeInterface *ginode = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+ /* workaround for AtkImplementorIface */
+ if (g_str_has_suffix (ginode->node.name, "Iface")) {
+ ginode->node.name[strlen (ginode->node.name) - strlen ("Iface")] = '\0';
+ }
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, ginode, (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix, lower_case_prefix, ginode);
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = get_type_symbol;
+
+ gboolean is_gobject = FALSE;
+ guint n_iface_prereqs;
+ GType *iface_prereqs = g_type_interface_prerequisites (type_id, &n_iface_prereqs);
+ for (i = 0; i < n_iface_prereqs; i++) {
+ if (g_type_fundamental (iface_prereqs[i]) == G_TYPE_OBJECT) {
+ is_gobject = TRUE;
+ }
+ ginode->prerequisites = g_list_append (ginode->prerequisites, g_strdup (g_type_name (iface_prereqs[i])));
+ }
+
+ if (is_gobject) {
+ g_igenerator_process_properties (igenerator, ginode, type_id);
+ } else {
+ g_type_default_interface_ref (type_id);
+ }
+ g_igenerator_process_signals (igenerator, ginode, type_id);
+ } else if (type_fundamental == G_TYPE_BOXED) {
+ GIdlNodeBoxed *ginode = (GIdlNodeBoxed *) g_idl_node_new (G_IDL_NODE_BOXED);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, ginode, (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix, lower_case_prefix, ginode);
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = get_type_symbol;
+ } else if (type_fundamental == G_TYPE_ENUM) {
+ GIdlNodeEnum *ginode = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, ginode, (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix, lower_case_prefix, ginode);
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = get_type_symbol;
+
+ GEnumClass *type_class = g_type_class_ref (type_id);
+ for (i = 0; i < type_class->n_values; i++) {
+ GIdlNodeValue *gival = (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+ ginode->values = g_list_append (ginode->values, gival);
+ gival->node.name = g_strdup (type_class->values[i].value_name);
+ gival->value = type_class->values[i].value;
+ }
+ } else if (type_fundamental == G_TYPE_FLAGS) {
+ GIdlNodeEnum *ginode = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_FLAGS);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, ginode, (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix, lower_case_prefix, ginode);
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = get_type_symbol;
+
+ GFlagsClass *type_class = g_type_class_ref (type_id);
+ for (i = 0; i < type_class->n_values; i++) {
+ GIdlNodeValue *gival = (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+ ginode->values = g_list_append (ginode->values, gival);
+ gival->node.name = g_strdup (type_class->values[i].value_name);
+ gival->value = type_class->values[i].value;
+ }
+ }
+ }
+ }
+}
+
+static GIdlNodeType *get_type_from_ctype (CType *ctype)
+{
+ GIdlNodeType *gitype = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
+ if (ctype->type == CTYPE_VOID) {
+ gitype->unparsed = g_strdup ("void");
+ } else if (ctype->type == CTYPE_BASIC_TYPE) {
+ gitype->unparsed = g_strdup (ctype->name);
+ } else if (ctype->type == CTYPE_TYPEDEF) {
+ gitype->unparsed = g_strdup (ctype->name);
+ } else if (ctype->type == CTYPE_STRUCT) {
+ if (ctype->name == NULL) {
+ /* anonymous struct */
+ gitype->unparsed = g_strdup ("gpointer");
+ } else {
+ gitype->unparsed = g_strdup_printf ("struct %s", ctype->name);
+ }
+ } else if (ctype->type == CTYPE_UNION) {
+ if (ctype->name == NULL) {
+ /* anonymous union */
+ gitype->unparsed = g_strdup ("gpointer");
+ } else {
+ gitype->unparsed = g_strdup_printf ("union %s", ctype->name);
+ }
+ } else if (ctype->type == CTYPE_ENUM) {
+ if (ctype->name == NULL) {
+ /* anonymous enum */
+ gitype->unparsed = g_strdup ("gint");
+ } else {
+ gitype->unparsed = g_strdup_printf ("enum %s", ctype->name);
+ }
+ } else if (ctype->type == CTYPE_POINTER) {
+ if (ctype->base_type->type == CTYPE_FUNCTION) {
+ /* anonymous function pointer */
+ gitype->unparsed = g_strdup ("GCallback");
+ } else {
+ GIdlNodeType *gibasetype = get_type_from_ctype (ctype->base_type);
+ gitype->unparsed = g_strdup_printf ("%s*", gibasetype->unparsed);
+ }
+ } else if (ctype->type == CTYPE_ARRAY) {
+ GIdlNodeType *gibasetype = get_type_from_ctype (ctype->base_type);
+ gitype->unparsed = g_strdup_printf ("%s[]", gibasetype->unparsed);
+ } else {
+ gitype->unparsed = g_strdup ("unknown");
+ }
+ return gitype;
+}
+
+static void g_igenerator_process_function_symbol (GIGenerator *igenerator, CSymbol *sym)
+{
+ GIdlNodeFunction *gifunc = (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
+ /* check whether this is a type method */
+ char *last_underscore = strrchr (sym->ident, '_');
+ while (last_underscore != NULL) {
+ char *prefix = str_replace (g_strndup (sym->ident, last_underscore - sym->ident), "_", "");
+ GIdlNode *ginode = g_hash_table_lookup (igenerator->type_by_lower_case_prefix, prefix);
+ if (ginode != NULL) {
+ gifunc->node.name = g_strdup (last_underscore + 1);
+ if (strcmp (gifunc->node.name, "get_type") == 0) {
+ /* ignore get_type functions in registered types */
+ return;
+ }
+ if ((ginode->type == G_IDL_NODE_OBJECT || ginode->type == G_IDL_NODE_BOXED) && g_str_has_prefix (gifunc->node.name, "new")) {
+ gifunc->is_constructor = TRUE;
+ } else {
+ gifunc->is_method = TRUE;
+ }
+ if (ginode->type == G_IDL_NODE_OBJECT || ginode->type == G_IDL_NODE_INTERFACE) {
+ GIdlNodeInterface *giiface = (GIdlNodeInterface *) ginode;
+ giiface->members = g_list_insert_sorted (giiface->members, gifunc, (GCompareFunc) g_idl_node_cmp);
+ break;
+ } else if (ginode->type == G_IDL_NODE_BOXED) {
+ GIdlNodeBoxed *giboxed = (GIdlNodeBoxed *) ginode;
+ giboxed->members = g_list_insert_sorted (giboxed->members, gifunc, (GCompareFunc) g_idl_node_cmp);
+ break;
+ } else if (ginode->type == G_IDL_NODE_STRUCT) {
+ GIdlNodeStruct *gistruct = (GIdlNodeStruct *) ginode;
+ gistruct->members = g_list_insert_sorted (gistruct->members, gifunc, (GCompareFunc) g_idl_node_cmp);
+ break;
+ } else if (ginode->type == G_IDL_NODE_UNION) {
+ GIdlNodeUnion *giunion = (GIdlNodeUnion *) ginode;
+ giunion->members = g_list_insert_sorted (giunion->members, gifunc, (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ } else if (strcmp (igenerator->lower_case_namespace, prefix) == 0) {
+ gifunc->node.name = g_strdup (last_underscore + 1);
+ gifunc->is_constructor = FALSE;
+ gifunc->is_method = FALSE;
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, gifunc, (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ last_underscore = g_utf8_strrchr (sym->ident, last_underscore - sym->ident, '_');
+ }
+
+ /* create a namespace function if no prefix matches */
+ if (gifunc->node.name == NULL) {
+ gifunc->node.name = sym->ident;
+ gifunc->is_constructor = FALSE;
+ gifunc->is_method = FALSE;
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, gifunc, (GCompareFunc) g_idl_node_cmp);
+ }
+
+ gifunc->symbol = sym->ident;
+ gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gifunc->result->type = get_type_from_ctype (sym->base_type->base_type);
+ GList *param_l;
+ for (param_l = sym->base_type->child_list; param_l != NULL; param_l = param_l->next) {
+ CSymbol *param_sym = param_l->data;
+ GIdlNodeParam *param = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ param->node.name = param_sym->ident;
+ param->type = get_type_from_ctype (param_sym->base_type);
+ gifunc->parameters = g_list_append (gifunc->parameters, param);
+ }
+}
+
+static void g_igenerator_process_unregistered_struct_typedef (GIGenerator *igenerator, CSymbol *sym, CType *struct_type)
+{
+ GIdlNodeStruct *ginode = (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
+ ginode->node.name = sym->ident;
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, ginode, (GCompareFunc) g_idl_node_cmp);
+ char *lower_case_prefix = g_ascii_strdown (sym->ident, -1);
+ g_hash_table_insert (igenerator->type_map, sym->ident, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix, lower_case_prefix, ginode);
+
+ GList *member_l;
+ for (member_l = struct_type->child_list; member_l != NULL; member_l = member_l->next) {
+ CSymbol *member = member_l->data;
+ GIdlNodeField *gifield = (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+}
+
+static void g_igenerator_process_struct_typedef (GIGenerator *igenerator, CSymbol *sym)
+{
+ CType *struct_type = sym->base_type;
+ gboolean opaque_type = FALSE;
+ if (struct_type->child_list == NULL) {
+ g_assert (struct_type->name != NULL);
+ CSymbol *struct_symbol = g_hash_table_lookup (igenerator->struct_or_union_or_enum_table, struct_type->name);
+ if (struct_symbol != NULL) {
+ struct_type = struct_symbol->base_type;
+ }
+ }
+ if (struct_type->child_list == NULL) {
+ opaque_type = TRUE;
+ }
+ GIdlNode *gitype = g_hash_table_lookup (igenerator->type_map, sym->ident);
+ if (gitype != NULL) {
+ /* struct of a GTypeInstance */
+ if (!opaque_type && (gitype->type == G_IDL_NODE_OBJECT || gitype->type == G_IDL_NODE_INTERFACE)) {
+ GIdlNodeInterface *ginode = (GIdlNodeInterface *) gitype;
+ GList *member_l;
+ /* ignore first field => parent */
+ for (member_l = struct_type->child_list->next; member_l != NULL; member_l = member_l->next) {
+ CSymbol *member = member_l->data;
+ /* ignore private / reserved members */
+ if (member->ident[0] == '_' || g_str_has_prefix (member->ident, "priv")) {
+ continue;
+ }
+ GIdlNodeField *gifield = (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+ } else if (gitype->type == G_IDL_NODE_BOXED) {
+ GIdlNodeBoxed *ginode = (GIdlNodeBoxed *) gitype;
+ GList *member_l;
+ for (member_l = struct_type->child_list; member_l != NULL; member_l = member_l->next) {
+ CSymbol *member = member_l->data;
+ GIdlNodeField *gifield = (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+ }
+ } else if (!opaque_type && (g_str_has_suffix (sym->ident, "Class") || g_str_has_suffix (sym->ident, "Iface"))) {
+ char *base_name = g_strndup (sym->ident, strlen (sym->ident) - 5);
+ gitype = g_hash_table_lookup (igenerator->type_map, base_name);
+ if (gitype == NULL || (gitype->type != G_IDL_NODE_OBJECT && gitype->type != G_IDL_NODE_INTERFACE)) {
+ g_igenerator_process_unregistered_struct_typedef (igenerator, sym, struct_type);
+ return;
+ }
+ GIdlNodeInterface *ginode = (GIdlNodeInterface *) gitype;
+
+ /* ignore first field => parent */
+ GList *member_l;
+ for (member_l = struct_type->child_list->next; member_l != NULL; member_l = member_l->next) {
+ CSymbol *member = member_l->data;
+ /* ignore private / reserved members */
+ if (member->ident[0] == '_') {
+ continue;
+ }
+ if (member->base_type->type == CTYPE_POINTER && member->base_type->base_type->type == CTYPE_FUNCTION) {
+ /* ignore default handlers of signals */
+ gboolean found_signal = FALSE;
+ GList *type_member_l;
+ for (type_member_l = ginode->members; type_member_l != NULL; type_member_l = type_member_l->next) {
+ GIdlNode *type_member = type_member_l->data;
+ char *normalized_name = str_replace (type_member->name, "-", "_");
+ if (type_member->type == G_IDL_NODE_SIGNAL && strcmp (normalized_name, member->ident) == 0) {
+ GList *vfunc_param_l;
+ GList *sig_param_l;
+ GIdlNodeSignal *sig = (GIdlNodeSignal *) type_member;
+ found_signal = TRUE;
+ /* set signal parameter names */
+ for (vfunc_param_l = member->base_type->base_type->child_list, sig_param_l = sig->parameters; vfunc_param_l != NULL && sig_param_l != NULL; vfunc_param_l = vfunc_param_l->next, sig_param_l = sig_param_l->next) {
+ CSymbol *vfunc_param = vfunc_param_l->data;
+ GIdlNodeParam *sig_param = sig_param_l->data;
+ g_free (sig_param->node.name);
+ sig_param->node.name = g_strdup (vfunc_param->ident);
+ }
+ break;
+ }
+ }
+ if (found_signal) {
+ continue;
+ }
+
+ GIdlNodeVFunc *givfunc = (GIdlNodeVFunc *) g_idl_node_new (G_IDL_NODE_VFUNC);
+ givfunc->node.name = member->ident;
+ ginode->members = g_list_insert_sorted (ginode->members, givfunc, (GCompareFunc) g_idl_node_cmp);
+ givfunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ givfunc->result->type = get_type_from_ctype (member->base_type->base_type->base_type);
+ GList *param_l;
+ for (param_l = member->base_type->base_type->child_list; param_l != NULL; param_l = param_l->next) {
+ CSymbol *param_sym = param_l->data;
+ GIdlNodeParam *param = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ param->node.name = param_sym->ident;
+ param->type = get_type_from_ctype (param_sym->base_type);
+ givfunc->parameters = g_list_append (givfunc->parameters, param);
+ }
+ }
+ }
+ } else if (g_str_has_suffix (sym->ident, "Private")) {
+ /* ignore private structs */
+ } else {
+ g_igenerator_process_unregistered_struct_typedef (igenerator, sym, struct_type);
+ }
+}
+
+static void g_igenerator_process_union_typedef (GIGenerator *igenerator, CSymbol *sym)
+{
+ CType *union_type = sym->base_type;
+ gboolean opaque_type = FALSE;
+ if (union_type->child_list == NULL) {
+ g_assert (union_type->name != NULL);
+ CSymbol *union_symbol = g_hash_table_lookup (igenerator->struct_or_union_or_enum_table, union_type->name);
+ if (union_symbol != NULL) {
+ union_type = union_symbol->base_type;
+ }
+ }
+ if (union_type->child_list == NULL) {
+ opaque_type = TRUE;
+ }
+ GIdlNode *gitype = g_hash_table_lookup (igenerator->type_map, sym->ident);
+ if (gitype != NULL) {
+ g_assert (gitype->type == G_IDL_NODE_BOXED);
+ GIdlNodeBoxed *ginode = (GIdlNodeBoxed *) gitype;
+ GList *member_l;
+ for (member_l = union_type->child_list; member_l != NULL; member_l = member_l->next) {
+ CSymbol *member = member_l->data;
+ GIdlNodeField *gifield = (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+ } else {
+ GIdlNodeUnion *ginode = (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
+ ginode->node.name = sym->ident;
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, ginode, (GCompareFunc) g_idl_node_cmp);
+ char *lower_case_prefix = g_ascii_strdown (sym->ident, -1);
+ g_hash_table_insert (igenerator->type_map, sym->ident, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix, lower_case_prefix, ginode);
+
+ ginode->node.name = sym->ident;
+ GList *member_l;
+ for (member_l = union_type->child_list; member_l != NULL; member_l = member_l->next) {
+ CSymbol *member = member_l->data;
+ GIdlNodeField *gifield = (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+ }
+}
+
+static void g_igenerator_process_enum_typedef (GIGenerator *igenerator, CSymbol *sym)
+{
+ CType *enum_type = sym->base_type;
+ if (enum_type->child_list == NULL) {
+ g_assert (enum_type->name != NULL);
+ CSymbol *enum_symbol = g_hash_table_lookup (igenerator->struct_or_union_or_enum_table, enum_type->name);
+ if (enum_symbol != NULL) {
+ enum_type = enum_symbol->base_type;
+ }
+ }
+ if (enum_type->child_list == NULL) {
+ /* opaque type */
+ return;
+ }
+ GIdlNodeEnum *ginode = g_hash_table_lookup (igenerator->type_map, sym->ident);
+ if (ginode != NULL) {
+ return;
+ }
+
+ ginode = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
+ ginode->node.name = sym->ident;
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, ginode, (GCompareFunc) g_idl_node_cmp);
+
+ GList *member_l;
+ for (member_l = enum_type->child_list; member_l != NULL; member_l = member_l->next) {
+ CSymbol *member = member_l->data;
+ GIdlNodeValue *gival = (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+ ginode->values = g_list_append (ginode->values, gival);
+ gival->node.name = member->ident;
+ gival->value = member->const_int;
+ }
+}
+
+static void g_igenerator_process_function_typedef (GIGenerator *igenerator, CSymbol *sym)
+{
+ /* handle callback types */
+ GIdlNodeFunction *gifunc = (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_CALLBACK);
+
+ gifunc->node.name = sym->ident;
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, gifunc, (GCompareFunc) g_idl_node_cmp);
+
+ gifunc->symbol = sym->ident;
+ gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gifunc->result->type = get_type_from_ctype (sym->base_type->base_type->base_type);
+ GList *param_l;
+ int i;
+ for (param_l = sym->base_type->base_type->child_list, i = 1; param_l != NULL; param_l = param_l->next, i++) {
+ CSymbol *param_sym = param_l->data;
+ GIdlNodeParam *param = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ if (param_sym->ident == NULL) {
+ param->node.name = g_strdup_printf ("p%d", i);
+ } else {
+ param->node.name = param_sym->ident;
+ }
+ param->type = get_type_from_ctype (param_sym->base_type);
+ gifunc->parameters = g_list_append (gifunc->parameters, param);
+ }
+}
+
+static void g_igenerator_process_constant (GIGenerator *igenerator, CSymbol *sym)
+{
+ GIdlNodeConstant *giconst = (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
+ giconst->node.name = sym->ident;
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, giconst, (GCompareFunc) g_idl_node_cmp);
+
+ giconst->type = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
+ if (sym->const_int_set) {
+ giconst->type->unparsed = g_strdup ("int");
+ giconst->value = g_strdup_printf ("%d", sym->const_int);
+ } else if (sym->const_string != NULL) {
+ giconst->type->unparsed = g_strdup ("char*");
+ giconst->value = sym->const_string;
+ }
+}
+
+static void g_igenerator_process_symbols (GIGenerator *igenerator)
+{
+ GList *l;
+ /* process type symbols first to ensure complete type hashtables */
+ /* type symbols */
+ for (l = igenerator->symbol_list; l != NULL; l = l->next) {
+ CSymbol *sym = l->data;
+ if (sym->ident[0] == '_') {
+ /* ignore private / reserved symbols */
+ continue;
+ }
+ if (sym->type == CSYMBOL_TYPE_TYPEDEF) {
+ if (sym->base_type->type == CTYPE_STRUCT) {
+ g_igenerator_process_struct_typedef (igenerator, sym);
+ } else if (sym->base_type->type == CTYPE_UNION) {
+ g_igenerator_process_union_typedef (igenerator, sym);
+ } else if (sym->base_type->type == CTYPE_ENUM) {
+ g_igenerator_process_enum_typedef (igenerator, sym);
+ } else if (sym->base_type->type == CTYPE_POINTER && sym->base_type->base_type->type == CTYPE_FUNCTION) {
+ g_igenerator_process_function_typedef (igenerator, sym);
+ } else {
+ GIdlNodeStruct *ginode = (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
+ ginode->node.name = sym->ident;
+ igenerator->module->entries = g_list_insert_sorted (igenerator->module->entries, ginode, (GCompareFunc) g_idl_node_cmp);
+ char *lower_case_prefix = g_ascii_strdown (sym->ident, -1);
+ g_hash_table_insert (igenerator->type_map, sym->ident, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix, lower_case_prefix, ginode);
+ }
+ }
+ }
+ /* other symbols */
+ for (l = igenerator->symbol_list; l != NULL; l = l->next) {
+ CSymbol *sym = l->data;
+ if (sym->ident[0] == '_') {
+ /* ignore private / reserved symbols */
+ continue;
+ }
+ if (sym->type == CSYMBOL_TYPE_FUNCTION) {
+ g_igenerator_process_function_symbol (igenerator, sym);
+ } else if (sym->type == CSYMBOL_TYPE_CONST) {
+ g_igenerator_process_constant (igenerator, sym);
+ }
+ }
+}
+
+void g_igenerator_add_symbol (GIGenerator *igenerator, CSymbol *symbol)
+{
+ /* only add symbols of main file */
+ gboolean found_filename = FALSE;
+ GList *l;
+ for (l = igenerator->filenames; l != NULL; l = l->next) {
+ if (strcmp (g_path_get_basename (l->data), g_path_get_basename (igenerator->current_filename)) == 0) {
+ found_filename = TRUE;
+ break;
+ }
+ }
+ if (found_filename || igenerator->macro_scan) {
+ igenerator->symbol_list = g_list_prepend (igenerator->symbol_list, symbol);
+ }
+
+ if (symbol->type == CSYMBOL_TYPE_TYPEDEF) {
+ g_hash_table_insert (igenerator->typedef_table, symbol->ident, symbol);
+ } else if (symbol->type == CSYMBOL_TYPE_STRUCT || symbol->type == CSYMBOL_TYPE_UNION || symbol->type == CSYMBOL_TYPE_ENUM) {
+ g_hash_table_insert (igenerator->struct_or_union_or_enum_table, symbol->ident, symbol);
+ }
+}
+
+gboolean g_igenerator_is_typedef (GIGenerator *igenerator, const char *name)
+{
+ gboolean b = g_hash_table_lookup (igenerator->typedef_table, name) != NULL;
+ return b;
+}
+
+void g_igenerator_generate (GIGenerator *igenerator)
+{
+ GList *l;
+ for (l = igenerator->symbol_list; l != NULL; l = l->next) {
+ CSymbol *sym = l->data;
+ if (sym->type == CSYMBOL_TYPE_FUNCTION && g_str_has_suffix (sym->ident, "_get_type")) {
+ igenerator->get_type_symbols = g_list_prepend (igenerator->get_type_symbols, sym->ident);
+ }
+ }
+ g_igenerator_process_types (igenerator);
+ g_igenerator_process_symbols (igenerator);
+
+ g_igenerator_write (igenerator, "<?xml version=\"1.0\"?>\n");
+ g_igenerator_write_indent (igenerator, "<api version=\"1.0\">\n");
+ module_generate (igenerator, igenerator->module);
+ g_igenerator_write_unindent (igenerator, "</api>\n");
+}
+
+int main (int argc, char **argv)
+{
+ g_type_init ();
+
+ GIGenerator *igenerator = g_igenerator_new ();
+
+ int cpp_argc = 0;
+ char **cpp_argv = g_new0 (char *, argc + 2);
+ cpp_argv[cpp_argc++] = "cc";
+ cpp_argv[cpp_argc++] = "-E";
+
+ int i;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ switch (argv[i][1]) {
+ case '-':
+ if (g_str_has_prefix (argv[i], "--namespace=")) {
+ igenerator->namespace = argv[i] + strlen ("--namespace=");
+ g_free (igenerator->lower_case_namespace);
+ igenerator->lower_case_namespace = g_ascii_strdown (igenerator->namespace, -1);
+ }
+ break;
+ case 'I':
+ case 'D':
+ case 'U':
+ cpp_argv[cpp_argc++] = argv[i];
+ break;
+ }
+ } else if (g_str_has_suffix (argv[i], ".h")) {
+ igenerator->filenames = g_list_append (igenerator->filenames, argv[i]);
+ } else if (g_str_has_suffix (argv[i], ".la") ||
+ g_str_has_suffix (argv[i], ".so") ||
+ g_str_has_suffix (argv[i], ".dll")) {
+ igenerator->libraries = g_list_append (igenerator->libraries, argv[i]);
+ }
+ }
+
+
+ GError *error = NULL;
+
+ char *tmp_name = NULL;
+ FILE *f= fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error), "w");
+
+
+ GList *l;
+ for (l = igenerator->filenames; l != NULL; l = l->next) {
+ fprintf (f, "#include <%s>\n", (char *) l->data);
+ }
+
+
+ fclose (f);
+
+ cpp_argv[cpp_argc++] = tmp_name;
+ cpp_argv[cpp_argc++] = NULL;
+
+ int cpp_out = -1;
+ g_spawn_async_with_pipes (NULL, cpp_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, &cpp_out, NULL, &error);
+ if (error != NULL) {
+ g_error ("%s", error->message);
+ }
+
+ g_igenerator_parse (igenerator, fdopen (cpp_out, "r"));
+
+ g_unlink (tmp_name);
+
+ g_igenerator_parse_macros (igenerator);
+
+ igenerator->module = g_idl_module_new (igenerator->namespace);
+ g_igenerator_generate (igenerator);
+
+ return 0;
+}
+
+CSymbol *csymbol_new (CSymbolType type) {
+ CSymbol *s = g_new0 (CSymbol, 1);
+ s->type = type;
+ return s;
+}
+
+gboolean csymbol_get_const_boolean (CSymbol *symbol) {
+ return (symbol->const_int_set && symbol->const_int) || symbol->const_string;
+}
+
+CType *ctype_new (CTypeType type) {
+ CType *t = g_new0 (CType, 1);
+ t->type = type;
+ return t;
+}
+
+CType *ctype_copy (CType *type) {
+ return g_memdup (type, sizeof (CType));
+}
+
+CType *cbasic_type_new (const char *name) {
+ CType *basic_type = ctype_new (CTYPE_BASIC_TYPE);
+ basic_type->name = g_strdup (name);
+ return basic_type;
+}
+
+CType *ctypedef_new (const char *name) {
+ CType *typedef_ = ctype_new (CTYPE_TYPEDEF);
+ typedef_->name = g_strdup (name);
+ return typedef_;
+}
+
+CType *cstruct_new (const char *name) {
+ CType *struct_ = ctype_new (CTYPE_STRUCT);
+ struct_->name = g_strdup (name);
+ return struct_;
+}
+
+CType *cunion_new (const char *name) {
+ CType *union_ = ctype_new (CTYPE_UNION);
+ union_->name = g_strdup (name);
+ return union_;
+}
+
+CType *cenum_new (const char *name) {
+ CType *enum_ = ctype_new (CTYPE_ENUM);
+ enum_->name = g_strdup (name);
+ return enum_;
+}
+
+CType *cpointer_new (CType *base_type) {
+ CType *pointer = ctype_new (CTYPE_POINTER);
+ pointer->base_type = base_type;
+ return pointer;
+}
+
+CType *carray_new (void) {
+ CType *array = ctype_new (CTYPE_ARRAY);
+ return array;
+}
+
+CType *cfunction_new (void) {
+ CType *func = ctype_new (CTYPE_FUNCTION);
+ return func;
+}
+
+static int eat_hspace (FILE *f) {
+ int c;
+ do {
+ c = fgetc (f);
+ } while (c == ' ' || c == '\t');
+ return c;
+}
+
+static int eat_line (FILE *f, int c) {
+ while (c != EOF && c != '\n') {
+ c = fgetc (f);
+ }
+ if (c == '\n') {
+ c = fgetc (f);
+ if (c == ' ' || c == '\t') {
+ c = eat_hspace (f);
+ }
+ }
+ return c;
+}
+
+static int read_identifier (FILE *f, int c, char **identifier) {
+ GString *id = g_string_new ("");
+ while (isalnum (c) || c == '_') {
+ g_string_append_c (id, c);
+ c = fgetc (f);
+ }
+ *identifier = g_string_free (id, FALSE);
+ return c;
+}
+
+static void g_igenerator_parse_macros (GIGenerator *igenerator) {
+ GError *error = NULL;
+ char *tmp_name = NULL;
+ FILE *fmacros = fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error), "w+");
+ g_unlink (tmp_name);
+
+ GList *l;
+ for (l = igenerator->filenames; l != NULL; l = l->next) {
+ FILE *f = fopen (l->data, "r");
+
+ GString *define_line;
+ char *str;
+ gboolean error_line = FALSE;
+ int c = eat_hspace (f);
+ while (c != EOF) {
+ if (c != '#') {
+ /* ignore line */
+ c = eat_line (f, c);
+ continue;
+ }
+ c = eat_hspace (f);
+ c = read_identifier (f, c, &str);
+ if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t')) {
+ g_free (str);
+ /* ignore line */
+ c = eat_line (f, c);
+ continue;
+ }
+ g_free (str);
+ c = eat_hspace (f);
+ c = read_identifier (f, c, &str);
+ if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '(')) {
+ g_free (str);
+ /* ignore line */
+ c = eat_line (f, c);
+ continue;
+ }
+ define_line = g_string_new ("#define ");
+ g_string_append (define_line, str);
+ g_free (str);
+ if (c == '(') {
+ while (c != ')') {
+ g_string_append_c (define_line, c);
+ c = fgetc (f);
+ if (c == EOF || c == '\n') {
+ error_line = TRUE;
+ break;
+ }
+ }
+ if (error_line) {
+ g_string_free (define_line, TRUE);
+ /* ignore line */
+ c = eat_line (f, c);
+ continue;
+ }
+
+ g_assert (c == ')');
+ g_string_append_c (define_line, c);
+ c = fgetc (f);
+
+ /* found function-like macro */
+ fprintf (fmacros, define_line->str);
+ fprintf (fmacros, "\n");
+
+ g_string_free (define_line, TRUE);
+ /* ignore rest of line */
+ c = eat_line (f, c);
+ continue;
+ }
+ if (c != ' ' && c != '\t') {
+ g_string_free (define_line, TRUE);
+ /* ignore line */
+ c = eat_line (f, c);
+ continue;
+ }
+ while (c != EOF && c != '\n') {
+ g_string_append_c (define_line, c);
+ c = fgetc (f);
+ if (c == '\\') {
+ c = fgetc (f);
+ if (c == '\n') {
+ /* fold lines when seeing backslash new-line sequence */
+ c = fgetc (f);
+ } else {
+ g_string_append_c (define_line, '\\');
+ }
+ }
+ }
+
+ /* found object-like macro */
+ fprintf (fmacros, define_line->str);
+ fprintf (fmacros, "\n");
+
+ c = eat_line (f, c);
+ }
+
+ fclose (f);
+ }
+
+ igenerator->macro_scan = TRUE;
+ rewind (fmacros);
+ g_igenerator_parse (igenerator, fmacros);
+ igenerator->macro_scan = FALSE;
+}
+
+
+
diff --git a/gobject-introspection/gen-introspect.h b/gobject-introspection/gen-introspect.h
new file mode 100644
index 000000000..91d4ab066
--- /dev/null
+++ b/gobject-introspection/gen-introspect.h
@@ -0,0 +1,157 @@
+/* GObject introspection: gen-introspect
+ *
+ * Copyright (C) 2007 Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ * Jürg Billeter <j@bitron.ch>
+ */
+
+#ifndef __GEN_INTROSPECT_H__
+#define __GEN_INTROSPECT_H__
+
+#include <glib.h>
+#include "gidlmodule.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GIGenerator GIGenerator;
+typedef struct _CSymbol CSymbol;
+typedef struct _CType CType;
+
+struct _GIGenerator {
+ const char *namespace;
+ char *lower_case_namespace;
+ /* specified files to be parsed */
+ GList *filenames;
+ GList *libraries;
+ /* source reference of current lexer position */
+ char *current_filename;
+ GList *symbol_list;
+ GHashTable *typedef_table;
+ GHashTable *struct_or_union_or_enum_table;
+
+ gboolean macro_scan;
+
+ GIdlModule *module;
+ GList *get_type_symbols;
+ GHashTable *type_map;
+ GHashTable *type_by_lower_case_prefix;
+
+ int indent;
+};
+
+GIGenerator *g_igenerator_new (void);
+void g_igenerator_parse (GIGenerator *igenerator, FILE *f);
+void g_igenerator_add_symbol (GIGenerator *igenerator, CSymbol *symbol);
+gboolean g_igenerator_is_typedef (GIGenerator *igenerator, const char *name);
+void g_igenerator_generate (GIGenerator *igenerator);
+
+GIGenerator *the_igenerator;
+
+typedef enum {
+ CSYMBOL_TYPE_INVALID,
+ CSYMBOL_TYPE_CONST,
+ CSYMBOL_TYPE_OBJECT,
+ CSYMBOL_TYPE_FUNCTION,
+ CSYMBOL_TYPE_STRUCT,
+ CSYMBOL_TYPE_UNION,
+ CSYMBOL_TYPE_ENUM,
+ CSYMBOL_TYPE_TYPEDEF
+} CSymbolType;
+
+struct _CSymbol {
+ CSymbolType type;
+ int id;
+ char *ident;
+ CType *base_type;
+ gboolean const_int_set;
+ int const_int;
+ char *const_string;
+};
+
+CSymbol *csymbol_new (CSymbolType type);
+gboolean csymbol_get_const_boolean (CSymbol *symbol);
+
+typedef enum {
+ CTYPE_INVALID,
+ CTYPE_VOID,
+ CTYPE_BASIC_TYPE,
+ CTYPE_TYPEDEF,
+ CTYPE_STRUCT,
+ CTYPE_UNION,
+ CTYPE_ENUM,
+ CTYPE_POINTER,
+ CTYPE_ARRAY,
+ CTYPE_FUNCTION
+} CTypeType;
+
+typedef enum {
+ STORAGE_CLASS_NONE = 0,
+ STORAGE_CLASS_TYPEDEF = 1 << 1,
+ STORAGE_CLASS_EXTERN = 1 << 2,
+ STORAGE_CLASS_STATIC = 1 << 3,
+ STORAGE_CLASS_AUTO = 1 << 4,
+ STORAGE_CLASS_REGISTER = 1 << 5
+} StorageClassSpecifier;
+
+typedef enum {
+ TYPE_QUALIFIER_NONE = 0,
+ TYPE_QUALIFIER_CONST = 1 << 1,
+ TYPE_QUALIFIER_RESTRICT = 1 << 2,
+ TYPE_QUALIFIER_VOLATILE = 1 << 3
+} TypeQualifier;
+
+typedef enum {
+ FUNCTION_NONE = 0,
+ FUNCTION_INLINE = 1 << 1
+} FunctionSpecifier;
+
+typedef enum {
+ UNARY_ADDRESS_OF,
+ UNARY_POINTER_INDIRECTION,
+ UNARY_PLUS,
+ UNARY_MINUS,
+ UNARY_BITWISE_COMPLEMENT,
+ UNARY_LOGICAL_NEGATION
+} UnaryOperator;
+
+struct _CType {
+ CTypeType type;
+ StorageClassSpecifier storage_class_specifier;
+ TypeQualifier type_qualifier;
+ FunctionSpecifier function_specifier;
+ char *name;
+ CType *base_type;
+ GList *child_list;
+};
+
+CType *ctype_new (CTypeType type);
+CType *ctype_copy (CType *type);
+CType *cbasic_type_new (const char *name);
+CType *ctypedef_new (const char *name);
+CType *cstruct_new (const char *name);
+CType *cunion_new (const char *name);
+CType *cenum_new (const char *name);
+CType *cpointer_new (CType *base_type);
+CType *carray_new (void);
+CType *cfunction_new (void);
+
+G_END_DECLS
+
+#endif
+