From 2549f2b773a9d91a8c11d947019ce81d822207c9 Mon Sep 17 00:00:00 2001 From: Juerg Billeter Date: Fri, 11 Jan 2008 21:44:01 +0000 Subject: update from gobject-introspection SVN, fixes bug 505920 2008-01-11 Juerg Billeter * gobject-introspection/: update from gobject-introspection SVN, fixes bug 505920 * vapigen/vala-gen-introspect/vala-gen-introspect.in: fix to work with updated gobject-introspection svn path=/trunk/; revision=829 --- gobject-introspection/Makefile.am | 15 +- gobject-introspection/clexer.l | 251 ----- gobject-introspection/cparser.y | 1236 --------------------- gobject-introspection/gen-introspect.c | 1372 ----------------------- gobject-introspection/gen-introspect.h | 157 --- gobject-introspection/gidlmodule.c | 23 +- gobject-introspection/gidlmodule.h | 11 +- gobject-introspection/gidlparser.c | 13 +- gobject-introspection/gidlwriter.c | 483 ++++++++ gobject-introspection/gidlwriter.h | 26 + gobject-introspection/girepository.h | 452 ++++++++ gobject-introspection/gmetadata.c | 1876 ++++++++++++++++++++++++++++++++ gobject-introspection/gmetadata.h | 24 +- gobject-introspection/scanner.c | 1824 +++++++++++++++++++++++++++++++ gobject-introspection/scanner.h | 167 +++ gobject-introspection/scannerlexer.l | 311 ++++++ gobject-introspection/scannerparser.y | 1376 +++++++++++++++++++++++ 17 files changed, 6573 insertions(+), 3044 deletions(-) delete mode 100644 gobject-introspection/clexer.l delete mode 100644 gobject-introspection/cparser.y delete mode 100644 gobject-introspection/gen-introspect.c delete mode 100644 gobject-introspection/gen-introspect.h create mode 100644 gobject-introspection/gidlwriter.c create mode 100644 gobject-introspection/gidlwriter.h create mode 100644 gobject-introspection/girepository.h create mode 100644 gobject-introspection/gmetadata.c create mode 100644 gobject-introspection/scanner.c create mode 100644 gobject-introspection/scanner.h create mode 100644 gobject-introspection/scannerlexer.l create mode 100644 gobject-introspection/scannerparser.y (limited to 'gobject-introspection') diff --git a/gobject-introspection/Makefile.am b/gobject-introspection/Makefile.am index 47e771fe8..4ec02752e 100644 --- a/gobject-introspection/Makefile.am +++ b/gobject-introspection/Makefile.am @@ -15,24 +15,29 @@ libgidl_la_SOURCES = \ gidlnode.h \ gidlparser.c \ gidlparser.h \ + girepository.h \ + gmetadata.c \ gmetadata.h \ $(NULL) libgidl_la_LIBADD = \ $(GLIB_LIBS) \ + $(GMODULE_LIBS) \ $(NULL) pkglibexecdir = $(libdir)/vala pkglibexec_PROGRAMS = gen-introspect -BUILT_SOURCES = cparser.h +BUILT_SOURCES = scannerparser.h AM_YFLAGS = -d gen_introspect_SOURCES = \ - clexer.l \ - cparser.y \ - gen-introspect.c \ - gen-introspect.h \ + gidlwriter.c \ + gidlwriter.h \ + scanner.c \ + scanner.h \ + scannerlexer.l \ + scannerparser.y \ $(NULL) gen_introspect_LDADD = \ diff --git a/gobject-introspection/clexer.l b/gobject-introspection/clexer.l deleted file mode 100644 index b0c9cd6cc..000000000 --- a/gobject-introspection/clexer.l +++ /dev/null @@ -1,251 +0,0 @@ -/* GObject introspection: C lexer - * - * Copyright (c) 1997 Sandro Sigala - * Copyright (c) 2007 Jürg Billeter - * - * 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 -#include - -#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, "%s:%d: unexpected character `%c'\n", the_igenerator->current_filename, 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, found_filename; - - lineno = 0; - found_filename = FALSE; - in_string = FALSE; - filename_builder = g_string_new (""); - - int c = input (); - while (c != EOF && c != '\n') { - if (!in_string) { - if (c == '\"') { - in_string = TRUE; - found_filename = TRUE; - } else if (c >= '0' && c <= '9') { - if (!found_filename) { - lineno = lineno * 10 + (c - '0'); - } - } - } 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 (); - } - - if (filename_builder->len > 0) { - char *filename = g_strcompress (filename_builder->str); - g_free (the_igenerator->current_filename); - the_igenerator->current_filename = filename; - } - - g_string_free (filename_builder, TRUE); -} - diff --git a/gobject-introspection/cparser.y b/gobject-introspection/cparser.y deleted file mode 100644 index c29ca8f81..000000000 --- a/gobject-introspection/cparser.y +++ /dev/null @@ -1,1236 +0,0 @@ -/* GObject introspection: C parser - * - * Copyright (c) 1997 Sandro Sigala - * Copyright (c) 2007 Jürg Billeter - * - * 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 -#include -#include -#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 IDENTIFIER "identifier" -%token 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 declaration_specifiers -%type enum_specifier -%type pointer -%type specifier_qualifier_list -%type struct_or_union -%type struct_or_union_specifier -%type type_specifier -%type identifier -%type typedef_name -%type identifier_or_typedef_name -%type abstract_declarator -%type init_declarator -%type declarator -%type enumerator -%type direct_abstract_declarator -%type direct_declarator -%type parameter_declaration -%type struct_declarator -%type enumerator_list -%type identifier_list -%type init_declarator_list -%type parameter_type_list -%type parameter_list -%type struct_declaration -%type struct_declaration_list -%type struct_declarator_list -%type storage_class_specifier -%type type_qualifier -%type type_qualifier_list -%type function_specifier -%type expression -%type constant_expression -%type conditional_expression -%type logical_and_expression -%type logical_or_expression -%type inclusive_or_expression -%type exclusive_or_expression -%type multiplicative_expression -%type additive_expression -%type shift_expression -%type relational_expression -%type equality_expression -%type and_expression -%type cast_expression -%type assignment_expression -%type unary_expression -%type postfix_expression -%type primary_expression -%type unary_operator -%type function_macro -%type object_macro -%type strings - -%% - -/* 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); - } - | strings - | '(' expression ')' - { - $$ = $2; - } - ; - -/* concatenate adjacent string literal tokens */ -strings - : STRING - { - $$ = csymbol_new (CSYMBOL_TYPE_CONST); - yytext[strlen (yytext) - 1] = '\0'; - $$->const_string = g_strcompress (yytext + 1); - } - | strings STRING - { - char *strings, *string2; - $$ = $1; - yytext[strlen (yytext) - 1] = '\0'; - string2 = g_strcompress (yytext + 1); - strings = g_strconcat ($$->const_string, string2, NULL); - g_free ($$->const_string); - g_free (string2); - $$->const_string = strings; - } - ; - -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 - : /* empty, support for anonymous structs and unions */ - { - $$ = csymbol_new (CSYMBOL_TYPE_INVALID); - } - | 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, "%s:%d: %s\n", the_igenerator->current_filename, 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 deleted file mode 100644 index edd64ab5d..000000000 --- a/gobject-introspection/gen-introspect.c +++ /dev/null @@ -1,1372 +0,0 @@ -/* 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 - */ - -#include -#include -#include -#include -#include -#include -#include -#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", 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 ("\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 ("\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 ("\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 ("\n", node->node.name, node->type->unparsed, node->readable ? "1" : "0", node->writable ? "1" : "0", node->construct ? "1" : "0", node->construct_only ? "1" : "0"); - 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 ("\n", node->node.name); - } else if (node->is_constructor) { - tag_name = "constructor"; - markup = g_markup_printf_escaped ("\n", node->node.name, node->symbol); - } else if (node->is_method) { - tag_name = "method"; - markup = g_markup_printf_escaped ("\n", node->node.name, node->symbol); - } else { - tag_name = "function"; - markup = g_markup_printf_escaped ("\n", node->node.name, node->symbol); - } - - g_igenerator_write_indent (igenerator, markup); - g_free (markup); - markup = g_markup_printf_escaped ("\n", node->result->type->unparsed); - g_igenerator_write (igenerator, markup); - g_free (markup); - if (node->parameters != NULL) { - GList *l; - g_igenerator_write_indent (igenerator, "\n"); - for (l = node->parameters; l != NULL; l = l->next) { - GIdlNodeParam *param = l->data; - markup = g_markup_printf_escaped ("\n", param->node.name, param->type->unparsed); - g_igenerator_write (igenerator, markup); - g_free (markup); - } - g_igenerator_write_unindent (igenerator, "\n"); - } - markup = g_strdup_printf ("\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 ("\n", node->node.name); - g_igenerator_write_indent (igenerator, markup); - g_free (markup); - markup = g_markup_printf_escaped ("\n", node->result->type->unparsed); - g_igenerator_write (igenerator, markup); - g_free (markup); - if (node->parameters != NULL) { - GList *l; - g_igenerator_write_indent (igenerator, "\n"); - for (l = node->parameters; l != NULL; l = l->next) { - GIdlNodeParam *param = l->data; - markup = g_markup_printf_escaped ("\n", param->node.name, param->type->unparsed); - g_igenerator_write (igenerator, markup); - g_free (markup); - } - g_igenerator_write_unindent (igenerator, "\n"); - } - g_igenerator_write_unindent (igenerator, "\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 ("\n", node->node.name, when); - g_igenerator_write_indent (igenerator, markup); - g_free (markup); - markup = g_markup_printf_escaped ("\n", node->result->type->unparsed); - g_igenerator_write (igenerator, markup); - g_free (markup); - if (node->parameters != NULL) { - GList *l; - g_igenerator_write_indent (igenerator, "\n"); - for (l = node->parameters; l != NULL; l = l->next) { - GIdlNodeParam *param = l->data; - markup = g_markup_printf_escaped ("\n", param->node.name, param->type->unparsed); - g_igenerator_write (igenerator, markup); - g_free (markup); - } - g_igenerator_write_unindent (igenerator, "\n"); - } - g_igenerator_write_unindent (igenerator, "\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 ("\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 ("\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, "\n"); - for (l = node->interfaces; l != NULL; l = l->next) { - markup = g_markup_printf_escaped ("\n", (char *) l->data); - g_igenerator_write (igenerator, markup); - g_free (markup); - } - g_igenerator_write_unindent (igenerator, "\n"); - } else if (node->node.type == G_IDL_NODE_INTERFACE && node->prerequisites != NULL) { - GList *l; - g_igenerator_write_indent (igenerator, "\n"); - for (l = node->prerequisites; l != NULL; l = l->next) { - markup = g_markup_printf_escaped ("\n", (char *) l->data); - g_igenerator_write (igenerator, markup); - g_free (markup); - } - g_igenerator_write_unindent (igenerator, "\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, "\n"); - } else if (node->node.type == G_IDL_NODE_INTERFACE) { - g_igenerator_write_unindent (igenerator, "\n"); - } -} - -static void struct_generate (GIGenerator *igenerator, GIdlNodeStruct *node) -{ - GList *l; - char *markup = g_markup_printf_escaped ("\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, "\n"); -} - -static void union_generate (GIGenerator *igenerator, GIdlNodeUnion *node) -{ - GList *l; - char *markup = g_markup_printf_escaped ("\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, "\n"); -} - -static void boxed_generate (GIGenerator *igenerator, GIdlNodeBoxed *node) -{ - GList *l; - char *markup = g_markup_printf_escaped ("\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, "\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 ("\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 ("\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, "\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); - giprop->readable = (properties[i]->flags & G_PARAM_READABLE) != 0; - giprop->writable = (properties[i]->flags & G_PARAM_WRITABLE) != 0; - giprop->construct = (properties[i]->flags & G_PARAM_CONSTRUCT) != 0; - giprop->construct_only = (properties[i]->flags & G_PARAM_CONSTRUCT_ONLY) != 0; - } -} - -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; - - if (get_type_symbol == NULL) { - /* ignore already processed functions */ - continue; - } - - TypeFunction type_fun; - if (!g_module_symbol (module, get_type_symbol, (gpointer*) &type_fun)) { - continue; - } - - /* symbol found, ignore in future iterations */ - l->data = NULL; - - 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; - int i; - for (param_l = sym->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_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") || g_str_has_suffix (sym->ident, "Interface"))) { - char *base_name; - if (g_str_has_suffix (sym->ident, "Interface")) { - base_name = g_strndup (sym->ident, strlen (sym->ident) - strlen ("Interface")); - } else { - base_name = g_strndup (sym->ident, strlen (sym->ident) - strlen ("Class")); - } - 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; - if (vfunc_param->ident != NULL) { - 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; - int i; - for (param_l = member->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); - 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 (l->data, 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")) { - if (sym->base_type->child_list == NULL) { - // ignore get_type functions with parameters - 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, "\n"); - g_igenerator_write_indent (igenerator, "\n"); - module_generate (igenerator, igenerator->module); - g_igenerator_write_unindent (igenerator, "\n"); -} - -int main (int argc, char **argv) -{ - g_type_init (); - - /* initialize threading as this may be required by libraries that we'll use */ - g_thread_init (NULL); - - 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"); - int line = 1; - - 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); - line++; - continue; - } - - /* print current location */ - str = g_strescape (l->data, ""); - fprintf (fmacros, "# %d \"%s\"\n", line, str); - g_free (str); - - 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); - line++; - 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); - line++; - 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); - line++; - continue; - } - - g_assert (c == ')'); - g_string_append_c (define_line, c); - c = fgetc (f); - - /* found function-like macro */ - fprintf (fmacros, "%s\n", define_line->str); - - g_string_free (define_line, TRUE); - /* ignore rest of line */ - c = eat_line (f, c); - line++; - continue; - } - if (c != ' ' && c != '\t') { - g_string_free (define_line, TRUE); - /* ignore line */ - c = eat_line (f, c); - line++; - 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, "%s\n", define_line->str); - - c = eat_line (f, c); - line++; - } - - 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 deleted file mode 100644 index 91d4ab066..000000000 --- a/gobject-introspection/gen-introspect.h +++ /dev/null @@ -1,157 +0,0 @@ -/* 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 - */ - -#ifndef __GEN_INTROSPECT_H__ -#define __GEN_INTROSPECT_H__ - -#include -#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 - diff --git a/gobject-introspection/gidlmodule.c b/gobject-introspection/gidlmodule.c index 2d4929e0a..d17a249a0 100644 --- a/gobject-introspection/gidlmodule.c +++ b/gobject-introspection/gidlmodule.c @@ -23,20 +23,23 @@ #include "gidlmodule.h" #include "gidlnode.h" -#include "gmetadata.h" #define ALIGN_VALUE(this, boundary) \ (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) GIdlModule * -g_idl_module_new (const gchar *name) +g_idl_module_new (const gchar *name, const gchar *shared_library) { GIdlModule *module; module = g_new (GIdlModule, 1); module->name = g_strdup (name); + if (shared_library) + module->shared_library = g_strdup (shared_library); + else + module->shared_library = NULL; module->entries = NULL; return module; @@ -57,12 +60,12 @@ g_idl_module_free (GIdlModule *module) g_free (module); } -void +GMetadata * g_idl_module_build_metadata (GIdlModule *module, - GList *modules, - guchar **metadata, - gsize *length) + GList *modules) { + guchar *metadata; + gsize length; gint i; GList *e; Header *header; @@ -116,6 +119,9 @@ g_idl_module_build_metadata (GIdlModule *module, header->annotations = 0; /* filled in later */ header->size = 0; /* filled in later */ header->namespace = write_string (module->name, strings, data, &header_size); + header->shared_library = (module->shared_library? + write_string (module->shared_library, strings, data, &header_size) + : 0); header->directory = ALIGN_VALUE (header_size, 4); header->entry_blob_size = 12; header->function_blob_size = 16; @@ -202,7 +208,8 @@ g_idl_module_build_metadata (GIdlModule *module, g_message ("reallocating to %d bytes", offset2); - *metadata = g_realloc (data, offset2); - *length = header->size = offset2; + metadata = g_realloc (data, offset2); + length = header->size = offset2; + return g_metadata_new_from_memory (metadata, length); } diff --git a/gobject-introspection/gidlmodule.h b/gobject-introspection/gidlmodule.h index 17135764c..3564a75fc 100644 --- a/gobject-introspection/gidlmodule.h +++ b/gobject-introspection/gidlmodule.h @@ -22,6 +22,7 @@ #define __G_IDL_MODULE_H__ #include +#include "gmetadata.h" G_BEGIN_DECLS @@ -31,16 +32,16 @@ typedef struct _GIdlModule GIdlModule; struct _GIdlModule { gchar *name; + gchar *shared_library; GList *entries; }; -GIdlModule *g_idl_module_new (const gchar *name); +GIdlModule *g_idl_module_new (const gchar *name, + const gchar *module_filename); void g_idl_module_free (GIdlModule *module); -void g_idl_module_build_metadata (GIdlModule *module, - GList *modules, - guchar **metadata, - gsize *length); +GMetadata * g_idl_module_build_metadata (GIdlModule *module, + GList *modules); G_END_DECLS diff --git a/gobject-introspection/gidlparser.c b/gobject-introspection/gidlparser.c index 150861708..3d5292619 100644 --- a/gobject-introspection/gidlparser.c +++ b/gobject-introspection/gidlparser.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "gidlmodule.h" @@ -92,6 +93,11 @@ parse_type_internal (gchar *str, gchar **rest) { "void", TYPE_TAG_VOID, 0 }, { "gpointer", TYPE_TAG_VOID, 1 }, { "gboolean", TYPE_TAG_BOOLEAN, 0 }, +#if 0 + { "char", TYPE_TAG_INT8, 0 }, + { "gchar", TYPE_TAG_INT8, 0 }, + { "guchar", TYPE_TAG_UINT8, 0 }, +#endif { "int8_t", TYPE_TAG_INT8, 0 }, { "int8", TYPE_TAG_INT8, 0 }, { "gint8", TYPE_TAG_INT8, 0 }, @@ -1724,15 +1730,16 @@ start_element_handler (GMarkupParseContext *context, case 'n': if (strcmp (element_name, "namespace") == 0 && ctx->state == STATE_ROOT) { - const gchar *name; + const gchar *name, *shared_library; name = find_attribute ("name", attribute_names, attribute_values); + shared_library = find_attribute ("shared-library", attribute_names, attribute_values); if (name == NULL) MISSING_ATTRIBUTE (error, element_name, "name"); else { - ctx->current_module = g_idl_module_new (name); + ctx->current_module = g_idl_module_new (name, shared_library); ctx->modules = g_list_append (ctx->modules, ctx->current_module); ctx->state = STATE_NAMESPACE; @@ -1863,7 +1870,7 @@ end_element_handler (GMarkupParseContext *context, case STATE_NAMESPACE: if (strcmp (element_name, "namespace") == 0) - { + { ctx->current_module = NULL; ctx->state = STATE_ROOT; } diff --git a/gobject-introspection/gidlwriter.c b/gobject-introspection/gidlwriter.c new file mode 100644 index 000000000..d46762bc0 --- /dev/null +++ b/gobject-introspection/gidlwriter.c @@ -0,0 +1,483 @@ +/* GObject introspection: gen-introspect + * + * Copyright (C) 2007 Jürg Billeter + * Copyright (C) 2007 Johan Dahlin + * + * 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 + */ + +#include +#include +#include "scanner.h" +#include "gidlnode.h" + +typedef struct { + int indent; + FILE *output; +} GIdlWriter; + +static void node_generate (GIdlWriter * writer, GIdlNode * node); + +static void +g_writer_write_inline (GIdlWriter * writer, const char *s) +{ + fprintf (writer->output, "%s", s); +} + +static void +g_writer_write (GIdlWriter * writer, const char *s) +{ + int i; + for (i = 0; i < writer->indent; i++) + { + fprintf (writer->output, "\t"); + } + + g_writer_write_inline (writer, s); +} + +static void +g_writer_write_indent (GIdlWriter * writer, const char *s) +{ + g_writer_write (writer, s); + writer->indent++; +} + +static void +g_writer_write_unindent (GIdlWriter * writer, const char *s) +{ + writer->indent--; + g_writer_write (writer, s); +} + +static void +field_generate (GIdlWriter * writer, GIdlNodeField * node) +{ + char *markup = + g_markup_printf_escaped ("\n", + node->node.name, node->type->unparsed); + g_writer_write (writer, markup); + g_free (markup); +} + +static void +value_generate (GIdlWriter * writer, GIdlNodeValue * node) +{ + char *markup = + g_markup_printf_escaped ("\n", + node->node.name, node->value); + g_writer_write (writer, markup); + g_free (markup); +} + +static void +constant_generate (GIdlWriter * writer, GIdlNodeConstant * node) +{ + char *markup = + g_markup_printf_escaped + ("\n", node->node.name, + node->type->unparsed, node->value); + g_writer_write (writer, markup); + g_free (markup); +} + +static void +property_generate (GIdlWriter * writer, GIdlNodeProperty * node) +{ + char *markup = + g_markup_printf_escaped ("\n", + node->node.name, + node->type->unparsed, + node->readable ? "1" : "0", + node->writable ? "1" : "0", + node->construct ? "1" : "0", + node->construct_only ? "1" : "0"); + g_writer_write (writer, markup); + g_free (markup); +} + +static void +function_generate (GIdlWriter * writer, GIdlNodeFunction * node) +{ + const char *tag_name; + GString *markup_s; + gchar *markup; + + if (node->node.type == G_IDL_NODE_CALLBACK) + tag_name = "callback"; + else if (node->is_constructor) + tag_name = "constructor"; + else if (node->is_method) + tag_name = "method"; + else + tag_name = "function"; + + markup_s = g_string_new ("<"); + g_string_append_printf (markup_s, + "%s name=\"%s\"", + tag_name, node->node.name); + + if (node->node.type != G_IDL_NODE_CALLBACK) + g_string_append_printf (markup_s, + g_markup_printf_escaped (" symbol=\"%s\"", node->symbol)); + + if (node->deprecated) + g_string_append_printf (markup_s, " deprecated=\"1\""); + + g_string_append (markup_s, ">\n"); + + g_writer_write_indent (writer, markup_s->str); + g_string_free (markup_s, TRUE); + + markup = + g_markup_printf_escaped ("\n", + node->result->type->unparsed); + g_writer_write (writer, markup); + g_free (markup); + + if (node->parameters != NULL) + { + GList *l; + g_writer_write_indent (writer, "\n"); + for (l = node->parameters; l != NULL; l = l->next) + { + GIdlNodeParam *param = l->data; + markup = + g_markup_printf_escaped ("\n", + param->node.name, param->type->unparsed); + g_writer_write (writer, markup); + g_free (markup); + } + g_writer_write_unindent (writer, "\n"); + } + markup = g_strdup_printf ("\n", tag_name); + g_writer_write_unindent (writer, markup); + g_free (markup); +} + +static void +vfunc_generate (GIdlWriter * writer, GIdlNodeVFunc * node) +{ + char *markup = + g_markup_printf_escaped ("\n", node->node.name); + g_writer_write_indent (writer, markup); + g_free (markup); + markup = + g_markup_printf_escaped ("\n", + node->result->type->unparsed); + g_writer_write (writer, markup); + g_free (markup); + if (node->parameters != NULL) + { + GList *l; + g_writer_write_indent (writer, "\n"); + for (l = node->parameters; l != NULL; l = l->next) + { + GIdlNodeParam *param = l->data; + markup = + g_markup_printf_escaped ("\n", + param->node.name, param->type->unparsed); + g_writer_write (writer, markup); + g_free (markup); + } + g_writer_write_unindent (writer, "\n"); + } + g_writer_write_unindent (writer, "\n"); +} + +static void +signal_generate (GIdlWriter * writer, 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 ("\n", + node->node.name, when); + g_writer_write_indent (writer, markup); + g_free (markup); + markup = + g_markup_printf_escaped ("\n", + node->result->type->unparsed); + g_writer_write (writer, markup); + g_free (markup); + if (node->parameters != NULL) + { + GList *l; + g_writer_write_indent (writer, "\n"); + for (l = node->parameters; l != NULL; l = l->next) + { + GIdlNodeParam *param = l->data; + markup = + g_markup_printf_escaped ("\n", + param->node.name, param->type->unparsed); + g_writer_write (writer, markup); + g_free (markup); + } + g_writer_write_unindent (writer, "\n"); + } + g_writer_write_unindent (writer, "\n"); +} + +static void +interface_generate (GIdlWriter * writer, GIdlNodeInterface * node) +{ + GList *l; + char *markup; + if (node->node.type == G_IDL_NODE_OBJECT) + { + markup = + g_markup_printf_escaped ("\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 + ("\n", + node->node.name, node->gtype_name, node->gtype_init); + } + + g_writer_write_indent (writer, markup); + g_free (markup); + if (node->node.type == G_IDL_NODE_OBJECT && node->interfaces != NULL) + { + GList *l; + g_writer_write_indent (writer, "\n"); + for (l = node->interfaces; l != NULL; l = l->next) + { + markup = + g_markup_printf_escaped ("\n", + (char *) l->data); + g_writer_write (writer, markup); + g_free (markup); + } + g_writer_write_unindent (writer, "\n"); + } + else if (node->node.type == G_IDL_NODE_INTERFACE + && node->prerequisites != NULL) + { + GList *l; + g_writer_write_indent (writer, "\n"); + for (l = node->prerequisites; l != NULL; l = l->next) + { + markup = + g_markup_printf_escaped ("\n", + (char *) l->data); + g_writer_write (writer, markup); + g_free (markup); + } + g_writer_write_unindent (writer, "\n"); + } + + for (l = node->members; l != NULL; l = l->next) + { + node_generate (writer, l->data); + } + + if (node->node.type == G_IDL_NODE_OBJECT) + { + g_writer_write_unindent (writer, "\n"); + } + else if (node->node.type == G_IDL_NODE_INTERFACE) + { + g_writer_write_unindent (writer, "\n"); + } +} + +static void +struct_generate (GIdlWriter * writer, GIdlNodeStruct * node) +{ + GList *l; + char *markup = + g_markup_printf_escaped ("\n", node->node.name); + g_writer_write_indent (writer, markup); + g_free (markup); + for (l = node->members; l != NULL; l = l->next) + { + node_generate (writer, l->data); + } + g_writer_write_unindent (writer, "\n"); +} + +static void +union_generate (GIdlWriter * writer, GIdlNodeUnion * node) +{ + GList *l; + char *markup = + g_markup_printf_escaped ("\n", node->node.name); + g_writer_write_indent (writer, markup); + g_free (markup); + for (l = node->members; l != NULL; l = l->next) + { + node_generate (writer, l->data); + } + g_writer_write_unindent (writer, "\n"); +} + +static void +boxed_generate (GIdlWriter * writer, GIdlNodeBoxed * node) +{ + GList *l; + char *markup = + g_markup_printf_escaped + ("\n", + node->node.name, node->gtype_name, node->gtype_init); + g_writer_write_indent (writer, markup); + g_free (markup); + for (l = node->members; l != NULL; l = l->next) + { + node_generate (writer, l->data); + } + g_writer_write_unindent (writer, "\n"); +} + +static void +enum_generate (GIdlWriter * writer, 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_writer_write_indent (writer, markup); + g_free (markup); + + for (l = node->values; l != NULL; l = l->next) + { + node_generate (writer, l->data); + } + + markup = g_strdup_printf ("\n", tag_name); + g_writer_write_unindent (writer, markup); + g_free (markup); +} + +static void +node_generate (GIdlWriter * writer, GIdlNode * node) +{ + switch (node->type) + { + case G_IDL_NODE_FUNCTION: + case G_IDL_NODE_CALLBACK: + function_generate (writer, (GIdlNodeFunction *) node); + break; + case G_IDL_NODE_VFUNC: + vfunc_generate (writer, (GIdlNodeVFunc *) node); + break; + case G_IDL_NODE_OBJECT: + case G_IDL_NODE_INTERFACE: + interface_generate (writer, (GIdlNodeInterface *) node); + break; + case G_IDL_NODE_STRUCT: + struct_generate (writer, (GIdlNodeStruct *) node); + break; + case G_IDL_NODE_UNION: + union_generate (writer, (GIdlNodeUnion *) node); + break; + case G_IDL_NODE_BOXED: + boxed_generate (writer, (GIdlNodeBoxed *) node); + break; + case G_IDL_NODE_ENUM: + case G_IDL_NODE_FLAGS: + enum_generate (writer, (GIdlNodeEnum *) node); + break; + case G_IDL_NODE_PROPERTY: + property_generate (writer, (GIdlNodeProperty *) node); + break; + case G_IDL_NODE_FIELD: + field_generate (writer, (GIdlNodeField *) node); + break; + case G_IDL_NODE_SIGNAL: + signal_generate (writer, (GIdlNodeSignal *) node); + break; + case G_IDL_NODE_VALUE: + value_generate (writer, (GIdlNodeValue *) node); + break; + case G_IDL_NODE_CONSTANT: + constant_generate (writer, (GIdlNodeConstant *) node); + break; + default: + g_assert_not_reached (); + } +} + +static void +g_writer_write_module (GIdlWriter * writer, GIdlModule * module) +{ + GList *l; + char *markup = + g_markup_printf_escaped ("\n", module->name); + g_writer_write_indent (writer, markup); + g_free (markup); + for (l = module->entries; l != NULL; l = l->next) + { + node_generate (writer, l->data); + } + g_writer_write_unindent (writer, "\n"); +} + +void +g_idl_writer_save_file (GIdlModule *module, + const gchar *filename) +{ + GIdlWriter *writer; + + writer = g_new0 (GIdlWriter, 1); + + if (!filename) + writer->output = stdout; + else + writer->output = fopen (filename, "w"); + + g_writer_write (writer, "\n"); + g_writer_write_indent (writer, "\n"); + g_writer_write_module (writer, module); + g_writer_write_unindent (writer, "\n"); + + if (filename) + fclose (writer->output); +} diff --git a/gobject-introspection/gidlwriter.h b/gobject-introspection/gidlwriter.h new file mode 100644 index 000000000..5d41a0c6a --- /dev/null +++ b/gobject-introspection/gidlwriter.h @@ -0,0 +1,26 @@ +/* GObject introspection: IDL writer + * + * Copyright (C) 2007 Johan Dahlin + * + * 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 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. + */ + +#ifndef __G_IDL_WRITER_H__ +#define __G_IDL_WRITER_H__ + +void g_idl_writer_save_file (GIdlModule *module, const gchar *filename); + +#endif /* __G_IDL_WRITER_H__ */ diff --git a/gobject-introspection/girepository.h b/gobject-introspection/girepository.h new file mode 100644 index 000000000..7ad1067a1 --- /dev/null +++ b/gobject-introspection/girepository.h @@ -0,0 +1,452 @@ +/* GObject introspection: Repository + * + * Copyright (C) 2005 Matthias Clasen + * + * 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 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. + */ + +#ifndef __G_IREPOSITORY_H__ +#define __G_IREPOSITORY_H__ + +#include +#include + +G_BEGIN_DECLS + +#define G_TYPE_IREPOSITORY (g_irepository_get_type ()) +#define G_IREPOSITORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_IREPOSITORY, GIRepository)) + +typedef struct _GIRepository GIRepository; +typedef struct _GIRepositoryClass GIRepositoryClass; +typedef struct _GIRepositoryPrivate GIRepositoryPrivate; +typedef struct _GIBaseInfo GIBaseInfo; +typedef struct _GICallableInfo GICallableInfo; +typedef struct _GIFunctionInfo GIFunctionInfo; +typedef struct _GICallbackInfo GICallbackInfo; +typedef struct _GIRegisteredTypeInfo GIRegisteredTypeInfo; +typedef struct _GIStructInfo GIStructInfo; +typedef struct _GIUnionInfo GIUnionInfo; +typedef struct _GIEnumInfo GIEnumInfo; +typedef struct _GIObjectInfo GIObjectInfo; +typedef struct _GIInterfaceInfo GIInterfaceInfo; +typedef struct _GIConstantInfo GIConstantInfo; +typedef struct _GIValueInfo GIValueInfo; +typedef struct _GISignalInfo GISignalInfo; +typedef struct _GIVFuncInfo GIVFuncInfo; +typedef struct _GIPropertyInfo GIPropertyInfo; +typedef struct _GIFieldInfo GIFieldInfo; +typedef struct _GIArgInfo GIArgInfo; +typedef struct _GITypeInfo GITypeInfo; +typedef struct _GIErrorDomainInfo GIErrorDomainInfo; +typedef struct _GIUnresolvedInfo GIUnresolvedInfo; +typedef struct _GMetadata GMetadata; + +struct _GIRepository +{ + GObject parent; + + /*< private >*/ + GIRepositoryPrivate *priv; +}; + +struct _GIRepositoryClass +{ + GObjectClass parent; +}; + + +/* Repository */ + +GType g_irepository_get_type (void) G_GNUC_CONST; +GIRepository *g_irepository_get_default (void); +const gchar * g_irepository_register (GIRepository *repository, + GMetadata *metadata); +void g_irepository_unregister (GIRepository *repository, + const gchar *namespace); +const gchar * g_irepository_register_file (GIRepository *repository, + const gchar *filename, + GError **error); +gboolean g_irepository_is_registered (GIRepository *repository, + const gchar *namespace); +GIBaseInfo * g_irepository_find_by_name (GIRepository *repository, + const gchar *namespace, + const gchar *name); +gchar ** g_irepository_get_namespaces (GIRepository *repository); +GIBaseInfo * g_irepository_find_by_gtype (GIRepository *repository, + GType gtype); +gint g_irepository_get_n_infos (GIRepository *repository, + const gchar *namespace); +GIBaseInfo * g_irepository_get_info (GIRepository *repository, + const gchar *namespace, + gint index); +const gchar * g_irepository_get_shared_library (GIRepository *repository, + const gchar *namespace); +/* Metadata */ + +GMetadata * g_metadata_new_from_memory (guchar *memory, + gsize len); +GMetadata * g_metadata_new_from_const_memory (const guchar *memory, + gsize len); +GMetadata * g_metadata_new_from_mapped_file (GMappedFile *mfile); +void g_metadata_free (GMetadata *metadata); +void g_metadata_set_module (GMetadata *metadata, + GModule *module); +const gchar * g_metadata_get_namespace (GMetadata *metadata); + +typedef enum +{ + G_IREPOSITORY_ERROR_METADATA_NOT_FOUND, + G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH, + G_IREPOSITORY_ERROR_LIBRARY_NOT_FOUND +} GIRepositoryError; + +#define G_IREPOSITORY_ERROR (g_irepository_error_quark ()) + +GQuark g_irepository_error_quark (void); + + +/* Types of objects registered in the repository */ + +typedef enum +{ + GI_INFO_TYPE_INVALID, + GI_INFO_TYPE_FUNCTION, + GI_INFO_TYPE_CALLBACK, + GI_INFO_TYPE_STRUCT, + GI_INFO_TYPE_BOXED, + GI_INFO_TYPE_ENUM, + GI_INFO_TYPE_FLAGS, + GI_INFO_TYPE_OBJECT, + GI_INFO_TYPE_INTERFACE, + GI_INFO_TYPE_CONSTANT, + GI_INFO_TYPE_ERROR_DOMAIN, + GI_INFO_TYPE_UNION, + GI_INFO_TYPE_VALUE, + GI_INFO_TYPE_SIGNAL, + GI_INFO_TYPE_VFUNC, + GI_INFO_TYPE_PROPERTY, + GI_INFO_TYPE_FIELD, + GI_INFO_TYPE_ARG, + GI_INFO_TYPE_TYPE, + GI_INFO_TYPE_UNRESOLVED +} GIInfoType; + + +/* GIBaseInfo */ + +GIBaseInfo * g_base_info_ref (GIBaseInfo *info); +void g_base_info_unref (GIBaseInfo *info); +GIInfoType g_base_info_get_type (GIBaseInfo *info); +const gchar * g_base_info_get_name (GIBaseInfo *info); +const gchar * g_base_info_get_namespace (GIBaseInfo *info); +gboolean g_base_info_is_deprecated (GIBaseInfo *info); +const gchar * g_base_info_get_annotation (GIBaseInfo *info, + const gchar *name); +GIBaseInfo * g_base_info_get_container (GIBaseInfo *info); +GMetadata * g_base_info_get_metadata (GIBaseInfo *info); + +GIBaseInfo * g_info_new (GIInfoType type, + GIBaseInfo *container, + GMetadata *metadata, + guint32 offset); + + +/* GIFunctionInfo */ + +typedef enum +{ + GI_FUNCTION_IS_METHOD = 1 << 0, + GI_FUNCTION_IS_CONSTRUCTOR = 1 << 1, + GI_FUNCTION_IS_GETTER = 1 << 2, + GI_FUNCTION_IS_SETTER = 1 << 3, + GI_FUNCTION_WRAPS_VFUNC = 1 << 4 +} GIFunctionInfoFlags; + +const gchar * g_function_info_get_symbol (GIFunctionInfo *info); +GIFunctionInfoFlags g_function_info_get_flags (GIFunctionInfo *info); +GIPropertyInfo * g_function_info_get_property (GIFunctionInfo *info); +GIVFuncInfo * g_function_info_get_vfunc (GIFunctionInfo *info); + +typedef union +{ + gboolean v_boolean; + gint8 v_int8; + guint8 v_uint8; + gint16 v_int16; + guint16 v_uint16; + gint32 v_int32; + guint32 v_uint32; + gint64 v_int64; + guint64 v_uint64; + gfloat v_float; + gdouble v_double; + gint v_int; + guint v_uint; + glong v_long; + gulong v_ulong; + gssize v_ssize; + gsize v_size; + gchar * v_string; + gpointer v_pointer; +} GArgument; + +#define G_INVOKE_ERROR (g_invoke_error_quark ()) +GQuark g_invoke_error_quark (void); + +typedef enum +{ + G_INVOKE_ERROR_FAILED, + G_INVOKE_ERROR_SYMBOL_NOT_FOUND, + G_INVOKE_ERROR_ARGUMENT_MISMATCH +} GInvokeError; + +gboolean g_function_info_invoke (GIFunctionInfo *info, + const GArgument *in_args, + int n_in_args, + const GArgument *out_args, + int n_out_args, + GArgument *return_value, + GError **error); + + +/* GICallableInfo */ + +typedef enum { + GI_TRANSFER_NOTHING, + GI_TRANSFER_CONTAINER, + GI_TRANSFER_EVERYTHING +} GITransfer; + +GITypeInfo * g_callable_info_get_return_type (GICallableInfo *info); +GITransfer g_callable_info_get_caller_owns (GICallableInfo *info); +gboolean g_callable_info_may_return_null (GICallableInfo *info); +gint g_callable_info_get_n_args (GICallableInfo *info); +GIArgInfo * g_callable_info_get_arg (GICallableInfo *info, + gint n); + +/* GIArgInfo */ + +typedef enum { + GI_DIRECTION_IN, + GI_DIRECTION_OUT, + GI_DIRECTION_INOUT +} GIDirection; + +GIDirection g_arg_info_get_direction (GIArgInfo *info); +gboolean g_arg_info_is_dipper (GIArgInfo *info); +gboolean g_arg_info_is_return_value (GIArgInfo *info); +gboolean g_arg_info_is_optional (GIArgInfo *info); +gboolean g_arg_info_may_be_null (GIArgInfo *info); +GITransfer g_arg_info_get_ownership_transfer (GIArgInfo *info); +GITypeInfo * g_arg_info_get_type (GIArgInfo *info); + + +/* GITypeInfo */ + +typedef enum { + GI_TYPE_TAG_VOID = 0, + GI_TYPE_TAG_BOOLEAN = 1, + GI_TYPE_TAG_INT8 = 2, + GI_TYPE_TAG_UINT8 = 3, + GI_TYPE_TAG_INT16 = 4, + GI_TYPE_TAG_UINT16 = 5, + GI_TYPE_TAG_INT32 = 6, + GI_TYPE_TAG_UINT32 = 7, + GI_TYPE_TAG_INT64 = 8, + GI_TYPE_TAG_UINT64 = 9, + GI_TYPE_TAG_INT = 10, + GI_TYPE_TAG_UINT = 11, + GI_TYPE_TAG_LONG = 12, + GI_TYPE_TAG_ULONG = 13, + GI_TYPE_TAG_SSIZE = 14, + GI_TYPE_TAG_SIZE = 15, + GI_TYPE_TAG_FLOAT = 16, + GI_TYPE_TAG_DOUBLE = 17, + GI_TYPE_TAG_UTF8 = 18, + GI_TYPE_TAG_FILENAME = 19, + GI_TYPE_TAG_ARRAY = 20, + GI_TYPE_TAG_INTERFACE = 21, + GI_TYPE_TAG_GLIST = 22, + GI_TYPE_TAG_GSLIST = 23, + GI_TYPE_TAG_GHASH = 24, + GI_TYPE_TAG_ERROR = 25 +} GITypeTag; + +gboolean g_type_info_is_pointer (GITypeInfo *info); +GITypeTag g_type_info_get_tag (GITypeInfo *info); +GITypeInfo * g_type_info_get_param_type (GITypeInfo *info, + gint n); +GIBaseInfo * g_type_info_get_interface (GITypeInfo *info); +gint g_type_info_get_array_length (GITypeInfo *info); +gboolean g_type_info_is_zero_terminated (GITypeInfo *info); + +gint g_type_info_get_n_error_domains (GITypeInfo *info); +GIErrorDomainInfo *g_type_info_get_error_domain (GITypeInfo *info, + gint n); + +/* GIErrorDomainInfo */ + +const gchar * g_error_domain_info_get_quark (GIErrorDomainInfo *info); +GIInterfaceInfo * g_error_domain_info_get_codes (GIErrorDomainInfo *info); + + +/* GIValueInfo */ + +glong g_value_info_get_value (GIValueInfo *info); + + +/* GIFieldInfo */ + +typedef enum +{ + GI_FIELD_IS_READABLE = 1 << 0, + GI_FIELD_IS_WRITABLE = 1 << 1 +} GIFieldInfoFlags; + +GIFieldInfoFlags g_field_info_get_flags (GIFieldInfo *info); +gint g_field_info_get_size (GIFieldInfo *info); +gint g_field_info_get_offset (GIFieldInfo *info); +GITypeInfo * g_field_info_get_type (GIFieldInfo *info); + + +/* GIUnionInfo */ +gint g_union_info_get_n_fields (GIUnionInfo *info); +GIFieldInfo * g_union_info_get_field (GIUnionInfo *info, + gint n); +gint g_union_info_get_n_methods (GIUnionInfo *info); +GIFunctionInfo * g_union_info_get_method (GIUnionInfo *info, + gint n); +gboolean g_union_info_is_discriminated (GIUnionInfo *info); +gint g_union_info_get_discriminator_offset (GIUnionInfo *info); +GITypeInfo * g_union_info_get_discriminator_type (GIUnionInfo *info); +GIConstantInfo * g_union_info_get_discriminator (GIUnionInfo *info, + gint n); + + +/* GIStructInfo */ +gint g_struct_info_get_n_fields (GIStructInfo *info); +GIFieldInfo * g_struct_info_get_field (GIStructInfo *info, + gint n); +gint g_struct_info_get_n_methods (GIStructInfo *info); +GIFunctionInfo * g_struct_info_get_method (GIStructInfo *info, + gint n); +GIFunctionInfo * g_struct_info_find_method (GIStructInfo *info, + const gchar *name); + +/* GIRegisteredTypeInfo */ + +const gchar * g_registered_type_info_get_type_name (GIRegisteredTypeInfo *info); +const gchar * g_registered_type_info_get_type_init (GIRegisteredTypeInfo *info); + + +/* GIEnumInfo */ + +gint g_enum_info_get_n_values (GIEnumInfo *info); +GIValueInfo * g_enum_info_get_value (GIEnumInfo *info, + gint n); + +/* GIObjectInfo */ + +const gchar * g_object_info_get_type_name (GIObjectInfo *info); +const gchar * g_object_info_get_type_init (GIObjectInfo *info); +GIObjectInfo * g_object_info_get_parent (GIObjectInfo *info); +gint g_object_info_get_n_interfaces (GIObjectInfo *info); +GIInterfaceInfo * g_object_info_get_interface (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_fields (GIObjectInfo *info); +GIFieldInfo * g_object_info_get_field (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_properties (GIObjectInfo *info); +GIPropertyInfo * g_object_info_get_property (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_methods (GIObjectInfo *info); +GIFunctionInfo * g_object_info_get_method (GIObjectInfo *info, + gint n); +GIFunctionInfo * g_object_info_find_method (GIObjectInfo *info, + const gchar *name); +gint g_object_info_get_n_signals (GIObjectInfo *info); +GISignalInfo * g_object_info_get_signal (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_vfuncs (GIObjectInfo *info); +GIVFuncInfo * g_object_info_get_vfunc (GIObjectInfo *info, + gint n); +gint g_object_info_get_n_constants (GIObjectInfo *info); +GIConstantInfo * g_object_info_get_constant (GIObjectInfo *info, + gint n); + + +/* GIInterfaceInfo */ + +gint g_interface_info_get_n_prerequisites (GIInterfaceInfo *info); +GIBaseInfo * g_interface_info_get_prerequisite (GIInterfaceInfo *info, + gint n); +gint g_interface_info_get_n_properties (GIInterfaceInfo *info); +GIPropertyInfo * g_interface_info_get_property (GIInterfaceInfo *info, + gint n); +gint g_interface_info_get_n_methods (GIInterfaceInfo *info); +GIFunctionInfo * g_interface_info_get_method (GIInterfaceInfo *info, + gint n); +GIFunctionInfo * g_interface_info_find_method (GIInterfaceInfo *info, + const gchar *name); +gint g_interface_info_get_n_signals (GIInterfaceInfo *info); +GISignalInfo * g_interface_info_get_signal (GIInterfaceInfo *info, + gint n); +gint g_interface_info_get_n_vfuncs (GIInterfaceInfo *info); +GIVFuncInfo * g_interface_info_get_vfunc (GIInterfaceInfo *info, + gint n); +gint g_interface_info_get_n_constants (GIInterfaceInfo *info); +GIConstantInfo * g_interface_info_get_constant (GIInterfaceInfo *info, + gint n); + + +/* GIPropertyInfo */ + +GParamFlags g_property_info_get_flags (GIPropertyInfo *info); +GITypeInfo * g_property_info_get_type (GIPropertyInfo *info); + + +/* GISignalInfo */ + +GSignalFlags g_signal_info_get_flags (GISignalInfo *info); +GIVFuncInfo * g_signal_info_get_class_closure (GISignalInfo *info); +gboolean g_signal_info_true_stops_emit (GISignalInfo *info); + + +/* GIVFuncInfo */ + +typedef enum +{ + GI_VFUNC_MUST_CHAIN_UP = 1 << 0, + GI_VFUNC_MUST_OVERRIDE = 1 << 1, + GI_VFUNC_MUST_NOT_OVERRIDE = 1 << 2 +} GIVFuncInfoFlags; + +GIVFuncInfoFlags g_vfunc_info_get_flags (GIVFuncInfo *info); +gint g_vfunc_info_get_offset (GIVFuncInfo *info); +GISignalInfo * g_vfunc_info_get_signal (GIVFuncInfo *info); + + +/* GIConstantInfo */ + +GITypeInfo * g_constant_info_get_type (GIConstantInfo *info); +gint g_constant_info_get_value (GIConstantInfo *info, + GArgument *value); + + +G_END_DECLS + +#endif /* __G_IREPOSITORY_H__ */ + diff --git a/gobject-introspection/gmetadata.c b/gobject-introspection/gmetadata.c new file mode 100644 index 000000000..b68039043 --- /dev/null +++ b/gobject-introspection/gmetadata.c @@ -0,0 +1,1876 @@ +/* GObject introspection: metadata validation, auxiliary functions + * related to the binary metadata format + * + * Copyright (C) 2005 Matthias Clasen + * + * 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 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. + */ + +#include +#include + +#include + +#include "gmetadata.h" + + +#define ALIGN_VALUE(this, boundary) \ + (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) + + +DirEntry * +g_metadata_get_dir_entry (GMetadata *metadata, + guint16 index) +{ + Header *header = (Header *)metadata->data; + + return (DirEntry *)&metadata->data[header->directory + (index - 1) * header->entry_blob_size]; +} + +void +g_metadata_check_sanity (void) +{ + /* Check that struct layout is as we expect */ + g_assert (sizeof (Header) == 100); + g_assert (sizeof (DirEntry) == 12); + g_assert (sizeof (SimpleTypeBlob) == 4); + g_assert (sizeof (ArgBlob) == 12); + g_assert (sizeof (SignatureBlob) == 8); + g_assert (sizeof (CommonBlob) == 8); + g_assert (sizeof (FunctionBlob) == 16); + g_assert (sizeof (InterfaceTypeBlob) == 4); + g_assert (sizeof (ArrayTypeBlob) == 8); + g_assert (sizeof (ParamTypeBlob) == 4); + g_assert (sizeof (ErrorTypeBlob) == 4); + g_assert (sizeof (ErrorDomainBlob) == 16); + g_assert (sizeof (ValueBlob) == 12); + g_assert (sizeof (FieldBlob) == 12); + g_assert (sizeof (RegisteredTypeBlob) == 16); + g_assert (sizeof (StructBlob) == 20); + g_assert (sizeof (EnumBlob) == 20); + g_assert (sizeof (PropertyBlob) == 12); + g_assert (sizeof (SignalBlob) == 12); + g_assert (sizeof (VFuncBlob) == 16); + g_assert (sizeof (ObjectBlob) == 32); + g_assert (sizeof (InterfaceBlob) == 28); + g_assert (sizeof (ConstantBlob) == 20); + g_assert (sizeof (AnnotationBlob) == 12); + g_assert (sizeof (UnionBlob) == 28); +} + + +static gboolean +is_aligned (guint32 offset) +{ + return offset == ALIGN_VALUE (offset, 4); +} + +#define MAX_NAME_LEN 200 + +static gboolean +is_name (const guchar *data, guint32 offset) +{ + gchar *name; + + name = (gchar*)&data[offset]; + + if (!memchr (name, '\0', MAX_NAME_LEN)) + return FALSE; + + if (strspn (name, G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_") < strlen (name)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_header (GMetadata *metadata, + GError **error) +{ + Header *header; + + if (metadata->len < sizeof (Header)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + header = (Header *)metadata->data; + + if (strncmp (header->magic, G_IDL_MAGIC, 16) != 0) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Magic string not found"); + return FALSE; + + } + + if (header->major_version != 1 || header->minor_version != 0) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Version mismatch"); + return FALSE; + + } + + if (header->n_entries < header->n_local_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Inconsistent entry counts"); + return FALSE; + } + + if (header->size != metadata->len) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Metadata size mismatch"); + return FALSE; + } + + if (header->entry_blob_size != 12 || + header->function_blob_size != 16 || + header->callback_blob_size != 12 || + header->signal_blob_size != 12 || + header->vfunc_blob_size != 16 || + header->arg_blob_size != 12 || + header->property_blob_size != 12 || + header->field_blob_size != 12 || + header->value_blob_size != 12 || + header->constant_blob_size != 20 || + header->error_domain_blob_size != 16 || + header->annotation_blob_size != 12 || + header->signature_blob_size != 8 || + header->enum_blob_size != 20 || + header->struct_blob_size != 20 || + header->object_blob_size != 32 || + header->interface_blob_size != 28 || + header->union_blob_size != 28) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Blob size mismatch"); + return FALSE; + } + + if (!is_aligned (header->directory)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Misaligned directory"); + return FALSE; + } + + if (!is_aligned (header->annotations)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Misaligned annotations"); + return FALSE; + } + + if (header->annotations == 0 && header->n_annotations > 0) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Wrong number of annotations"); + return FALSE; + } + + if (!is_name (metadata->data, header->namespace)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_HEADER, + "Invalid namespace name"); + return FALSE; + } + + return TRUE; +} + +static gboolean validate_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error); + +static gboolean +validate_array_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + ArrayTypeBlob *blob; + + blob = (ArrayTypeBlob*)&metadata->data[offset]; + + if (!blob->pointer) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", blob->tag); + return FALSE; + } + + /* FIXME validate length */ + + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (ArrayTypeBlob, type), + 0, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_iface_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + InterfaceTypeBlob *blob; + Header *header; + + header = (Header *)metadata->data; + + blob = (InterfaceTypeBlob*)&metadata->data[offset]; + + if (blob->interface == 0 || blob->interface > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid directory index %d", blob->interface); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_param_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + gint n_params, + GError **error) +{ + ParamTypeBlob *blob; + gint i; + + blob = (ParamTypeBlob*)&metadata->data[offset]; + + if (!blob->pointer) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", blob->tag); + return FALSE; + } + + if (blob->n_types != n_params) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Parameter type number mismatch"); + return FALSE; + } + + for (i = 0; i < n_params; i++) + { + if (!validate_type_blob (metadata, + offset + sizeof (ParamTypeBlob) + + i * sizeof (SimpleTypeBlob), + 0, FALSE, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_error_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + ErrorTypeBlob *blob; + Header *header; + gint i; + DirEntry *entry; + + blob = (ErrorTypeBlob*)&metadata->data[offset]; + + header = (Header *)metadata->data; + + if (!blob->pointer) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", blob->tag); + return FALSE; + } + + for (i = 0; i < blob->n_domains; i++) + { + if (blob->domains[i] == 0 || blob->domains[i] > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid directory index %d", blob->domains[i]); + return FALSE; + } + + entry = g_metadata_get_dir_entry (metadata, blob->domains[i]); + + if (entry->blob_type != BLOB_TYPE_ERROR_DOMAIN && + (entry->local || entry->blob_type != BLOB_TYPE_INVALID)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +validate_type_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + SimpleTypeBlob *simple; + InterfaceTypeBlob *iface; + + simple = (SimpleTypeBlob *)&metadata->data[offset]; + + if (simple->reserved == 0 && + simple->reserved2 == 0) + { + if (simple->tag >= TYPE_TAG_ARRAY) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong tag in simple type"); + return FALSE; + } + + if (simple->tag >= TYPE_TAG_UTF8 && + !simple->pointer) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", simple->tag); + return FALSE; + } + + return TRUE; + } + + iface = (InterfaceTypeBlob*)&metadata->data[simple->offset]; + + switch (iface->tag) + { + case TYPE_TAG_ARRAY: + if (!validate_array_type_blob (metadata, simple->offset, + signature_offset, return_type, error)) + return FALSE; + break; + case TYPE_TAG_INTERFACE: + if (!validate_iface_type_blob (metadata, simple->offset, + signature_offset, return_type, error)) + return FALSE; + break; + case TYPE_TAG_LIST: + case TYPE_TAG_SLIST: + if (!validate_param_type_blob (metadata, simple->offset, + signature_offset, return_type, 1, error)) + return FALSE; + break; + case TYPE_TAG_HASH: + if (!validate_param_type_blob (metadata, simple->offset, + signature_offset, return_type, 2, error)) + return FALSE; + break; + case TYPE_TAG_ERROR: + if (!validate_error_type_blob (metadata, simple->offset, + signature_offset, return_type, error)) + return FALSE; + break; + default: + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong tag in complex type"); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_arg_blob (GMetadata *metadata, + guint32 offset, + guint32 signature_offset, + GError **error) +{ + ArgBlob *blob; + + if (metadata->len < offset + sizeof (ArgBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ArgBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid argument name"); + return FALSE; + } + + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (ArgBlob, arg_type), + signature_offset, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_signature_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + SignatureBlob *blob; + gint i; + + if (metadata->len < offset + sizeof (SignatureBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (SignatureBlob*) &metadata->data[offset]; + + if (blob->return_type.offset != 0) + { + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (SignatureBlob, return_type), + offset, TRUE, error)) + return FALSE; + } + + for (i = 0; i < blob->n_arguments; i++) + { + if (!validate_arg_blob (metadata, + offset + sizeof (SignatureBlob) + + i * sizeof (ArgBlob), + offset, + error)) + return FALSE; + } + + /* FIXME check constraints on return_value */ + /* FIXME check array-length pairs */ + return TRUE; +} + +static gboolean +validate_function_blob (GMetadata *metadata, + guint32 offset, + guint16 container_type, + GError **error) +{ + FunctionBlob *blob; + + if (metadata->len < offset + sizeof (FunctionBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (FunctionBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_FUNCTION) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid function name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->symbol)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid function symbol"); + return FALSE; + } + + if (blob->constructor) + { + switch (container_type) + { + case BLOB_TYPE_BOXED: + case BLOB_TYPE_OBJECT: + case BLOB_TYPE_INTERFACE: + break; + default: + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Constructor not allowed"); + return FALSE; + } + } + + if (blob->setter || blob->getter || blob->wraps_vfunc) + { + switch (container_type) + { + case BLOB_TYPE_OBJECT: + case BLOB_TYPE_INTERFACE: + break; + default: + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Setter, getter or wrapper not allowed"); + return FALSE; + } + } + + if (blob->index) + { + if (!(blob->setter || blob->getter || blob->wraps_vfunc)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Must be setter, getter or wrapper"); + return FALSE; + } + } + + /* FIXME: validate index range */ + /* FIXME: validate "this" argument for methods */ + /* FIXME: validate return type for constructors */ + + if (!validate_signature_blob (metadata, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_callback_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + CallbackBlob *blob; + + if (metadata->len < offset + sizeof (CallbackBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (CallbackBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_CALLBACK) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid callback name"); + return FALSE; + } + + if (!validate_signature_blob (metadata, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_constant_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + gint value_size[] = { + 0, 4, 1, 1, 2, 2, 4, 4, 8, 8, + sizeof (gint), sizeof (guint), + sizeof (glong), sizeof (gulong), + sizeof (gssize), sizeof (gsize), + sizeof (gfloat), sizeof (gdouble), + 0, 0 + }; + ConstantBlob *blob; + SimpleTypeBlob *type; + + if (metadata->len < offset + sizeof (ConstantBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ConstantBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_CONSTANT) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid constant name"); + return FALSE; + } + + if (!validate_type_blob (metadata, offset + G_STRUCT_OFFSET (ConstantBlob, type), + 0, FALSE, error)) + return FALSE; + + if (!is_aligned (blob->offset)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Misaligned constant value"); + return FALSE; + } + + type = (SimpleTypeBlob *)&metadata->data[offset + G_STRUCT_OFFSET (ConstantBlob, type)]; + if (type->reserved == 0) + { + if (type->tag == 0) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Constant value type void"); + return FALSE; + } + + if (value_size[type->tag] != 0 && + blob->size != value_size[type->tag]) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Constant value size mismatch"); + return FALSE; + } + /* FIXME check string values */ + } + + return TRUE; +} + +static gboolean +validate_value_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + ValueBlob *blob; + + if (metadata->len < offset + sizeof (ValueBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ValueBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid value name"); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_field_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + FieldBlob *blob; + + if (metadata->len < offset + sizeof (FieldBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (FieldBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid field name"); + return FALSE; + } + + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (FieldBlob, type), + 0, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_property_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + PropertyBlob *blob; + + if (metadata->len < offset + sizeof (PropertyBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (PropertyBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid property name"); + return FALSE; + } + + if (!validate_type_blob (metadata, + offset + G_STRUCT_OFFSET (PropertyBlob, type), + 0, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_signal_blob (GMetadata *metadata, + guint32 offset, + guint32 container_offset, + GError **error) +{ + SignalBlob *blob; + gint n_signals; + + if (metadata->len < offset + sizeof (SignalBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (SignalBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid signal name"); + return FALSE; + } + + if ((blob->run_first != 0) + + (blob->run_last != 0) + + (blob->run_cleanup != 0) != 1) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid signal run flags"); + return FALSE; + } + + if (blob->has_class_closure) + { + if (((CommonBlob*)&metadata->data[container_offset])->blob_type == BLOB_TYPE_OBJECT) + { + ObjectBlob *object; + + object = (ObjectBlob*)&metadata->data[container_offset]; + + n_signals = object->n_signals; + } + else + { + InterfaceBlob *iface; + + iface = (InterfaceBlob*)&metadata->data[container_offset]; + + n_signals = iface->n_signals; + } + + if (blob->class_closure >= n_signals) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid class closure index"); + return FALSE; + } + } + + if (!validate_signature_blob (metadata, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_vfunc_blob (GMetadata *metadata, + guint32 offset, + guint32 container_offset, + GError **error) +{ + VFuncBlob *blob; + gint n_vfuncs; + + if (metadata->len < offset + sizeof (VFuncBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (VFuncBlob*) &metadata->data[offset]; + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid vfunc name"); + return FALSE; + } + + if (blob->class_closure) + { + if (((CommonBlob*)&metadata->data[container_offset])->blob_type == BLOB_TYPE_OBJECT) + { + ObjectBlob *object; + + object = (ObjectBlob*)&metadata->data[container_offset]; + + n_vfuncs = object->n_vfuncs; + } + else + { + InterfaceBlob *iface; + + iface = (InterfaceBlob*)&metadata->data[container_offset]; + + n_vfuncs = iface->n_vfuncs; + } + + if (blob->class_closure >= n_vfuncs) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid class closure index"); + return FALSE; + } + } + + if (!validate_signature_blob (metadata, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_struct_blob (GMetadata *metadata, + guint32 offset, + guint16 blob_type, + GError **error) +{ + StructBlob *blob; + gint i; + + if (metadata->len < offset + sizeof (StructBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (StructBlob*) &metadata->data[offset]; + + if (blob->blob_type != blob_type) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if ((blob->blob_type == BLOB_TYPE_BOXED && blob->unregistered) || + (blob->blob_type == BLOB_TYPE_STRUCT && !blob->unregistered)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Registration/blob type mismatch"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid struct name"); + return FALSE; + } + + if (blob_type == BLOB_TYPE_BOXED) + { + if (!is_name (metadata->data, blob->gtype_name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid boxed type name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_init)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid boxed type init"); + return FALSE; + } + } + else + { + if (blob->gtype_name || blob->gtype_init) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Gtype data in struct"); + return FALSE; + } + } + + if (metadata->len < offset + sizeof (StructBlob) + + blob->n_fields * sizeof (FieldBlob) + + blob->n_methods * sizeof (FunctionBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + for (i = 0; i < blob->n_fields; i++) + { + if (!validate_field_blob (metadata, + offset + sizeof (StructBlob) + + i * sizeof (FieldBlob), + error)) + return FALSE; + } + + for (i = 0; i < blob->n_methods; i++) + { + if (!validate_function_blob (metadata, + offset + sizeof (StructBlob) + + blob->n_fields * sizeof (FieldBlob) + + i * sizeof (FunctionBlob), + blob_type, + error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_enum_blob (GMetadata *metadata, + guint32 offset, + guint16 blob_type, + GError **error) +{ + EnumBlob *blob; + ValueBlob *v1, *v2; + gint i, j; + + if (metadata->len < offset + sizeof (EnumBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (EnumBlob*) &metadata->data[offset]; + + if (blob->blob_type != blob_type) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!blob->unregistered) + { + if (!is_name (metadata->data, blob->gtype_name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid enum type name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_init)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid enum type init"); + return FALSE; + } + } + else + { + if (blob->gtype_name || blob->gtype_init) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Gtype data in unregistered enum"); + return FALSE; + } + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid enum name"); + return FALSE; + } + + if (metadata->len < offset + sizeof (EnumBlob) + + blob->n_values * sizeof (ValueBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + for (i = 0; i < blob->n_values; i++) + { + if (!validate_value_blob (metadata, + offset + sizeof (EnumBlob) + + i * sizeof (ValueBlob), + error)) + return FALSE; + + v1 = (ValueBlob *)&metadata->data[offset + sizeof (EnumBlob) + + i * sizeof (ValueBlob)]; + for (j = 0; j < i; j++) + { + v2 = (ValueBlob *)&metadata->data[offset + sizeof (EnumBlob) + + j * sizeof (ValueBlob)]; + + if (v1->value == v2->value) + { + /* FIXME should this be an error ? */ + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Duplicate enum value"); + return FALSE; + } + } + } + + return TRUE; +} + +static gboolean +validate_object_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + Header *header; + ObjectBlob *blob; + gint i; + guint32 offset2; + + header = (Header *)metadata->data; + + if (metadata->len < offset + sizeof (ObjectBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ObjectBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_OBJECT) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid object type name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_init)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid object type init"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid object name"); + return FALSE; + } + + if (blob->parent > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid parent index"); + return FALSE; + } + + if (blob->parent != 0) + { + DirEntry *entry; + + entry = g_metadata_get_dir_entry (metadata, blob->parent); + if (entry->blob_type != BLOB_TYPE_OBJECT && + (entry->local || entry->blob_type != 0)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Parent not object"); + return FALSE; + } + } + + if (metadata->len < offset + sizeof (ObjectBlob) + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * sizeof (FieldBlob) + + blob->n_properties * sizeof (PropertyBlob) + + blob->n_methods * sizeof (FunctionBlob) + + blob->n_signals * sizeof (SignalBlob) + + blob->n_vfuncs * sizeof (VFuncBlob) + + blob->n_constants * sizeof (ConstantBlob)) + + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + offset2 = offset + sizeof (ObjectBlob); + + for (i = 0; i < blob->n_interfaces; i++, offset2 += 2) + { + guint16 iface; + DirEntry *entry; + + iface = *(guint16*)&metadata->data[offset2]; + if (iface == 0 || iface > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid interface index"); + return FALSE; + } + + entry = g_metadata_get_dir_entry (metadata, iface); + + if (entry->blob_type != BLOB_TYPE_INTERFACE && + (entry->local || entry->blob_type != 0)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Not an interface"); + return FALSE; + } + } + + offset2 += 2 * (blob->n_interfaces %2); + + for (i = 0; i < blob->n_fields; i++, offset2 += sizeof (FieldBlob)) + { + if (!validate_field_blob (metadata, offset2, error)) + return FALSE; + } + + for (i = 0; i < blob->n_properties; i++, offset2 += sizeof (PropertyBlob)) + { + if (!validate_property_blob (metadata, offset2, error)) + return FALSE; + } + + for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob)) + { + if (!validate_function_blob (metadata, offset2, BLOB_TYPE_OBJECT, error)) + return FALSE; + } + + for (i = 0; i < blob->n_signals; i++, offset2 += sizeof (SignalBlob)) + { + if (!validate_signal_blob (metadata, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_vfuncs; i++, offset2 += sizeof (VFuncBlob)) + { + if (!validate_vfunc_blob (metadata, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_constants; i++, offset2 += sizeof (ConstantBlob)) + { + if (!validate_constant_blob (metadata, offset2, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_interface_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + Header *header; + InterfaceBlob *blob; + gint i; + guint32 offset2; + + header = (Header *)metadata->data; + + if (metadata->len < offset + sizeof (InterfaceBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (InterfaceBlob*) &metadata->data[offset]; + + if (blob->blob_type != BLOB_TYPE_INTERFACE) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid interface type name"); + return FALSE; + } + + if (!is_name (metadata->data, blob->gtype_init)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid interface type init"); + return FALSE; + } + + if (!is_name (metadata->data, blob->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid interface name"); + return FALSE; + } + + if (metadata->len < offset + sizeof (InterfaceBlob) + + (blob->n_prerequisites + blob->n_prerequisites % 2) * 2 + + blob->n_properties * sizeof (PropertyBlob) + + blob->n_methods * sizeof (FunctionBlob) + + blob->n_signals * sizeof (SignalBlob) + + blob->n_vfuncs * sizeof (VFuncBlob) + + blob->n_constants * sizeof (ConstantBlob)) + + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + offset2 = offset + sizeof (InterfaceBlob); + + for (i = 0; i < blob->n_prerequisites; i++, offset2 += 2) + { + DirEntry *entry; + guint16 req; + + req = *(guint16*)&metadata->data[offset2]; + if (req == 0 || req > header->n_entries) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Invalid prerequisite index"); + return FALSE; + } + + entry = g_metadata_get_dir_entry (metadata, req); + if (entry->blob_type != BLOB_TYPE_INTERFACE && + entry->blob_type != BLOB_TYPE_OBJECT && + (entry->local || entry->blob_type != 0)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_BLOB, + "Not an interface or object"); + return FALSE; + } + } + + offset2 += 2 * (blob->n_prerequisites % 2); + + for (i = 0; i < blob->n_properties; i++, offset2 += sizeof (PropertyBlob)) + { + if (!validate_property_blob (metadata, offset2, error)) + return FALSE; + } + + for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob)) + { + if (!validate_function_blob (metadata, offset2, BLOB_TYPE_INTERFACE, error)) + return FALSE; + } + + for (i = 0; i < blob->n_signals; i++, offset2 += sizeof (SignalBlob)) + { + if (!validate_signal_blob (metadata, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_vfuncs; i++, offset2 += sizeof (VFuncBlob)) + { + if (!validate_vfunc_blob (metadata, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_constants; i++, offset2 += sizeof (ConstantBlob)) + { + if (!validate_constant_blob (metadata, offset2, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_errordomain_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + return TRUE; +} + +static gboolean +validate_union_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + return TRUE; +} + +static gboolean +validate_blob (GMetadata *metadata, + guint32 offset, + GError **error) +{ + CommonBlob *common; + + if (metadata->len < offset + sizeof (CommonBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + common = (CommonBlob*)&metadata->data[offset]; + + switch (common->blob_type) + { + case BLOB_TYPE_FUNCTION: + if (!validate_function_blob (metadata, offset, 0, error)) + return FALSE; + break; + case BLOB_TYPE_CALLBACK: + if (!validate_callback_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_STRUCT: + case BLOB_TYPE_BOXED: + if (!validate_struct_blob (metadata, offset, common->blob_type, error)) + return FALSE; + break; + case BLOB_TYPE_ENUM: + case BLOB_TYPE_FLAGS: + if (!validate_enum_blob (metadata, offset, common->blob_type, error)) + return FALSE; + break; + case BLOB_TYPE_OBJECT: + if (!validate_object_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_INTERFACE: + if (!validate_interface_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_CONSTANT: + if (!validate_constant_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_ERROR_DOMAIN: + if (!validate_errordomain_blob (metadata, offset, error)) + return FALSE; + break; + case BLOB_TYPE_UNION: + if (!validate_union_blob (metadata, offset, error)) + return FALSE; + break; + default: + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_ENTRY, + "Invalid blob type"); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_directory (GMetadata *metadata, + GError **error) +{ + Header *header = (Header *)metadata->data; + DirEntry *entry; + gint i; + + if (metadata->len < header->directory + header->n_entries * sizeof (DirEntry)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + for (i = 0; i < header->n_entries; i++) + { + entry = g_metadata_get_dir_entry (metadata, i + 1); + + if (!is_name (metadata->data, entry->name)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Invalid entry name"); + return FALSE; + } + + if ((entry->local && entry->blob_type == BLOB_TYPE_INVALID) || + entry->blob_type > BLOB_TYPE_UNION) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Invalid entry type"); + return FALSE; + } + + if (i < header->n_local_entries) + { + if (!entry->local) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Too few local directory entries"); + return FALSE; + } + + if (!is_aligned (entry->offset)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Misaligned entry"); + return FALSE; + } + + if (!validate_blob (metadata, entry->offset, error)) + return FALSE; + } + else + { + if (entry->local) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Too many local directory entries"); + return FALSE; + } + + if (!is_name (metadata->data, entry->offset)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID_DIRECTORY, + "Invalid namespace name"); + return FALSE; + } + } + } + + return TRUE; +} + +static gboolean +validate_annotations (GMetadata *metadata, + GError **error) +{ + Header *header = (Header *)metadata->data; + + if (header->size < header->annotations + header->n_annotations * sizeof (AnnotationBlob)) + { + g_set_error (error, + G_METADATA_ERROR, + G_METADATA_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + return TRUE; +} + +gboolean +g_metadata_validate (GMetadata *metadata, + GError **error) +{ + if (!validate_header (metadata, error)) + return FALSE; + + if (!validate_directory (metadata, error)) + return FALSE; + + if (!validate_annotations (metadata, error)) + return FALSE; + + return TRUE; +} + +GQuark +g_metadata_error_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("g-metadata-error-quark"); + return quark; +} + + +static inline void +_g_metadata_init (GMetadata *metadata) +{ + Header *header; + + header = (Header *) metadata->data; + if (header->shared_library) + { + const gchar *shlib; + shlib = g_metadata_get_string (metadata, header->shared_library); + metadata->module = g_module_open (shlib, G_MODULE_BIND_LAZY|G_MODULE_BIND_LOCAL); + if (metadata->module == NULL) + g_warning ("Failed to load shared library referenced by the metadata: %s", + g_module_error ()); + } +} + +/** + * g_metadata_new_from_memory: + * @memory: address of memory chunk containing the metadata + * @len: length of memory chunk containing the metadata + * + * Creates a new #GMetadata from a memory location. The memory block + * pointed to by @metadata will be automatically g_free()d when the + * repository is destroyed. + * + * Return value: the new #GMetadata + **/ +GMetadata * +g_metadata_new_from_memory (guchar *memory, gsize len) +{ + GMetadata *meta; + + meta = g_new0 (GMetadata, 1); + meta->data = memory; + meta->len = len; + meta->owns_memory = TRUE; + _g_metadata_init (meta); + return meta; +} + +/** + * g_metadata_new_from_const_memory: + * @memory: address of memory chunk containing the metadata + * @len: length of memory chunk containing the metadata + * + * Creates a new #GMetadata from a memory location. + * + * Return value: the new #GMetadata + **/ +GMetadata * +g_metadata_new_from_const_memory (const guchar *memory, gsize len) +{ + GMetadata *meta; + + meta = g_new0 (GMetadata, 1); + meta->data = (guchar *) memory; + meta->len = len; + meta->owns_memory = FALSE; + _g_metadata_init (meta); + return meta; +} + +/** + * g_metadata_new_from_mapped_file: + * @mfile: a #GMappedFile, that will be free'd when the repository is destroyed + * + * Creates a new #GMetadata from a #GMappedFile. + * + * Return value: the new #GMetadata + **/ +GMetadata * +g_metadata_new_from_mapped_file (GMappedFile *mfile) +{ + GMetadata *meta; + + meta = g_new0 (GMetadata, 1); + meta->mfile = mfile; + meta->owns_memory = FALSE; + meta->data = (guchar *) g_mapped_file_get_contents (mfile); + meta->len = g_mapped_file_get_length (mfile); + _g_metadata_init (meta); + return meta; +} + +/** + * g_metadata_free: + * @metadata: a #GMetadata + * + * Free a #GMetadata. + **/ +void +g_metadata_free (GMetadata *metadata) +{ + if (metadata->mfile) + g_mapped_file_free (metadata->mfile); + else + if (metadata->owns_memory) + g_free (metadata->data); + if (metadata->module) + g_module_close (metadata->module); + g_free (metadata); +} + +/** + * g_metadata_set_module: + * @metadata: a #GMetadata instance + * @module: a #GModule; takes ownership of this module + * + * Sets the target module for all symbols referenced by the metadata. + **/ +void +g_metadata_set_module (GMetadata *metadata, GModule *module) +{ + if (metadata->module) + g_module_close (metadata->module); + metadata->module = module; +} + +const gchar * +g_metadata_get_namespace(GMetadata *metadata) +{ + return g_metadata_get_string (metadata, ((Header *) metadata->data)->namespace); +} diff --git a/gobject-introspection/gmetadata.h b/gobject-introspection/gmetadata.h index 7ca390c0d..a22ee235e 100644 --- a/gobject-introspection/gmetadata.h +++ b/gobject-introspection/gmetadata.h @@ -22,6 +22,9 @@ #ifndef __G_METADATA_H__ #define __G_METADATA_H__ +#include +#include "girepository.h" + G_BEGIN_DECLS #define G_IDL_MAGIC "GOBJ\nMETADATA\r\n\032" @@ -56,6 +59,7 @@ typedef struct guint32 size; guint32 namespace; + guint32 shared_library; guint16 entry_blob_size; guint16 function_blob_size; @@ -77,7 +81,7 @@ typedef struct guint16 interface_blob_size; guint16 union_blob_size; - guint16 padding; + guint16 padding[7]; } Header; typedef struct @@ -506,13 +510,20 @@ typedef struct } AnnotationBlob; +struct _GMetadata { + guchar *data; + gsize len; + gboolean owns_memory; + GMappedFile *mfile; + GModule *module; +}; -DirEntry *g_metadata_get_dir_entry (const guchar *metadata, - guint16 index); +DirEntry *g_metadata_get_dir_entry (GMetadata *metadata, + guint16 index); void g_metadata_check_sanity (void); -#define g_metadata_get_string(metadata,offset) ((const gchar*)&(metadata)[(offset)]) +#define g_metadata_get_string(metadata,offset) ((const gchar*)&(metadata->data)[(offset)]) typedef enum @@ -528,9 +539,8 @@ typedef enum GQuark g_metadata_error_quark (void); -gboolean g_metadata_validate (const guchar *data, - guint len, - GError **error); +gboolean g_metadata_validate (GMetadata *metadata, + GError **error); G_END_DECLS diff --git a/gobject-introspection/scanner.c b/gobject-introspection/scanner.c new file mode 100644 index 000000000..58885791a --- /dev/null +++ b/gobject-introspection/scanner.c @@ -0,0 +1,1824 @@ +/* GObject introspection: scanner + * + * Copyright (C) 2007-2008 Jürg Billeter + * Copyright (C) 2007 Johan Dahlin + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include /* waitpid */ +#include +#include "scanner.h" +#include "gidlparser.h" +#include "gidlmodule.h" +#include "gidlnode.h" +#include "gidlwriter.h" + +typedef GType (*TypeFunction) (void); + +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); + } +} + +static GIGenerator * +g_igenerator_new (const gchar *namespace, + const gchar *shared_library) +{ + GIGenerator *igenerator = g_new0 (GIGenerator, 1); + igenerator->namespace = g_strdup (namespace); + igenerator->shared_library = g_strdup (shared_library); + igenerator->lower_case_namespace = + g_ascii_strdown (igenerator->namespace, -1); + igenerator->module = g_idl_module_new (namespace, shared_library); + + 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); + igenerator->symbols = g_hash_table_new (g_str_hash, g_str_equal); + + return igenerator; +} + +static void +g_igenerator_free (GIGenerator *generator) +{ + g_free (generator->namespace); + g_free (generator->shared_library); + g_free (generator->lower_case_namespace); +#if 0 + g_idl_module_free (generator->module); +#endif + g_hash_table_destroy (generator->typedef_table); + g_hash_table_destroy (generator->struct_or_union_or_enum_table); + g_hash_table_destroy (generator->type_map); + g_hash_table_destroy (generator->type_by_lower_case_prefix); + g_hash_table_destroy (generator->symbols); + g_list_foreach (generator->filenames, (GFunc)g_free, NULL); + g_list_free (generator->filenames); +#if 0 + g_list_foreach (generator->symbol_list, (GFunc)csymbol_free, NULL); + g_list_free (generator->symbol_list); +#endif + g_free (generator); +} + +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++) + { + GIdlNodeProperty *giprop; + + /* ignore inherited properties */ + if (properties[i]->owner_type != type_id) + { + continue; + } + 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); + giprop->readable = (properties[i]->flags & G_PARAM_READABLE) != 0; + giprop->writable = (properties[i]->flags & G_PARAM_WRITABLE) != 0; + giprop->construct = (properties[i]->flags & G_PARAM_CONSTRUCT) != 0; + giprop->construct_only = + (properties[i]->flags & G_PARAM_CONSTRUCT_ONLY) != 0; + } +} + +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; + GIdlNodeSignal *gisig; + GIdlNodeParam *giparam; + + g_signal_query (signal_ids[i], &signal_query); + 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 */ + 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 const gchar * +lookup_symbol (GIGenerator *igenerator, const gchar *typename) +{ + const gchar *name = + g_hash_table_lookup (igenerator->symbols, typename); + + if (!name) + { + g_printerr ("Unknown symbol: %s\n", typename); + return typename; + } + + return name; +} + +static void +g_igenerator_create_object (GIGenerator *igenerator, + const char *symbol_name, + GType type_id, + char *lower_case_prefix) + +{ + char *alt_lower_case_prefix; + GIdlNodeInterface *ginode; + guint n_type_interfaces; + GType *type_interfaces; + int i; + + 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 = g_strdup (symbol_name); + ginode->parent = g_strdup (lookup_symbol (igenerator, + g_type_name (g_type_parent (type_id)))); + + 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_hash_table_insert (igenerator->symbols, + g_strdup (ginode->gtype_name), + /* FIXME: Strip igenerator->namespace */ + g_strdup (ginode->node.name)); + + g_igenerator_process_properties (igenerator, ginode, type_id); + g_igenerator_process_signals (igenerator, ginode, type_id); +} + +static void +g_igenerator_create_interface (GIGenerator *igenerator, + const char *symbol_name, + GType type_id, + char *lower_case_prefix) + +{ + GIdlNodeInterface *ginode; + gboolean is_gobject = FALSE; + guint n_iface_prereqs; + GType *iface_prereqs; + int i; + + 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 = g_strdup (symbol_name); + + 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); +} + +static void +g_igenerator_create_boxed (GIGenerator *igenerator, + const char *symbol_name, + GType type_id, + char *lower_case_prefix) +{ + 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 = g_strdup (symbol_name); +} + +static void +g_igenerator_create_enum (GIGenerator *igenerator, + const char *symbol_name, + GType type_id, + char *lower_case_prefix) +{ + GIdlNodeEnum *ginode; + int i; + GEnumClass *type_class; + + 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 = g_strdup (symbol_name); + + 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 void +g_igenerator_create_flags (GIGenerator *igenerator, + const char *symbol_name, + GType type_id, + char *lower_case_prefix) +{ + GIdlNodeEnum *ginode; + GFlagsClass *type_class; + int i; + + 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 = g_strdup (symbol_name); + + 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 gboolean +g_igenerator_process_module_symbol (GIGenerator *igenerator, + GModule *module, + const gchar *symbol_name) +{ + TypeFunction type_fun; + GType type_id; + GType type_fundamental; + char *lower_case_prefix; + + /* ignore already processed functions */ + if (symbol_name == NULL) + return FALSE; + + if (!g_module_symbol (module, + symbol_name, + (gpointer *) & type_fun)) + return FALSE; + + type_id = type_fun (); + type_fundamental = g_type_fundamental (type_id); + lower_case_prefix = + str_replace (g_strndup + (symbol_name, + strlen (symbol_name) - strlen ("_get_type")), + "_", ""); + + switch (type_fundamental) + { + case G_TYPE_OBJECT: + g_igenerator_create_object (igenerator, symbol_name, type_id, + lower_case_prefix); + break; + case G_TYPE_INTERFACE: + g_igenerator_create_interface (igenerator, symbol_name, type_id, + lower_case_prefix); + break; + case G_TYPE_BOXED: + g_igenerator_create_boxed (igenerator, symbol_name, type_id, + lower_case_prefix); + break; + case G_TYPE_ENUM: + g_igenerator_create_enum (igenerator, symbol_name, type_id, + lower_case_prefix); + break; + case G_TYPE_FLAGS: + g_igenerator_create_flags (igenerator, symbol_name, type_id, + lower_case_prefix); + break; + default: + break; + } + return TRUE; +} + +static void +g_igenerator_process_module (GIGenerator * igenerator, + const gchar *filename) +{ + GModule *module; + GList *l; + + module = g_module_open (filename, + G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + + if (module == NULL) + { + g_critical ("Couldn't open module: %s", filename); + return; + } + + for (l = igenerator->get_type_symbols; l != NULL; l = l->next) + { + if (g_igenerator_process_module_symbol (igenerator, + module, (const char *)l->data)) + /* symbol found, ignore in future iterations */ + l->data = NULL; + } +} + +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, '_'); + GList *param_l; + int i; + GSList *l; + + 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); + + for (param_l = sym->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); + } + + for (l = sym->directives; l; l = l->next) + { + CDirective *directive = (CDirective*)l->data; + + if (!strcmp (directive->name, "deprecated")) + gifunc->deprecated = strcmp (directive->value, "1") == 0; + else + g_printerr ("Unknown function directive: %s\n", + directive->name); + } +} + +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); + GList *member_l; + char *lower_case_prefix; + + ginode->node.name = sym->ident; + igenerator->module->entries = + g_list_insert_sorted (igenerator->module->entries, ginode, + (GCompareFunc) g_idl_node_cmp); + 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); + + 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; + GIdlNode *gitype; + + if (struct_type->child_list == NULL) + { + CSymbol *struct_symbol; + g_assert (struct_type->name != NULL); + 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; + } + + 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") + || g_str_has_suffix (sym->ident, "Interface"))) + { + char *base_name; + GList *member_l; + GIdlNodeInterface *ginode; + + if (g_str_has_suffix (sym->ident, "Interface")) + { + base_name = + g_strndup (sym->ident, + strlen (sym->ident) - strlen ("Interface")); + } + else + { + base_name = + g_strndup (sym->ident, strlen (sym->ident) - strlen ("Class")); + } + 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; + } + ginode = (GIdlNodeInterface *) gitype; + + /* 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] == '_') + { + 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; + GList *param_l; + int i; + GIdlNodeVFunc *givfunc; + + 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; + if (vfunc_param->ident != NULL) + { + g_free (sig_param->node.name); + sig_param->node.name = + g_strdup (vfunc_param->ident); + } + } + break; + } + } + if (found_signal) + { + continue; + } + + 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); + for (param_l = member->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); + 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; + GIdlNode *gitype; + + 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; + } + + 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); + char *lower_case_prefix; + GList *member_l; + + ginode->node.name = sym->ident; + igenerator->module->entries = + g_list_insert_sorted (igenerator->module->entries, ginode, + (GCompareFunc) g_idl_node_cmp); + 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; + 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; + GList *member_l; + GIdlNodeEnum *ginode; + CSymbol *enum_symbol; + + enum_type = sym->base_type; + if (enum_type->child_list == NULL) + { + g_assert (enum_type->name != NULL); + 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; + } + + 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); + + 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) +{ + GList *param_l; + int i; + + /* 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); + + 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); + char *lower_case_prefix; + + ginode->node.name = sym->ident; + igenerator->module->entries = + g_list_insert_sorted (igenerator->module->entries, ginode, + (GCompareFunc) g_idl_node_cmp); + 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 (l->data, igenerator->current_filename) == 0) + { + found_filename = TRUE; + break; + } + } + + symbol->directives = g_slist_reverse (igenerator->directives); + igenerator->directives = NULL; + + 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, + const gchar * filename, + GList *libraries) +{ + 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")) + { + if (sym->base_type->child_list == NULL) + { + // ignore get_type functions with parameters + igenerator->get_type_symbols = + g_list_prepend (igenerator->get_type_symbols, sym->ident); + } + } + } + + /* ensure to initialize GObject */ + g_type_class_ref (G_TYPE_OBJECT); + + for (l = libraries; l; l = l->next) + g_igenerator_process_module (igenerator, (const gchar*)l->data); + + g_igenerator_process_symbols (igenerator); + + g_idl_writer_save_file (igenerator->module, filename); +} + +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"); + int line = 1; + + 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); + line++; + continue; + } + + /* print current location */ + str = g_strescape (l->data, ""); + fprintf (fmacros, "# %d \"%s\"\n", line, str); + g_free (str); + + 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); + line++; + 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); + line++; + 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); + line++; + continue; + } + + g_assert (c == ')'); + g_string_append_c (define_line, c); + c = fgetc (f); + + /* found function-like macro */ + fprintf (fmacros, "%s\n", define_line->str); + + g_string_free (define_line, TRUE); + /* ignore rest of line */ + c = eat_line (f, c); + line++; + continue; + } + if (c != ' ' && c != '\t') + { + g_string_free (define_line, TRUE); + /* ignore line */ + c = eat_line (f, c); + line++; + 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, "%s\n", define_line->str); + + c = eat_line (f, c); + line++; + } + + fclose (f); + } + + igenerator->macro_scan = TRUE; + rewind (fmacros); + + g_igenerator_parse_file (igenerator, fmacros); + fclose (fmacros); + + igenerator->macro_scan = FALSE; +} + +static void +g_igenerator_add_module (GIGenerator *igenerator, + GIdlModule *module) +{ + GList *l; + + for (l = module->entries; l; l = l->next) + { + GIdlNode *node = (GIdlNode*)l->data; + + if (node->type == G_IDL_NODE_OBJECT) + { + GIdlNodeInterface *object = (GIdlNodeInterface*)node; + gchar *name; + if (strcmp(module->name, igenerator->namespace) == 0) + name = g_strdup (node->name); + else + name = g_strdup_printf ("%s.%s", module->name, node->name); + g_hash_table_insert (igenerator->symbols, + g_strdup (object->gtype_name), + name); + } + } +} + +static void +g_igenerator_add_include_idl (GIGenerator *igenerator, + const gchar *filename) +{ + GList *l; + GList *modules; + + GError *error = NULL; + + modules = g_idl_parse_file (filename, &error); + if (error) + { + g_printerr ("An error occured while parsing %s: %s\n", + filename, error->message); + return; + } + + for (l = modules; l; l = l->next) + { + GIdlModule *module = (GIdlModule*)l->data; + g_igenerator_add_module (igenerator, module); + } +} + +static FILE * +g_igenerator_start_preprocessor (GIGenerator *igenerator, + GList *cpp_options) +{ + int cpp_out = -1, cpp_in = -1; + int cpp_argc = 0; + char **cpp_argv; + GList *l; + GError *error = NULL; + FILE *f, *out; + GPid pid; + int status = 0; + int read_bytes; + int i; + char **buffer; + int tmp; + char *tmpname; + + cpp_argv = g_new0 (char *, g_list_length (cpp_options) + 4); + cpp_argv[cpp_argc++] = "cpp"; + cpp_argv[cpp_argc++] = "-C"; + + /* Disable GCC extensions as we cannot parse them yet */ + cpp_argv[cpp_argc++] = "-U__GNUC__"; + + for (l = cpp_options; l; l = l->next) + cpp_argv[cpp_argc++] = (char*)l->data; + + cpp_argv[cpp_argc++] = NULL; + + if (igenerator->verbose) + { + GString *args = g_string_new (""); + + for (i = 0; i < cpp_argc - 1; i++) + { + g_string_append (args, cpp_argv[i]); + if (i < cpp_argc - 2) + g_string_append_c (args, ' '); + } + + g_printf ("Executing '%s'\n", args->str); + g_string_free (args, FALSE); + } + g_spawn_async_with_pipes (NULL, cpp_argv, NULL, + G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, &pid, &cpp_in, &cpp_out, NULL, &error); + + g_free (cpp_argv); + if (error != NULL) + { + g_error ("%s", error->message); + return NULL; + } + + f = fdopen (cpp_in, "w"); + + for (l = igenerator->filenames; l != NULL; l = l->next) + { + if (igenerator->verbose) + g_printf ("Pre-processing %s\n", (char*)l->data); + + fprintf (f, "#include <%s>\n", (char *) l->data); + + } + + fclose (f); + close (cpp_in); + + tmp = g_file_open_tmp (NULL, &tmpname, &error); + if (error != NULL) + { + g_error (error->message); + return NULL; + } + + buffer = g_malloc0 (4096 * sizeof (char)); + + while (1) + { + read_bytes = read (cpp_out, buffer, 4096); + if (read_bytes == 0) + break; + write (tmp, buffer, read_bytes); + } + + g_free (buffer); + + close (cpp_out); + + if (waitpid (pid, &status, 0) > 0) + { + if (status != 0) + { + g_spawn_close_pid (pid); + kill (pid, SIGKILL); + + g_error ("cpp returned error code: %d\n", status); + unlink (tmpname); + g_free (tmpname); + return NULL; + } + } + + f = fdopen (tmp, "r"); + if (!f) + { + g_error (strerror (errno)); + unlink (tmpname); + g_free (tmpname); + return NULL; + } + rewind (f); + unlink (tmpname); + g_free (tmpname); + + return f; +} + + +void +g_igenerator_set_verbose (GIGenerator *igenerator, + gboolean verbose) +{ + igenerator->verbose = verbose; +} + +int +main (int argc, char **argv) +{ + GOptionContext *ctx; + gchar *namespace = NULL; + gchar *shared_library = NULL; + gchar **include_idls = NULL; + gchar *output = NULL; + gboolean verbose = FALSE; + + GIGenerator *igenerator; + int gopt_argc, i; + char **gopt_argv; + GList *filenames = NULL; + GError *error = NULL; + GList *l, *libraries = NULL; + GList *cpp_options = NULL; + char *buffer; + size_t size; + FILE *tmp; + GOptionEntry entries[] = + { + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + "Be verbose" }, + { "output", 'o', 0, G_OPTION_ARG_STRING, &output, + "write output here instead of stdout", "FILE" }, + { "namespace", 'n', 0, G_OPTION_ARG_STRING, &namespace, + "Namespace of the module, like 'Gtk'", "NAMESPACE" }, + { "shared-library", 0, 0, G_OPTION_ARG_FILENAME, &shared_library, + "Shared library which contains the symbols", "FILE" }, + { "include-idl", 0, 0, G_OPTION_ARG_STRING_ARRAY, &include_idls, + "Other gidls to include", "IDL" }, + { NULL } + }; + + gopt_argc = 1; + gopt_argv = (char**)g_malloc (argc * sizeof (char*)); + gopt_argv[0] = argv[0]; + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'I': + case 'D': + case 'U': + cpp_options = g_list_prepend (cpp_options, g_strdup (argv[i])); + break; + default: + gopt_argv[gopt_argc++] = argv[i]; + break; + } + } + else if (g_str_has_suffix (argv[i], ".h")) + { + gchar* filename; + + if (!g_path_is_absolute (argv[i])) + { + gchar *dir = g_get_current_dir (); + filename = g_strdup_printf ("%s/%s", dir, + argv[i]); + g_free (dir); + } + else + filename = g_strdup (argv[i]); + + filenames = g_list_append (filenames, filename); + } + else if (g_str_has_suffix (argv[i], ".la") || + g_str_has_suffix (argv[i], ".so") || + g_str_has_suffix (argv[i], ".dll")) + { + libraries = g_list_prepend (libraries, g_strdup (argv[i])); + } + else + { + gopt_argv[gopt_argc++] = argv[i]; + } + } + + ctx = g_option_context_new (""); + g_option_context_add_main_entries (ctx, entries, NULL); + + if (!g_option_context_parse (ctx, &gopt_argc, &gopt_argv, &error)) + { + g_printerr ("Parsing error: %s\n", error->message); + g_option_context_free (ctx); + return 1; + } + + g_free (gopt_argv); + g_option_context_free (ctx); + + if (!namespace) + { + g_printerr ("ERROR: namespace must be specified\n"); + return 1; + } + + igenerator = g_igenerator_new (namespace, shared_library); + + if (verbose) + g_igenerator_set_verbose (igenerator, TRUE); + + if (!filenames) + { + g_printerr ("ERROR: Need at least one header file.\n"); + g_igenerator_free (igenerator); + return 0; + } + igenerator->filenames = filenames; + cpp_options = g_list_reverse (cpp_options); + libraries = g_list_reverse (libraries); + + g_type_init (); + + /* initialize threading as this may be required by libraries that we'll use + * libsoup-2.2 is an example of that. + */ + g_thread_init (NULL); + + if (include_idls) + { + for (i = 0; i < g_strv_length (include_idls); i++) + g_igenerator_add_include_idl (igenerator, include_idls[i]); + } + + tmp = g_igenerator_start_preprocessor (igenerator, cpp_options); + if (!tmp) + { + g_error ("ERROR in pre-processor.\n"); + g_igenerator_free (igenerator); + return 1; + } + + if (!g_igenerator_parse_file (igenerator, tmp)) + { + fclose (tmp); + g_igenerator_free (igenerator); + return 1; + } + + g_igenerator_parse_macros (igenerator); + + g_igenerator_generate (igenerator, output, libraries); + + fclose (tmp); + g_igenerator_free (igenerator); + + return 0; +} + diff --git a/gobject-introspection/scanner.h b/gobject-introspection/scanner.h new file mode 100644 index 000000000..b21407590 --- /dev/null +++ b/gobject-introspection/scanner.h @@ -0,0 +1,167 @@ +/* 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 + */ + +#ifndef __GEN_INTROSPECT_H__ +#define __GEN_INTROSPECT_H__ + +#include +#include "gidlmodule.h" + +G_BEGIN_DECLS typedef struct _GIGenerator GIGenerator; +typedef struct _CSymbol CSymbol; +typedef struct _CType CType; +typedef struct _CDirective CDirective; + +struct _GIGenerator +{ + /* parameters */ + char *namespace; + char *shared_library; + char *lower_case_namespace; + gboolean verbose; + + /* specified files to be parsed */ + GList *filenames; + /* source reference of current lexer position */ + char *current_filename; + GList *symbol_list; + GHashTable *typedef_table; + GHashTable *struct_or_union_or_enum_table; + + GIdlModule *module; + GList *get_type_symbols; + GHashTable *type_map; + GHashTable *type_by_lower_case_prefix; + + GHashTable *symbols; /* typename -> module.name */ + + /* scanner variables */ + gboolean macro_scan; + GSList *directives; /* list of CDirective for the current symbol */ +}; + +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; + GSList *directives; /* list of CDirective */ +}; + +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; +}; + +struct _CDirective { + char *name; + char *value; +}; + +CSymbol * csymbol_new (CSymbolType type); +gboolean csymbol_get_const_boolean (CSymbol *symbol); +void csymbol_free (CSymbol *symbol); +CDirective * cdirective_new (const gchar *name, + const gchar *value); +void cdirective_free (CDirective *directive); + +gboolean g_igenerator_parse_file (GIGenerator *igenerator, + FILE *file); +void g_igenerator_set_verbose (GIGenerator *igenerator, + gboolean verbose); +void g_igenerator_add_symbol (GIGenerator *igenerator, + CSymbol *symbol); +gboolean g_igenerator_is_typedef (GIGenerator *igenerator, + const char *name); +G_END_DECLS +#endif diff --git a/gobject-introspection/scannerlexer.l b/gobject-introspection/scannerlexer.l new file mode 100644 index 000000000..255f7dcd6 --- /dev/null +++ b/gobject-introspection/scannerlexer.l @@ -0,0 +1,311 @@ +/* -*- Mode: C -*- +/* GObject introspection: C lexer + * + * Copyright (c) 1997 Sandro Sigala + * Copyright (c) 2007 Jürg Billeter + * + * 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 +#include + +#include "scanner.h" +#include "scannerparser.h" + +int lineno; + +extern int yylex (GIGenerator *igenerator); +#define YY_DECL int yylex (GIGenerator *igenerator) +static int yywrap (void); +static void parse_comment (GIGenerator *igenerator); +static void process_directive (GIGenerator *igenerator); +static int check_identifier (GIGenerator *igenerator, 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. */ } + +"/*" { parse_comment(igenerator); } +"//".* { } + +"#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(igenerator); } + +"{" { 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 (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(igenerator, 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, "%s:%d: unexpected character `%c'\n", igenerator->current_filename, lineno, yytext[0]); } + +%% + +static int yywrap (void) +{ + return 1; +} + +static void parse_gtkdoc (GIGenerator *igenerator, int *c1, int *c2) +{ + gboolean isline = FALSE; + gchar line[256]; + int i; + gchar **parts; + CDirective *directive; + char *name, *value; + + i = 0; + do { + *c1 = *c2; + if (*c1 == '\n') + { + isline = TRUE; + break; + } + if (i >= 256) + break; + line[i++] = *c1; + *c2 = input(); + + } while (*c2 != EOF && !(*c1 == '*' && *c2 == '/')); + + if (!isline) + return; + + line[i] = '\0'; + + parts = g_strsplit (line, ": ", 2); + + if (g_strv_length (parts) == 2) + { + name = parts[0]; + value = parts[1]; + } + else /* parts == 1 */ + { + name = parts[0]; + value = "1"; + } + + directive = cdirective_new (name, value); + igenerator->directives = g_slist_prepend (igenerator->directives, + directive); + + g_strfreev (parts); +} + +static void parse_comment (GIGenerator *igenerator) +{ + int c1, c2; + + c1 = input(); + c2 = input(); + + while (c2 != EOF && !(c1 == '*' && c2 == '/')) + { + if (c1 == '\n') + ++lineno; + c1 = c2; + c2 = input(); + + if (c1 == ' ' && c2 == '@') + { + c1 = c2; + c2 = input(); + parse_gtkdoc (igenerator, &c1, &c2); + } + } +} + +static int check_identifier (GIGenerator *igenerator, const char *s) +{ + /* + * This function checks if `s' is a type name or an + * identifier. + */ + + if (g_igenerator_is_typedef (igenerator, s)) { + return TYPEDEF_NAME; + } else if (strcmp (s, "__builtin_va_list") == 0) { + return TYPEDEF_NAME; + } + + return IDENTIFIER; +} + +static void process_directive (GIGenerator *igenerator) +{ + /* extract current filename from #line directives */ + GString *filename_builder; + gboolean in_string, found_filename; + + lineno = 0; + found_filename = FALSE; + in_string = FALSE; + filename_builder = g_string_new (""); + + int c = input (); + while (c != EOF && c != '\n') { + if (!in_string) { + if (c == '\"') { + in_string = TRUE; + found_filename = TRUE; + } else if (c >= '0' && c <= '9') { + if (!found_filename) { + lineno = lineno * 10 + (c - '0'); + } + } + } 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 (); + } + + if (filename_builder->len > 0) { + char *filename = g_strcompress (filename_builder->str); + g_free (igenerator->current_filename); + igenerator->current_filename = filename; + } + + g_string_free (filename_builder, TRUE); +} + diff --git a/gobject-introspection/scannerparser.y b/gobject-introspection/scannerparser.y new file mode 100644 index 000000000..fae5067db --- /dev/null +++ b/gobject-introspection/scannerparser.y @@ -0,0 +1,1376 @@ +/* GObject introspection: C parser + * + * Copyright (c) 1997 Sandro Sigala + * Copyright (c) 2007 Jürg Billeter + * + * 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 +#include +#include +#include +#include "scanner.h" + +extern FILE *yyin; +extern int lineno; +extern char *yytext; + +extern int yylex (GIGenerator *igenerator); +static void yyerror(GIGenerator *igenerator, const char *s); + +static int last_enum_value = -1; +static GHashTable *const_table = NULL; + +CSymbol * +csymbol_new (CSymbolType type) +{ + CSymbol *s = g_new0 (CSymbol, 1); + s->type = type; + return s; +} + +static void +ctype_free (CType * type) +{ + g_free (type); + g_free (type->name); + g_list_foreach (type->child_list, (GFunc)ctype_free, NULL); + g_list_free (type->child_list); +} + +void +csymbol_free (CSymbol * symbol) +{ + g_free (symbol->ident); + ctype_free (symbol->base_type); + g_free (symbol->const_string); + g_free (symbol); + g_slist_foreach (symbol->directives, (GFunc)cdirective_free, NULL); + g_slist_free (symbol->directives); +} + +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 = ctype_copy (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; +} + +/* 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); +} + +CDirective * +cdirective_new (const gchar *name, + const gchar *value) +{ + CDirective *directive; + + directive = g_slice_new (CDirective); + directive->name = g_strdup (name); + directive->value = g_strdup (value); + return directive; +} + +void +cdirective_free (CDirective *directive) +{ + g_free (directive->name); + g_free (directive->value); + g_slice_free (CDirective, directive); +} + +%} + +%error-verbose +%union { + char *str; + GList *list; + CSymbol *symbol; + CType *ctype; + StorageClassSpecifier storage_class_specifier; + TypeQualifier type_qualifier; + FunctionSpecifier function_specifier; + UnaryOperator unary_operator; +} + +%parse-param { GIGenerator* igenerator } +%lex-param { GIGenerator* igenerator } + +%token IDENTIFIER "identifier" +%token 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 declaration_specifiers +%type enum_specifier +%type pointer +%type specifier_qualifier_list +%type struct_or_union +%type struct_or_union_specifier +%type type_specifier +%type identifier +%type typedef_name +%type identifier_or_typedef_name +%type abstract_declarator +%type init_declarator +%type declarator +%type enumerator +%type direct_abstract_declarator +%type direct_declarator +%type parameter_declaration +%type struct_declarator +%type enumerator_list +%type identifier_list +%type init_declarator_list +%type parameter_type_list +%type parameter_list +%type struct_declaration +%type struct_declaration_list +%type struct_declarator_list +%type storage_class_specifier +%type type_qualifier +%type type_qualifier_list +%type function_specifier +%type expression +%type constant_expression +%type conditional_expression +%type logical_and_expression +%type logical_or_expression +%type inclusive_or_expression +%type exclusive_or_expression +%type multiplicative_expression +%type additive_expression +%type shift_expression +%type relational_expression +%type equality_expression +%type and_expression +%type cast_expression +%type assignment_expression +%type unary_expression +%type postfix_expression +%type primary_expression +%type unary_operator +%type function_macro +%type object_macro +%type strings + +%% + +/* 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); + } + | strings + | '(' expression ')' + { + $$ = $2; + } + ; + +/* concatenate adjacent string literal tokens */ +strings + : STRING + { + $$ = csymbol_new (CSYMBOL_TYPE_CONST); + yytext[strlen (yytext) - 1] = '\0'; + $$->const_string = g_strcompress (yytext + 1); + } + | strings STRING + { + char *strings, *string2; + $$ = $1; + yytext[strlen (yytext) - 1] = '\0'; + string2 = g_strcompress (yytext + 1); + strings = g_strconcat ($$->const_string, string2, NULL); + g_free ($$->const_string); + g_free (string2); + $$->const_string = strings; + } + ; + +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 (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 (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 + : /* empty, support for anonymous structs and unions */ + { + $$ = csymbol_new (CSYMBOL_TYPE_INVALID); + } + | 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, g_strdup ($$->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, g_strdup ($$->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 (igenerator, $2); + } + } + ; + +macro + : function_macro_define + | object_macro_define + | error + ; + +%% + +static void +yyerror (GIGenerator *igenerator, const char *s) +{ + /* ignore errors while doing a macro scan as not all object macros + * have valid expressions */ + if (!igenerator->macro_scan) + { + fprintf(stderr, "%s:%d: %s\n", + igenerator->current_filename, lineno, s); + } +} + +gboolean +g_igenerator_parse_file (GIGenerator *igenerator, FILE *file) +{ + g_return_val_if_fail (file != NULL, FALSE); + + const_table = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + + lineno = 1; + yyin = file; + yyparse (igenerator); + + g_hash_table_destroy (const_table); + const_table = NULL; + + yyin = NULL; + + return TRUE; +} + + -- cgit v1.2.1