diff options
-rw-r--r-- | ChangeLog | 35 | ||||
-rw-r--r-- | configure.ac | 13 | ||||
-rw-r--r-- | src/Makefile.am | 16 | ||||
-rw-r--r-- | src/clexer.l | 251 | ||||
-rw-r--r-- | src/cparser.y | 1236 | ||||
-rw-r--r-- | src/gen-introspect.c | 1914 | ||||
-rw-r--r-- | src/gen-introspect.h | 162 |
7 files changed, 3625 insertions, 2 deletions
@@ -1,5 +1,40 @@ 2007-11-30 Jürg Billeter <j@bitron.ch> + * configure.ac: + * src/Makefile.am: + * src/clexer.l: + * src/cparser.y: + * src/gen-introspect.c: (g_idl_node_cmp), (g_igenerator_new), + (g_igenerator_write_inline), (g_igenerator_write), + (g_igenerator_write_indent), (g_igenerator_write_unindent), + (field_generate), (value_generate), (constant_generate), + (property_generate), (function_generate), (vfunc_generate), + (signal_generate), (interface_generate), (struct_generate), + (union_generate), (boxed_generate), (enum_generate), + (node_generate), (module_generate), (get_type_from_type_id), + (str_replace), (g_igenerator_process_properties), + (g_igenerator_process_signals), (g_igenerator_process_types), + (get_type_from_ctype), (g_igenerator_process_function_symbol), + (g_igenerator_process_unregistered_struct_typedef), + (g_igenerator_process_struct_typedef), + (g_igenerator_process_union_typedef), + (g_igenerator_process_enum_typedef), + (g_igenerator_process_function_typedef), + (g_igenerator_process_constant), (g_igenerator_process_symbols), + (g_igenerator_add_symbol), (g_igenerator_is_typedef), + (g_igenerator_generate), (main), (csymbol_new), + (csymbol_get_const_boolean), (ctype_new), (ctype_copy), + (cbasic_type_new), (ctypedef_new), (cstruct_new), (cunion_new), + (cenum_new), (cpointer_new), (carray_new), (cfunction_new), + (eat_hspace), (eat_line), (read_identifier), + (g_igenerator_parse_macros): + * src/gen-introspect.h: + + Import gen-introspect to generate introspection information by + parsing C headers. + +2007-11-30 Jürg Billeter <j@bitron.ch> + * src/gidlnode.c: (g_idl_node_new): support creating callback nodes 2007-11-30 Jürg Billeter <j@bitron.ch> diff --git a/configure.ac b/configure.ac index 6ab03de2..91e0ed6b 100644 --- a/configure.ac +++ b/configure.ac @@ -10,12 +10,23 @@ AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CC +AM_PROG_CC_C_O AC_PROG_LIBTOOL +AC_PROG_LEX +if test "$LEX" = :; then + AC_MSG_ERROR([flex not found but required]) +fi + +AC_CHECK_PROGS(YACC, 'bison -y' byacc yacc, :) +if test "$YACC" = :; then + AC_MSG_ERROR([bison not found but required]) +fi + # Checks for libraries. AC_CHECK_LIB([dl], [dlopen]) -PKG_CHECK_MODULES(GIREPO, glib-2.0 gobject-2.0 gmodule-2.0 libffi) +PKG_CHECK_MODULES(GIREPO, glib-2.0 gobject-2.0 gmodule-2.0 gthread-2.0 libffi) # Checks for header files. diff --git a/src/Makefile.am b/src/Makefile.am index 97c0ccdc..02ea1a2b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in lib_LTLIBRARIES = libgirepository.la -bin_PROGRAMS = g-idl-compiler g-idl-generate +bin_PROGRAMS = g-idl-compiler g-idl-generate gen-introspect libgirepository_la_SOURCES = \ @@ -28,3 +28,17 @@ g_idl_generate_LDADD = -ldl $(GIREPO_LIBS) libgirepository.la girepodir = $(includedir)/glib-2.0/gobject-introspection girepo_HEADERS = girepository.h + +BUILT_SOURCES = cparser.h +AM_YFLAGS = -d + +gen_introspect_SOURCES = \ + clexer.l \ + cparser.y \ + gidlmodule.c \ + gidlnode.c \ + gen-introspect.c \ + gen-introspect.h +gen_introspect_CFLAGS = $(GIREPO_CFLAGS) +gen_introspect_LDADD = -ldl $(GIREPO_LIBS) + diff --git a/src/clexer.l b/src/clexer.l new file mode 100644 index 00000000..b0c9cd6c --- /dev/null +++ b/src/clexer.l @@ -0,0 +1,251 @@ +/* GObject introspection: C lexer + * + * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it> + * Copyright (c) 2007 Jürg Billeter <j@bitron.ch> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +%{ +#include <ctype.h> +#include <stdio.h> + +#include "gen-introspect.h" +#include "cparser.h" + +int lineno; + +static int yywrap (void); +static void skip_comment (void); +static void process_directive (void); +static int check_identifier (const char *); +%} + +intsuffix ([uU][lL]?)|([lL][uU]?) +fracconst ([0-9]*\.[0-9]+)|([0-9]+\.) +exppart [eE][-+]?[0-9]+ +floatsuffix [fFlL] +chartext ([^'])|(\\.) +stringtext ([^"])|(\\.) + +%% + +"\n" { ++lineno; } +[\t\f\v\r ]+ { /* Ignore whitespace. */ } + +"/*" { skip_comment(); } +"//".* { } + +"#define "[a-zA-Z_][a-zA-Z_0-9]*"(" { yyless (yyleng - 1); return FUNCTION_MACRO; } +"#define "[a-zA-Z_][a-zA-Z_0-9]* { return OBJECT_MACRO; } + +"#" { process_directive(); } + +"{" { return '{'; } +"<%" { return '{'; } +"}" { return '}'; } +"%>" { return '}'; } +"[" { return '['; } +"<:" { return '['; } +"]" { return ']'; } +":>" { return ']'; } +"(" { return '('; } +")" { return ')'; } +";" { return ';'; } +":" { return ':'; } +"..." { return ELLIPSIS; } +"?" { return '?'; } +"." { return '.'; } +"+" { return '+'; } +"-" { return '-'; } +"*" { return '*'; } +"/" { return '/'; } +"%" { return '%'; } +"^" { return '^'; } +"&" { return '&'; } +"|" { return '|'; } +"~" { return '~'; } +"!" { return '!'; } +"=" { return '='; } +"<" { return '<'; } +">" { return '>'; } +"+=" { return ADDEQ; } +"-=" { return SUBEQ; } +"*=" { return MULEQ; } +"/=" { return DIVEQ; } +"%=" { return MODEQ; } +"^=" { return XOREQ; } +"&=" { return ANDEQ; } +"|=" { return OREQ; } +"<<" { return SL; } +">>" { return SR; } +"<<=" { return SLEQ; } +">>=" { return SREQ; } +"==" { return EQ; } +"!=" { return NOTEQ; } +"<=" { return LTEQ; } +">=" { return GTEQ; } +"&&" { return ANDAND; } +"||" { return OROR; } +"++" { return PLUSPLUS; } +"--" { return MINUSMINUS; } +"," { return ','; } +"->" { return ARROW; } + +[a-zA-Z_][a-zA-Z_0-9]* { if (the_igenerator->macro_scan) return IDENTIFIER; else REJECT; } + +"auto" { return AUTO; } +"break" { return BREAK; } +"case" { return CASE; } +"char" { return CHAR; } +"const" { return CONST; } +"continue" { return CONTINUE; } +"default" { return DEFAULT; } +"do" { return DO; } +"double" { return DOUBLE; } +"else" { return ELSE; } +"enum" { return ENUM; } +"extern" { return EXTERN; } +"float" { return FLOAT; } +"for" { return FOR; } +"goto" { return GOTO; } +"if" { return IF; } +"inline" { return INLINE; } +"int" { return INT; } +"long" { return LONG; } +"register" { return REGISTER; } +"restrict" { return RESTRICT; } +"return" { return RETURN; } +"short" { return SHORT; } +"signed" { return SIGNED; } +"sizeof" { return SIZEOF; } +"static" { return STATIC; } +"struct" { return STRUCT; } +"switch" { return SWITCH; } +"typedef" { return TYPEDEF; } +"union" { return UNION; } +"unsigned" { return UNSIGNED; } +"void" { return VOID; } +"volatile" { return VOLATILE; } +"while" { return WHILE; } + +[a-zA-Z_][a-zA-Z_0-9]* { return check_identifier(yytext); } + +"0"[xX][0-9a-fA-F]+{intsuffix}? { return INTEGER; } +"0"[0-7]+{intsuffix}? { return INTEGER; } +[0-9]+{intsuffix}? { return INTEGER; } + +{fracconst}{exppart}?{floatsuffix}? { return FLOATING; } +[0-9]+{exppart}{floatsuffix}? { return FLOATING; } + +"'"{chartext}*"'" { return CHARACTER; } +"L'"{chartext}*"'" { return CHARACTER; } + +"\""{stringtext}*"\"" { return STRING; } +"L\""{stringtext}*"\"" { return STRING; } + +. { fprintf(stderr, "%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/src/cparser.y b/src/cparser.y new file mode 100644 index 00000000..c29ca8f8 --- /dev/null +++ b/src/cparser.y @@ -0,0 +1,1236 @@ +/* GObject introspection: C parser + * + * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it> + * Copyright (c) 2007 Jürg Billeter <j@bitron.ch> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +%{ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "gen-introspect.h" + +extern FILE *yyin; +extern int lineno; +extern char *yytext; + +extern int yylex (void); +static void yyerror(const char *s); + +static int last_enum_value = -1; +static GHashTable *const_table = NULL; + +/* use specified type as base type of symbol */ +static void csymbol_merge_type (CSymbol *symbol, CType *type) +{ + CType **foundation_type = &(symbol->base_type); + while (*foundation_type != NULL) { + foundation_type = &((*foundation_type)->base_type); + } + *foundation_type = ctype_copy (type); +} +%} + +%error-verbose +%union { + char *str; + GList *list; + CSymbol *symbol; + CType *ctype; + StorageClassSpecifier storage_class_specifier; + TypeQualifier type_qualifier; + FunctionSpecifier function_specifier; + UnaryOperator unary_operator; +} + +%token <str> IDENTIFIER "identifier" +%token <str> TYPEDEF_NAME "typedef-name" + +%token INTEGER FLOATING CHARACTER STRING + +%token ELLIPSIS ADDEQ SUBEQ MULEQ DIVEQ MODEQ XOREQ ANDEQ OREQ SL SR +%token SLEQ SREQ EQ NOTEQ LTEQ GTEQ ANDAND OROR PLUSPLUS MINUSMINUS ARROW + +%token AUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM +%token EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT RETURN SHORT +%token SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE +%token WHILE + +%token FUNCTION_MACRO OBJECT_MACRO + +%start translation_unit + +%type <ctype> declaration_specifiers +%type <ctype> enum_specifier +%type <ctype> pointer +%type <ctype> specifier_qualifier_list +%type <ctype> struct_or_union +%type <ctype> struct_or_union_specifier +%type <ctype> type_specifier +%type <str> identifier +%type <str> typedef_name +%type <str> identifier_or_typedef_name +%type <symbol> abstract_declarator +%type <symbol> init_declarator +%type <symbol> declarator +%type <symbol> enumerator +%type <symbol> direct_abstract_declarator +%type <symbol> direct_declarator +%type <symbol> parameter_declaration +%type <symbol> struct_declarator +%type <list> enumerator_list +%type <list> identifier_list +%type <list> init_declarator_list +%type <list> parameter_type_list +%type <list> parameter_list +%type <list> struct_declaration +%type <list> struct_declaration_list +%type <list> struct_declarator_list +%type <storage_class_specifier> storage_class_specifier +%type <type_qualifier> type_qualifier +%type <type_qualifier> type_qualifier_list +%type <function_specifier> function_specifier +%type <symbol> expression +%type <symbol> constant_expression +%type <symbol> conditional_expression +%type <symbol> logical_and_expression +%type <symbol> logical_or_expression +%type <symbol> inclusive_or_expression +%type <symbol> exclusive_or_expression +%type <symbol> multiplicative_expression +%type <symbol> additive_expression +%type <symbol> shift_expression +%type <symbol> relational_expression +%type <symbol> equality_expression +%type <symbol> and_expression +%type <symbol> cast_expression +%type <symbol> assignment_expression +%type <symbol> unary_expression +%type <symbol> postfix_expression +%type <symbol> primary_expression +%type <unary_operator> unary_operator +%type <str> function_macro +%type <str> object_macro +%type <symbol> 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/src/gen-introspect.c b/src/gen-introspect.c new file mode 100644 index 00000000..a4b522c3 --- /dev/null +++ b/src/gen-introspect.c @@ -0,0 +1,1914 @@ +/* GObject introspection: gen-introspect + * + * Copyright (C) 2007 Jürg Billeter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: + * Jürg Billeter <j@bitron.ch> + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <glib.h> +#include <glib/gstdio.h> +#include <glib-object.h> +#include <gmodule.h> +#include "gen-introspect.h" +#include "gidlmodule.h" +#include "gidlnode.h" + +typedef GType (*TypeFunction) (void); + +static void node_generate (GIGenerator * igenerator, GIdlNode * node); +static void g_igenerator_parse_macros (GIGenerator * igenerator); + +static int +g_idl_node_cmp (GIdlNode * a, GIdlNode * b) +{ + if (a->type < b->type) + { + return -1; + } + else if (a->type > b->type) + { + return 1; + } + else + { + return strcmp (a->name, b->name); + } +} + +GIGenerator * +g_igenerator_new (void) +{ + GIGenerator *igenerator = g_new0 (GIGenerator, 1); + igenerator->namespace = ""; + igenerator->lower_case_namespace = g_strdup (""); + igenerator->typedef_table = g_hash_table_new (g_str_hash, g_str_equal); + igenerator->struct_or_union_or_enum_table = + g_hash_table_new (g_str_hash, g_str_equal); + + igenerator->type_map = g_hash_table_new (g_str_hash, g_str_equal); + igenerator->type_by_lower_case_prefix = + g_hash_table_new (g_str_hash, g_str_equal); + + the_igenerator = igenerator; + + return igenerator; +} + +static void +g_igenerator_write_inline (GIGenerator * igenerator, const char *s) +{ + fprintf (stdout, "%s", s); +} + +static void +g_igenerator_write (GIGenerator * igenerator, const char *s) +{ + int i; + for (i = 0; i < igenerator->indent; i++) + { + fprintf (stdout, "\t"); + } + + g_igenerator_write_inline (igenerator, s); +} + +static void +g_igenerator_write_indent (GIGenerator * igenerator, const char *s) +{ + g_igenerator_write (igenerator, s); + igenerator->indent++; +} + +static void +g_igenerator_write_unindent (GIGenerator * igenerator, const char *s) +{ + igenerator->indent--; + g_igenerator_write (igenerator, s); +} + +static void +field_generate (GIGenerator * igenerator, GIdlNodeField * node) +{ + char *markup = + g_markup_printf_escaped ("<field name=\"%s\" type=\"%s\"/>\n", + node->node.name, node->type->unparsed); + g_igenerator_write (igenerator, markup); + g_free (markup); +} + +static void +value_generate (GIGenerator * igenerator, GIdlNodeValue * node) +{ + char *markup = + g_markup_printf_escaped ("<member name=\"%s\" value=\"%d\"/>\n", + node->node.name, node->value); + g_igenerator_write (igenerator, markup); + g_free (markup); +} + +static void +constant_generate (GIGenerator * igenerator, GIdlNodeConstant * node) +{ + char *markup = + g_markup_printf_escaped + ("<constant name=\"%s\" type=\"%s\" value=\"%s\"/>\n", node->node.name, + node->type->unparsed, node->value); + g_igenerator_write (igenerator, markup); + g_free (markup); +} + +static void +property_generate (GIGenerator * igenerator, GIdlNodeProperty * node) +{ + char *markup = + g_markup_printf_escaped + ("<property name=\"%s\" type=\"%s\" readable=\"%s\" writable=\"%s\" construct=\"%s\" construct-only=\"%s\"/>\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 ("<callback name=\"%s\">\n", node->node.name); + } + else if (node->is_constructor) + { + tag_name = "constructor"; + markup = + g_markup_printf_escaped ("<constructor name=\"%s\" symbol=\"%s\">\n", + node->node.name, node->symbol); + } + else if (node->is_method) + { + tag_name = "method"; + markup = + g_markup_printf_escaped ("<method name=\"%s\" symbol=\"%s\">\n", + node->node.name, node->symbol); + } + else + { + tag_name = "function"; + markup = + g_markup_printf_escaped ("<function name=\"%s\" symbol=\"%s\">\n", + node->node.name, node->symbol); + } + + g_igenerator_write_indent (igenerator, markup); + g_free (markup); + markup = + g_markup_printf_escaped ("<return-type type=\"%s\"/>\n", + node->result->type->unparsed); + g_igenerator_write (igenerator, markup); + g_free (markup); + if (node->parameters != NULL) + { + GList *l; + g_igenerator_write_indent (igenerator, "<parameters>\n"); + for (l = node->parameters; l != NULL; l = l->next) + { + GIdlNodeParam *param = l->data; + markup = + g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n", + param->node.name, param->type->unparsed); + g_igenerator_write (igenerator, markup); + g_free (markup); + } + g_igenerator_write_unindent (igenerator, "</parameters>\n"); + } + markup = g_strdup_printf ("</%s>\n", tag_name); + g_igenerator_write_unindent (igenerator, markup); + g_free (markup); +} + +static void +vfunc_generate (GIGenerator * igenerator, GIdlNodeVFunc * node) +{ + char *markup = + g_markup_printf_escaped ("<vfunc name=\"%s\">\n", node->node.name); + g_igenerator_write_indent (igenerator, markup); + g_free (markup); + markup = + g_markup_printf_escaped ("<return-type type=\"%s\"/>\n", + node->result->type->unparsed); + g_igenerator_write (igenerator, markup); + g_free (markup); + if (node->parameters != NULL) + { + GList *l; + g_igenerator_write_indent (igenerator, "<parameters>\n"); + for (l = node->parameters; l != NULL; l = l->next) + { + GIdlNodeParam *param = l->data; + markup = + g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n", + param->node.name, param->type->unparsed); + g_igenerator_write (igenerator, markup); + g_free (markup); + } + g_igenerator_write_unindent (igenerator, "</parameters>\n"); + } + g_igenerator_write_unindent (igenerator, "</vfunc>\n"); +} + +static void +signal_generate (GIGenerator * igenerator, GIdlNodeSignal * node) +{ + char *markup; + const char *when = "LAST"; + if (node->run_first) + { + when = "FIRST"; + } + else if (node->run_cleanup) + { + when = "CLEANUP"; + } + markup = + g_markup_printf_escaped ("<signal name=\"%s\" when=\"%s\">\n", + node->node.name, when); + g_igenerator_write_indent (igenerator, markup); + g_free (markup); + markup = + g_markup_printf_escaped ("<return-type type=\"%s\"/>\n", + node->result->type->unparsed); + g_igenerator_write (igenerator, markup); + g_free (markup); + if (node->parameters != NULL) + { + GList *l; + g_igenerator_write_indent (igenerator, "<parameters>\n"); + for (l = node->parameters; l != NULL; l = l->next) + { + GIdlNodeParam *param = l->data; + markup = + g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n", + param->node.name, param->type->unparsed); + g_igenerator_write (igenerator, markup); + g_free (markup); + } + g_igenerator_write_unindent (igenerator, "</parameters>\n"); + } + g_igenerator_write_unindent (igenerator, "</signal>\n"); +} + +static void +interface_generate (GIGenerator * igenerator, GIdlNodeInterface * node) +{ + GList *l; + char *markup; + if (node->node.type == G_IDL_NODE_OBJECT) + { + markup = + g_markup_printf_escaped + ("<object name=\"%s\" parent=\"%s\" type-name=\"%s\" get-type=\"%s\">\n", + node->node.name, node->parent, node->gtype_name, node->gtype_init); + } + else if (node->node.type == G_IDL_NODE_INTERFACE) + { + markup = + g_markup_printf_escaped + ("<interface name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n", + node->node.name, node->gtype_name, node->gtype_init); + } + + g_igenerator_write_indent (igenerator, markup); + g_free (markup); + if (node->node.type == G_IDL_NODE_OBJECT && node->interfaces != NULL) + { + GList *l; + g_igenerator_write_indent (igenerator, "<implements>\n"); + for (l = node->interfaces; l != NULL; l = l->next) + { + markup = + g_markup_printf_escaped ("<interface name=\"%s\"/>\n", + (char *) l->data); + g_igenerator_write (igenerator, markup); + g_free (markup); + } + g_igenerator_write_unindent (igenerator, "</implements>\n"); + } + else if (node->node.type == G_IDL_NODE_INTERFACE + && node->prerequisites != NULL) + { + GList *l; + g_igenerator_write_indent (igenerator, "<requires>\n"); + for (l = node->prerequisites; l != NULL; l = l->next) + { + markup = + g_markup_printf_escaped ("<interface name=\"%s\"/>\n", + (char *) l->data); + g_igenerator_write (igenerator, markup); + g_free (markup); + } + g_igenerator_write_unindent (igenerator, "</requires>\n"); + } + + for (l = node->members; l != NULL; l = l->next) + { + node_generate (igenerator, l->data); + } + + if (node->node.type == G_IDL_NODE_OBJECT) + { + g_igenerator_write_unindent (igenerator, "</object>\n"); + } + else if (node->node.type == G_IDL_NODE_INTERFACE) + { + g_igenerator_write_unindent (igenerator, "</interface>\n"); + } +} + +static void +struct_generate (GIGenerator * igenerator, GIdlNodeStruct * node) +{ + GList *l; + char *markup = + g_markup_printf_escaped ("<struct name=\"%s\">\n", node->node.name); + g_igenerator_write_indent (igenerator, markup); + g_free (markup); + for (l = node->members; l != NULL; l = l->next) + { + node_generate (igenerator, l->data); + } + g_igenerator_write_unindent (igenerator, "</struct>\n"); +} + +static void +union_generate (GIGenerator * igenerator, GIdlNodeUnion * node) +{ + GList *l; + char *markup = + g_markup_printf_escaped ("<union name=\"%s\">\n", node->node.name); + g_igenerator_write_indent (igenerator, markup); + g_free (markup); + for (l = node->members; l != NULL; l = l->next) + { + node_generate (igenerator, l->data); + } + g_igenerator_write_unindent (igenerator, "</union>\n"); +} + +static void +boxed_generate (GIGenerator * igenerator, GIdlNodeBoxed * node) +{ + GList *l; + char *markup = + g_markup_printf_escaped + ("<boxed name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n", + node->node.name, node->gtype_name, node->gtype_init); + g_igenerator_write_indent (igenerator, markup); + g_free (markup); + for (l = node->members; l != NULL; l = l->next) + { + node_generate (igenerator, l->data); + } + g_igenerator_write_unindent (igenerator, "</boxed>\n"); +} + +static void +enum_generate (GIGenerator * igenerator, GIdlNodeEnum * node) +{ + GList *l; + char *markup; + const char *tag_name = NULL; + + if (node->node.type == G_IDL_NODE_ENUM) + { + tag_name = "enum"; + } + else if (node->node.type == G_IDL_NODE_FLAGS) + { + tag_name = "flags"; + } + markup = + g_markup_printf_escaped ("<%s name=\"%s\">\n", tag_name, node->node.name); + g_igenerator_write_indent (igenerator, markup); + g_free (markup); + + for (l = node->values; l != NULL; l = l->next) + { + node_generate (igenerator, l->data); + } + + markup = g_strdup_printf ("</%s>\n", tag_name); + g_igenerator_write_unindent (igenerator, markup); + g_free (markup); +} + +static void +node_generate (GIGenerator * igenerator, GIdlNode * node) +{ + switch (node->type) + { + case G_IDL_NODE_FUNCTION: + case G_IDL_NODE_CALLBACK: + function_generate (igenerator, (GIdlNodeFunction *) node); + break; + case G_IDL_NODE_VFUNC: + vfunc_generate (igenerator, (GIdlNodeVFunc *) node); + break; + case G_IDL_NODE_OBJECT: + case G_IDL_NODE_INTERFACE: + interface_generate (igenerator, (GIdlNodeInterface *) node); + break; + case G_IDL_NODE_STRUCT: + struct_generate (igenerator, (GIdlNodeStruct *) node); + break; + case G_IDL_NODE_UNION: + union_generate (igenerator, (GIdlNodeUnion *) node); + break; + case G_IDL_NODE_BOXED: + boxed_generate (igenerator, (GIdlNodeBoxed *) node); + break; + case G_IDL_NODE_ENUM: + case G_IDL_NODE_FLAGS: + enum_generate (igenerator, (GIdlNodeEnum *) node); + break; + case G_IDL_NODE_PROPERTY: + property_generate (igenerator, (GIdlNodeProperty *) node); + break; + case G_IDL_NODE_FIELD: + field_generate (igenerator, (GIdlNodeField *) node); + break; + case G_IDL_NODE_SIGNAL: + signal_generate (igenerator, (GIdlNodeSignal *) node); + break; + case G_IDL_NODE_VALUE: + value_generate (igenerator, (GIdlNodeValue *) node); + break; + case G_IDL_NODE_CONSTANT: + constant_generate (igenerator, (GIdlNodeConstant *) node); + break; + default: + g_assert_not_reached (); + } +} + +static void +module_generate (GIGenerator * igenerator, GIdlModule * module) +{ + GList *l; + char *markup = + g_markup_printf_escaped ("<namespace name=\"%s\">\n", module->name); + g_igenerator_write_indent (igenerator, markup); + g_free (markup); + for (l = module->entries; l != NULL; l = l->next) + { + node_generate (igenerator, l->data); + } + g_igenerator_write_unindent (igenerator, "</namespace>\n"); +} + +static GIdlNodeType * +get_type_from_type_id (GType type_id) +{ + GIdlNodeType *gitype = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE); + + GType type_fundamental = g_type_fundamental (type_id); + + if (type_fundamental == G_TYPE_STRING) + { + gitype->unparsed = g_strdup ("char*"); + } + else if (type_id == G_TYPE_STRV) + { + gitype->unparsed = g_strdup ("char*[]"); + } + else if (type_fundamental == G_TYPE_INTERFACE + || type_fundamental == G_TYPE_BOXED + || type_fundamental == G_TYPE_OBJECT) + { + gitype->unparsed = g_strdup_printf ("%s*", g_type_name (type_id)); + } + else if (type_fundamental == G_TYPE_PARAM) + { + gitype->unparsed = g_strdup ("GParamSpec*"); + } + else + { + gitype->unparsed = g_strdup (g_type_name (type_id)); + } + + return gitype; +} + +static char * +str_replace (const char *str, const char *needle, const char *replacement) +{ + char **strings = g_strsplit (str, needle, 0); + char *result = g_strjoinv (replacement, strings); + g_strfreev (strings); + return result; +} + +static void +g_igenerator_process_properties (GIGenerator * igenerator, + GIdlNodeInterface * ginode, GType type_id) +{ + int i; + guint n_properties; + GParamSpec **properties; + + if (ginode->node.type == G_IDL_NODE_OBJECT) + { + GObjectClass *type_class = g_type_class_ref (type_id); + properties = g_object_class_list_properties (type_class, &n_properties); + } + else if (ginode->node.type == G_IDL_NODE_INTERFACE) + { + GTypeInterface *iface = g_type_default_interface_ref (type_id); + properties = g_object_interface_list_properties (iface, &n_properties); + } + else + { + g_assert_not_reached (); + } + + for (i = 0; i < n_properties; i++) + { + /* ignore inherited properties */ + if (properties[i]->owner_type != type_id) + { + continue; + } + GIdlNodeProperty *giprop = + (GIdlNodeProperty *) g_idl_node_new (G_IDL_NODE_PROPERTY); + giprop->node.name = properties[i]->name; + ginode->members = + g_list_insert_sorted (ginode->members, giprop, + (GCompareFunc) g_idl_node_cmp); + giprop->type = get_type_from_type_id (properties[i]->value_type); + 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, "<?xml version=\"1.0\"?>\n"); + g_igenerator_write_indent (igenerator, "<api version=\"1.0\">\n"); + module_generate (igenerator, igenerator->module); + g_igenerator_write_unindent (igenerator, "</api>\n"); +} + +int +main (int argc, char **argv) +{ + g_type_init (); + + /* 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/src/gen-introspect.h b/src/gen-introspect.h new file mode 100644 index 00000000..23f0aa05 --- /dev/null +++ b/src/gen-introspect.h @@ -0,0 +1,162 @@ +/* GObject introspection: gen-introspect + * + * Copyright (C) 2007 Jürg Billeter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: + * Jürg Billeter <j@bitron.ch> + */ + +#ifndef __GEN_INTROSPECT_H__ +#define __GEN_INTROSPECT_H__ + +#include <glib.h> +#include "gidlmodule.h" + +G_BEGIN_DECLS typedef struct _GIGenerator GIGenerator; +typedef struct _CSymbol CSymbol; +typedef struct _CType CType; + +struct _GIGenerator +{ + const char *namespace; + char *lower_case_namespace; + /* specified files to be parsed */ + GList *filenames; + GList *libraries; + /* source reference of current lexer position */ + char *current_filename; + GList *symbol_list; + GHashTable *typedef_table; + GHashTable *struct_or_union_or_enum_table; + + gboolean macro_scan; + + GIdlModule *module; + GList *get_type_symbols; + GHashTable *type_map; + GHashTable *type_by_lower_case_prefix; + + int indent; +}; + +GIGenerator *g_igenerator_new (void); +void g_igenerator_parse (GIGenerator * igenerator, FILE * f); +void g_igenerator_add_symbol (GIGenerator * igenerator, CSymbol * symbol); +gboolean g_igenerator_is_typedef (GIGenerator * igenerator, const char *name); +void g_igenerator_generate (GIGenerator * igenerator); + +GIGenerator *the_igenerator; + +typedef enum +{ + CSYMBOL_TYPE_INVALID, + CSYMBOL_TYPE_CONST, + CSYMBOL_TYPE_OBJECT, + CSYMBOL_TYPE_FUNCTION, + CSYMBOL_TYPE_STRUCT, + CSYMBOL_TYPE_UNION, + CSYMBOL_TYPE_ENUM, + CSYMBOL_TYPE_TYPEDEF +} CSymbolType; + +struct _CSymbol +{ + CSymbolType type; + int id; + char *ident; + CType *base_type; + gboolean const_int_set; + int const_int; + char *const_string; +}; + +CSymbol *csymbol_new (CSymbolType type); +gboolean csymbol_get_const_boolean (CSymbol * symbol); + +typedef enum +{ + CTYPE_INVALID, + CTYPE_VOID, + CTYPE_BASIC_TYPE, + CTYPE_TYPEDEF, + CTYPE_STRUCT, + CTYPE_UNION, + CTYPE_ENUM, + CTYPE_POINTER, + CTYPE_ARRAY, + CTYPE_FUNCTION +} CTypeType; + +typedef enum +{ + STORAGE_CLASS_NONE = 0, + STORAGE_CLASS_TYPEDEF = 1 << 1, + STORAGE_CLASS_EXTERN = 1 << 2, + STORAGE_CLASS_STATIC = 1 << 3, + STORAGE_CLASS_AUTO = 1 << 4, + STORAGE_CLASS_REGISTER = 1 << 5 +} StorageClassSpecifier; + +typedef enum +{ + TYPE_QUALIFIER_NONE = 0, + TYPE_QUALIFIER_CONST = 1 << 1, + TYPE_QUALIFIER_RESTRICT = 1 << 2, + TYPE_QUALIFIER_VOLATILE = 1 << 3 +} TypeQualifier; + +typedef enum +{ + FUNCTION_NONE = 0, + FUNCTION_INLINE = 1 << 1 +} FunctionSpecifier; + +typedef enum +{ + UNARY_ADDRESS_OF, + UNARY_POINTER_INDIRECTION, + UNARY_PLUS, + UNARY_MINUS, + UNARY_BITWISE_COMPLEMENT, + UNARY_LOGICAL_NEGATION +} UnaryOperator; + +struct _CType +{ + CTypeType type; + StorageClassSpecifier storage_class_specifier; + TypeQualifier type_qualifier; + FunctionSpecifier function_specifier; + char *name; + CType *base_type; + GList *child_list; +}; + +CType *ctype_new (CTypeType type); +CType *ctype_copy (CType * type); +CType *cbasic_type_new (const char *name); +CType *ctypedef_new (const char *name); +CType *cstruct_new (const char *name); +CType *cunion_new (const char *name); +CType *cenum_new (const char *name); +CType *cpointer_new (CType * base_type); +CType *carray_new (void); +CType *cfunction_new (void); + +G_END_DECLS +#endif |