/* GOB C Preprocessor * Copyright (C) 1999,2000 the Free Software Foundation. * Copyright (C) 2000 Eazel, Inc. * Copyright (C) 2001 George Lebl * * Author: George Lebl * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "config.h" #include #include #include #include #include #include #include #include "treefuncs.h" #include "parse.h" #include "out.h" #include "util.h" #include "checks.h" #include "main.h" char *filename = NULL; int yyparse(void); extern int yydebug; extern FILE * yyin; extern Node *class; extern GList *nodes; extern GList *include_files; extern GHashTable *gtk_doc_hash; char *filebase; static char *funcbase; static char *pfuncbase; static char *macrobase; static char *macrois; static char *pmacrois; static char *macrotype; static char *pmacrotype; static char *typebase; static char *ptypebase; static int signals = 0; /* number of signals */ static int set_properties = 0; /* number of named (set) properties */ static int get_properties = 0; /* number of named (get) properties */ static int overrides = 0; /* number of override methods */ static int privates = 0; /* number of private data members */ static int protecteds = 0; /* number of protected methods */ static int unreftors = 0; /* number of variable unreffing destructors */ static int destructors = 0; /* number of variable non-unreffing destructors */ static int initializers = 0; /* number of variable initializers */ static gboolean overrode_get_type = FALSE; /* provided your won _get_type */ static gboolean made_aliases = FALSE; /* if we made any shorthand aliases and need the REALLY UGLY HACK to avoid warnings */ /* the special variable types we need to define */ static gboolean special_array[SPECIAL_LAST] = {0}; static gboolean any_special = FALSE; static gboolean need_shutdown = FALSE; static Method * shutdown_handler = NULL; static gboolean need_finalize = FALSE; static Method * finalize_handler = NULL; FILE *out = NULL; FILE *outh = NULL; FILE *outph = NULL; FILE *devnull = NULL; gboolean no_touch_headers = FALSE; gboolean for_cpp = FALSE; gboolean no_gnu = FALSE; gboolean exit_on_warn = FALSE; gboolean exit_on_error = TRUE; gboolean got_error = FALSE; gint private_header = PRIVATE_HEADER_ONDEMAND; gboolean no_extern_c = FALSE; gboolean no_write = FALSE; gboolean no_lines = FALSE; gboolean no_self_alias = FALSE; gboolean always_private_struct = FALSE; int method_unique_id = 1; static void make_bases (void) { filebase = replace_sep (((Class *)class)->otype, '-'); g_strdown (filebase); funcbase = replace_sep (((Class *)class)->otype, '_'); g_strdown (funcbase); pfuncbase = replace_sep (((Class *)class)->ptype, '_'); g_strdown (pfuncbase); macrobase = replace_sep (((Class *)class)->otype, '_'); g_strup (macrobase); macrois = make_pre_macro (((Class *)class)->otype, "IS"); pmacrois = make_pre_macro (((Class *)class)->ptype, "IS"); macrotype = make_pre_macro (((Class *)class)->otype, "TYPE"); pmacrotype = make_pre_macro (((Class *)class)->ptype, "TYPE"); typebase = remove_sep (((Class *)class)->otype); ptypebase = remove_sep (((Class *)class)->ptype); } static char * get_type (const Type *t, gboolean postfix_to_stars) { char *s; int i; int extra; GString *gs; s = remove_sep(t->name); gs = g_string_new(s); g_free(s); extra = 0; if (postfix_to_stars) { const char *p; /*XXX: this is ugly perhaps we can do this whole postfix thing in a nicer way, we just count the number of '[' s and from that we deduce the number of dimensions, so that we can print that many stars */ for (p = t->postfix; p && *p; p++) if(*p == '[') extra++; } g_string_append_c(gs, ' '); if (t->pointer != NULL) { g_string_append (gs, t->pointer); for (i=0; i < extra; i++) g_string_append_c (gs, '*'); g_string_append_c (gs, ' '); } s = gs->str; g_string_free (gs, FALSE); return s; } static char * get_gtk_doc (const char *id) { char *val; if(!gtk_doc_hash) return NULL; val = g_hash_table_lookup(gtk_doc_hash, id); if(val) return g_strdup_printf("/**\n * %s_%s:\n%s **/\n", funcbase, id, val); val = g_hash_table_lookup(gtk_doc_hash, id); if(val) return g_strdup_printf("/**\n * %s_%s:\n%s **/\n", funcbase, id, val); return NULL; } static void print_type(FILE *fp, const Type *t, gboolean postfix_to_stars) { char *s; s = get_type(t, postfix_to_stars); out_printf(fp, "%s", s); g_free(s); } static void print_method (FILE *fp, const char *typeprefix, const char *nameprefix, const char *subnameprefix, const char *namepostfix, const char *afterargs, const char *postfix, const Method *m, gboolean one_arg_per_line, gboolean no_funcbase, gboolean kill_underscore) { GList *li; const char *id; out_printf(fp, "%s", typeprefix); print_type(fp, m->mtype, TRUE); id = m->id; if(no_funcbase) out_printf(fp, "%s%s%s%s(", nameprefix, subnameprefix, id, namepostfix); else out_printf(fp, "%s%s_%s%s%s(", nameprefix, funcbase, subnameprefix, id, namepostfix); if(m->args) { for(li=m->args; li; li=g_list_next(li)) { FuncArg *arg = li->data; print_type(fp, arg->atype, FALSE); if(li->next) out_printf(fp, "%s%s,%s", arg->name, arg->atype->postfix ? arg->atype->postfix : "", one_arg_per_line ? "\n\t\t\t\t\t" : " "); else out_printf(fp, "%s%s", arg->name, arg->atype->postfix ? arg->atype->postfix : ""); } if(m->vararg) out_printf(fp, ",%s...", one_arg_per_line ? "\n\t\t\t\t\t" : " "); } else { out_printf(fp, "void"); } out_printf(fp, "%s)%s", afterargs, postfix); } static gboolean any_method_to_alias(Class *c) { GList *li; for(li=c->nodes;li;li=g_list_next(li)) { Node *node = li->data; if(node->type == METHOD_NODE) { Method *m = (Method *)node; if(m->method == INIT_METHOD || m->method == CLASS_INIT_METHOD || m->method == OVERRIDE_METHOD) continue; return TRUE; } } return FALSE; } /* just the vararg macros, we use the same func pointers for these as in non-gnu */ static void make_method_gnu_aliases(Class *c) { GList *li; for(li = c->nodes; li != NULL; li = li->next) { Node *node = li->data; if(node->type == METHOD_NODE) { Method *m = (Method *)node; if(m->method == INIT_METHOD || m->method == CLASS_INIT_METHOD || m->method == OVERRIDE_METHOD) continue; if(m->args != NULL) out_printf(out, "#define self_%s(args...) " "%s_%s(args)\n", m->id, funcbase, m->id); else out_printf(out, "#define self_%s() " "%s_%s()\n", m->id, funcbase, m->id); } } } static void make_method_nongnu_aliases(Class *c) { GList *li; gboolean local_made_aliases = FALSE; for(li=c->nodes; li; li=g_list_next(li)) { Node *node = li->data; if(node->type == METHOD_NODE) { Method *m = (Method *)node; if(m->method == INIT_METHOD || m->method == CLASS_INIT_METHOD || m->method == OVERRIDE_METHOD) continue; if( ! local_made_aliases) out_printf(out, "\n/* Short form pointers */\n"); print_method(out, "static ", "(* const self_", "", ") ", "", "", m, FALSE, TRUE, FALSE); out_printf(out, " = %s_%s;\n", funcbase, m->id); local_made_aliases = TRUE; } } if(local_made_aliases) { out_printf(out, "\n"); made_aliases = TRUE; } } static void add_bad_hack_to_avoid_unused_warnings(Class *c) { GList *li; /* if we haven't had any methods, just return */ if( ! made_aliases) return; if( ! no_gnu) out_printf(out, "\n\n#if (!defined __GNUC__) || (defined __GNUC__ && defined __STRICT_ANSI__)\n"); out_printf(out, "/*REALLY BAD HACK\n" " This is to avoid unused warnings if you don't call\n" " some method. I need to find a better way to do\n" " this, not needed in GCC since we use some gcc\n" " extentions to make saner, faster code */\n" "static void\n" "___%s_really_bad_hack_to_avoid_warnings(void)\n" "{\n", funcbase); out_printf(out, "\t((void (*)(void))GET_NEW_VARG)();\n"); for(li=c->nodes;li;li=g_list_next(li)) { Node *node = li->data; if(node->type == METHOD_NODE) { Method *m = (Method *)node; if(m->method == INIT_METHOD || m->method == CLASS_INIT_METHOD || m->method == OVERRIDE_METHOD) continue; /* in C++ mode we don't alias new */ if(for_cpp && strcmp(m->id, "new")==0) continue; out_printf(out, "\t((void (*)(void))self_%s)();\n", m->id); } } out_printf(out, "\t___%s_really_bad_hack_to_avoid_warnings();\n", funcbase); if(!no_gnu) out_printf(out, "}\n#endif /* !__GNUC__ || (__GNUC__ && __STRICT_ANSI__) */\n\n"); else out_printf(out, "}\n\n"); } static void put_variable(Variable *v, FILE *fp) { out_printf(fp, "\t"); print_type(fp, v->vtype, FALSE); out_printf(fp, "%s%s;", v->id, v->vtype->postfix? v->vtype->postfix:""); if(v->scope == PROTECTED_SCOPE) out_printf(fp, " /* protected */"); out_printf(fp, "\n"); } static void put_vs_method(const Method *m) { if(m->method != SIGNAL_LAST_METHOD && m->method != SIGNAL_FIRST_METHOD && m->method != VIRTUAL_METHOD) return; /* if a signal mark it as such */ if(m->method != VIRTUAL_METHOD) print_method(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n", m, FALSE, TRUE, TRUE); else print_method(outh, "\t", "(* ", "", ") ", "", ";\n", m, FALSE, TRUE, TRUE); } static void put_pub_method(const Method *m) { if(m->scope != PUBLIC_SCOPE) return; print_method(outh, "", "\t", "", "\t", "", ";\n", m, TRUE, FALSE, TRUE); } static void put_signal_macro (const Method *m, gboolean gnu) { char *id; if(m->method != SIGNAL_LAST_METHOD && m->method != SIGNAL_FIRST_METHOD) return; id = g_strdup (m->id); g_strup (id); if ( ! gnu) { out_printf (outh, "#define %s_SIGNAL_%s(func)\t" "\"%s\",(GCallback)(func)\n", macrobase, id, m->id); } else { out_printf (outh, "#define %s_SIGNAL_%s(func)\t" "\"%s\",(GCallback)(({", macrobase, id, m->id); print_method (outh, "", "(* ___", "", ") ", ", gpointer data ", " = func; ", m, FALSE, TRUE, TRUE); out_printf (outh, "___%s; }))\n", m->id); } g_free (id); } static void put_signal_macros (const Class *c, gboolean gnu) { const GList *li; if (signals < 0) return; for (li = c->nodes; li != NULL; li = li->next) { const Node *n = li->data; if (n->type == METHOD_NODE) put_signal_macro ((Method *)n, gnu); } } static void put_prot_method(const Method *m) { if(m->scope != PROTECTED_SCOPE) return; if(outph) print_method(outph, "", "\t", "", "\t", "", ";\n", m, FALSE, FALSE, TRUE); else print_method(out, "", "\t", "", "\t", "", ";\n", m, FALSE, FALSE, TRUE); } static void put_priv_method_prot(Method *m) { if(m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD || m->method == VIRTUAL_METHOD) { if(m->cbuf) print_method(out, "static ", "___real_", "", " ", "", ";\n", m, FALSE, FALSE, TRUE); } /* no else, here, it might still have a private prototype, it's not * exclusive */ if((m->method == OVERRIDE_METHOD && m->cbuf)) { /* add unique ID */ char *s = g_strdup_printf("___%x_", (guint)m->unique_id); print_method(out, "static ", s, "", " ", "", no_gnu?";\n":" G_GNUC_UNUSED;\n", m, FALSE, FALSE, FALSE); g_free(s); } else if(m->scope == PRIVATE_SCOPE || m->method == INIT_METHOD || m->method == CLASS_INIT_METHOD) { print_method(out, "static ", "", "", " ", "", no_gnu?";\n":" G_GNUC_UNUSED;\n", m, FALSE, FALSE, TRUE); } } static GList * make_func_arg(char *typename, int is_class, char *name) { Node *node; Node *type; char *tn; if(is_class) tn = g_strconcat(typename, ":Class", NULL); else tn = g_strdup(typename); type = node_new (TYPE_NODE, "name:steal", tn, "pointer", "*", NULL); node = node_new (FUNCARG_NODE, "atype:steal", (Type *)type, "name:steal", name, NULL); return g_list_prepend(NULL, node); } static void make_inits(Class *cl) { int got_class_init = FALSE; int got_init = FALSE; GList *li; Node *node; for(li=cl->nodes;li;li=g_list_next(li)) { Node *n = li->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == INIT_METHOD) { if(got_init) error_print(GOB_ERROR, m->line_no, "init defined more then once"); got_init = TRUE; } else if(m->method == CLASS_INIT_METHOD) { if(got_class_init) error_print(GOB_ERROR, m->line_no, "class_init defined more then once"); got_class_init = TRUE; } } } if(!got_class_init) { Type *type = (Type *)node_new (TYPE_NODE, "name", "void", NULL); node = node_new (METHOD_NODE, "scope", NO_SCOPE, "method", CLASS_INIT_METHOD, "mtype:steal", type, "id", "class_init", "args:steal", make_func_arg (cl->otype, TRUE, g_strdup("c")), "unique_id", method_unique_id++, NULL); cl->nodes = g_list_prepend(cl->nodes, node); } if(!got_init) { Type *type = (Type *)node_new (TYPE_NODE, "name", "void", NULL); node = node_new (METHOD_NODE, "scope", NO_SCOPE, "method", INIT_METHOD, "mtype:steal", type, "id", "init", "args:steal", make_func_arg (cl->otype, TRUE, g_strdup("o")), "unique_id", method_unique_id++, NULL); cl->nodes = g_list_prepend(cl->nodes, node); } } static void find_shutdown(Class *cl) { GList *li; shutdown_handler = NULL; for(li=cl->nodes;li;li=g_list_next(li)) { Node *n = li->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == OVERRIDE_METHOD && strcmp(m->id, "shutdown")==0) { if(strcmp(m->otype, "G:Object") != 0) { error_print(GOB_ERROR, m->line_no, "shutdown method override " "of class other then " "G:Object"); } if(g_list_length(m->args) != 1) { error_print(GOB_ERROR, m->line_no, "shutdown method override " "with more then one " "parameter"); } shutdown_handler = m; break; } } } } static void find_finalize(Class *cl) { GList *li; finalize_handler = NULL; for(li=cl->nodes;li;li=g_list_next(li)) { Node *n = li->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == OVERRIDE_METHOD && strcmp(m->id, "finalize")==0) { if(strcmp(m->otype, "G:Object") != 0) { error_print(GOB_ERROR, m->line_no, "finalize method override " "of class other then " "G:Object"); } if(g_list_length(m->args) != 1) { error_print(GOB_ERROR, m->line_no, "finalize method override " "with more then one " "parameter"); } finalize_handler = m; break; } } } } /* hash of method -> name of signal prototype */ static GHashTable *marsh = NULL; /* list of methods with different signal prototypes, we check this list if we can use a signal prototype of a previous signal method, there are only uniques here */ static GList *eq_signal_methods = NULL; /* compare a list of strings */ static gboolean is_list_equal(GList *a, GList *b) { for(;a && b; a=a->next, b=b->next) { if(strcmp(a->data, b->data)!=0) { return FALSE; } } /* the the lists were different length */ if(a || b) return FALSE; return TRUE; } static Method * find_same_type_signal(Method *m) { GList *li; for(li=eq_signal_methods;li;li=li->next) { Method *mm = li->data; if(is_list_equal(mm->gtktypes, m->gtktypes)) return mm; } return NULL; } static void print_signal_marsal_args (Method *m) { if (strcmp (m->gtktypes->next->data, "NONE") != 0) { GList *li; int i; for (i = 0, li = m->gtktypes->next; li != NULL; i++, li = li->next) { char *get_func = g_strdup_printf ("g_value_get_%s", (char *)li->data); g_strdown (get_func); out_printf (out, ",\n\t\t(%s) " "%s (param_values + %d)", get_cast (li->data, FALSE), get_func, i + 1); g_free (get_func); } } out_printf (out, ",\n\t\tdata2);\n"); } static void add_signal_prots(Method *m) { GList *li; static int sig = 1; char *s; Method *mm; gboolean ret_none = FALSE; gboolean arglist_none = FALSE; const char *retcast; if (m->method != SIGNAL_LAST_METHOD && m->method != SIGNAL_FIRST_METHOD) return; if (marsh == NULL) marsh = g_hash_table_new(NULL, NULL); g_assert (m->gtktypes->next != NULL); ret_none = strcmp(m->gtktypes->data, "NONE") == 0; arglist_none = strcmp(m->gtktypes->next->data, "NONE") == 0; if (ret_none && arglist_none) return; /* if we already did a signal prototype just use that */ mm = find_same_type_signal (m); if (mm != NULL) { s = g_hash_table_lookup (marsh, mm); g_hash_table_insert (marsh, m, s); return; } if (ret_none) retcast = NULL; else retcast = get_cast (m->gtktypes->data, FALSE); s = g_strdup_printf("Sig%d", sig++); g_hash_table_insert(marsh, m, s); eq_signal_methods = g_list_prepend(eq_signal_methods, m); /* we know that we'll know all the gtktypes (so get_cast can't fail) */ out_printf(out, "\ntypedef %s (*___%s) (%s *, ", get_cast(m->gtktypes->data, FALSE), s, typebase); if ( ! arglist_none) { for (li = m->gtktypes->next; li != NULL; li = li->next) out_printf (out, "%s, ", get_cast (li->data, FALSE)); } out_printf (out, "gpointer);\n"); out_printf (out, "\nstatic void\n" "___marshal_%s (GClosure *closure,\n" "\tGValue *return_value,\n" "\tguint n_param_values,\n" "\tconst GValue *param_values,\n" "\tgpointer invocation_hint,\n" "\tgpointer marshal_data)\n" "{\n", s); if ( ! ret_none) out_printf (out, "\t%s v_return;\n", retcast); out_printf (out, "\tregister ___%s callback;\n" "\tregister GCClosure *cc = (GCClosure*) closure;\n" "\tregister gpointer data1, data2;\n\n", s); out_printf (out, "\tg_return_if_fail (n_param_values == %d);\n\n", arglist_none ? 1 : g_list_length (m->gtktypes)); out_printf (out, "\tif (G_CCLOSURE_SWAP_DATA (closure)) {\n" "\t\tdata1 = closure->data;\n" "\t\tdata2 = g_value_peek_pointer (param_values + 0);\n" "\t} else {\n" "\t\tdata1 = g_value_peek_pointer (param_values + 0);\n" "\t\tdata2 = closure->data;\n" "\t}\n\n"); out_printf (out, "\tcallback = (___%s) " "(marshal_data != NULL ? marshal_data : cc->callback);" "\n\n", s); if (ret_none) { out_printf (out, "\tcallback ((%s *)data1", typebase); } else { out_printf (out, "\tv_return = callback ((%s *)data1", typebase); } print_signal_marsal_args (m); if ( ! ret_none) { /* FIXME: This code is so fucking ugly it hurts */ gboolean take_ownership = (strcmp ((char *)m->gtktypes->data, "STRING") == 0 || strcmp ((char *)m->gtktypes->data, "BOXED") == 0); char *set_func = g_strdup_printf ("g_value_set_%s%s", (char *)m->gtktypes->data, take_ownership ? "_take_ownership" : ""); g_strdown (set_func); out_printf (out, "\n\t%s (return_value, v_return);\n", set_func); g_free (set_func); } out_printf (out, "}\n\n"); } static void add_enums(Class *c) { GList *li; out_printf(out, "\n"); if(signals>0) { out_printf(out, "enum {\n"); for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD) { char *s = g_strdup(m->id); g_strup(s); out_printf(out, "\t%s_SIGNAL,\n", s); g_free(s); } } } out_printf(out, "\tLAST_SIGNAL\n};\n\n"); } if (set_properties > 0 || get_properties > 0) { out_printf(out, "enum {\n\tPROP_0"); for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; if (n->type == PROPERTY_NODE) { Property *p = (Property *)n; char *s = g_strdup (p->name); g_strup (s); out_printf (out, ",\n\tPROP_%s", s); g_free(s); } else if (n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; char *s = g_strdup(a->name); g_strup(s); out_printf(out, ",\n\tPROP_%s", s); g_free(s); } } out_printf(out, "\n};\n\n"); } if (signals > 0) out_printf(out, "static guint object_signals[LAST_SIGNAL] = {0};\n\n"); out_printf(out, "/* pointer to the class of our parent */\n"); out_printf(out, "static %sClass *parent_class = NULL;\n\n", ptypebase); } static void add_get_type(void) { /*char *chunk_size = ((Class*)class)->chunk_size;*/ out_printf(out, "GType\n" "%s_get_type (void)\n" "{\n" "\tstatic GType type = 0;\n\n" "\tif (type == 0) {\n" "\t\tstatic const GTypeInfo info = {\n" "\t\t\tsizeof (%sClass),\n" "\t\t\t(GBaseInitFunc) NULL,\n" "\t\t\t(GBaseFinalizeFunc) NULL,\n" "\t\t\t(GClassInitFunc) %s_class_init,\n" "\t\t\t(GClassFinalizeFunc) NULL,\n" "\t\t\tNULL /* class_data */,\n" "\t\t\tsizeof (%s),\n" "\t\t\t0 /* n_preallocs */,\n" "\t\t\t(GInstanceInitFunc) %s_init,\n" "\t\t};\n\n" "\t\ttype = g_type_register_static (%s, \"%s\", &info, (GTypeFlags)0);\n", funcbase, typebase, funcbase, typebase, funcbase, pmacrotype, typebase); /* if(chunk_size) { out_printf(out, "#if %s > 0\n" "\t\tgtk_type_set_chunk_alloc(type, %s);\n" "#endif\n", chunk_size, chunk_size); } */ out_printf(out, "\t}\n\n" "\treturn type;\n" "}\n\n"); } static void add_bonobo_x_get_type (void) { /* char *chunk_size = ((Class*)class)->chunk_size; */ out_printf(out, "\n#error \"BonoboX isn't ported to glib 2.0 and " "gob2 doesn't support it yet\""); out_printf(out, "GtkType\n" "%s_get_type (void)\n" "{\n" "\tstatic GtkType type = 0;\n\n" "\tif (type == 0) {\n" "\t\tstatic const GtkTypeInfo info = {\n" "\t\t\t\"%s\",\n" "\t\t\tsizeof (%s),\n" "\t\t\tsizeof (%sClass),\n" "\t\t\t(GtkClassInitFunc) %s_class_init,\n" "\t\t\t(GtkObjectInitFunc) %s_init,\n" "\t\t\t/* reserved_1 */ NULL,\n" "\t\t\t/* reserved_2 */ NULL,\n" "\t\t\t(GtkClassInitFunc) NULL\n" "\t\t};\n\n" "\t\ttype = bonobo_x_type_unique\n" "\t\t\t(%s_get_type (),\n" "\t\t\tPOA_%s__init, NULL,\n" "\t\t\tGTK_STRUCT_OFFSET (%sClass, _epv),\n" "\t\t\t&info);\n", funcbase, typebase, typebase, typebase, funcbase, funcbase, pfuncbase, ((Class*)class)->bonobo_x_class, typebase); /*if(chunk_size) { out_printf(out, "#if %s > 0\n" "\t\tgtk_type_set_chunk_alloc(type, %s);\n" "#endif\n", chunk_size, chunk_size); }*/ out_printf(out, "\t}\n\n" "\treturn type;\n" "}\n\n"); } static void add_overrides(Class *c, const char *oname, gboolean did_base_obj) { GList *li; GHashTable *done; char *s; done = g_hash_table_new (g_str_hash, g_str_equal); if (did_base_obj) { s = g_strdup ("GObject"); g_hash_table_insert (done, s, s); } for (li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; char *f; Method *m = (Method *)n; if(n->type != METHOD_NODE || m->method != OVERRIDE_METHOD) continue; s = remove_sep(m->otype); if(g_hash_table_lookup(done, s)) { g_free(s); continue; } g_hash_table_insert(done, s, s); f = replace_sep(m->otype, '_'); g_strdown(f); out_printf(out, "\t%sClass *%s_class = (%sClass *)%s;\n", s, f, s, oname); g_free(f); } g_hash_table_foreach (done, (GHFunc)g_free, NULL); g_hash_table_destroy (done); } static char * make_run_signal_flags(Method *m, gboolean last) { GList *li; GString *gs; char *flags[] = { "RUN_FIRST", "RUN_LAST", "RUN_CLEANUP", "NO_RECURSE", "DETAILED", "ACTION", "NO_HOOKS", NULL }; gs = g_string_new(NULL); if(last) g_string_assign(gs, "G_SIGNAL_RUN_LAST"); else g_string_assign(gs, "G_SIGNAL_RUN_FIRST"); if(m->scope == PUBLIC_SCOPE) g_string_append(gs, " | G_SIGNAL_ACTION"); for(li = m->flags; li; li = li->next) { char *flag = li->data; int i; for(i=0;flags[i];i++) { if(strcmp(flags[i], flag)==0) break; } /* if we haven't found it in our list */ if( ! flags[i]) { error_printf(GOB_WARN, m->line_no, "Unknown flag '%s' used, " "perhaps it was misspelled", flag); } g_string_sprintfa(gs, " | G_SIGNAL_%s", flag); } { char *ret = gs->str; g_string_free(gs, FALSE); return ret; } } static void add_signals(Class *c) { GList *li; out_printf(out, "\n"); for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; char *mar, *sig, *flags; gboolean is_none, last = FALSE; Method *m = (Method *)n; if(n->type != METHOD_NODE || (m->method != SIGNAL_FIRST_METHOD && m->method != SIGNAL_LAST_METHOD)) continue; if(m->method == SIGNAL_FIRST_METHOD) last = FALSE; else last = TRUE; if(g_hash_table_lookup(marsh, m)) mar = g_strconcat("___marshal_", (char *)g_hash_table_lookup(marsh, m), NULL); else mar = g_strdup("g_cclosure_marshal_VOID__VOID"); is_none = (strcmp(m->gtktypes->next->data, "NONE")==0); sig = g_strdup (m->id); g_strup (sig); flags = make_run_signal_flags (m, last); out_printf (out, "\tobject_signals[%s_SIGNAL] =\n" "\t\tg_signal_new (\"%s\",\n" "\t\t\tG_TYPE_FROM_CLASS (g_object_class),\n" "\t\t\t(GSignalFlags)(%s),\n" "\t\t\tG_STRUCT_OFFSET (%sClass, %s),\n" "\t\t\tNULL, NULL,\n" "\t\t\t%s,\n" "\t\t\tG_TYPE_%s, %d", sig, m->id, flags, typebase, m->id, mar, (char *)m->gtktypes->data, is_none ? 0 : g_list_length(m->gtktypes->next)); g_free(mar); g_free(sig); g_free(flags); if( ! is_none) { GList *l; for(l = m->gtktypes->next; l != NULL; l = l->next) out_printf(out, ",\n\t\t\tG_TYPE_%s", (char *)l->data); } out_printf(out, ");\n"); if(strcmp(m->gtktypes->data, "NONE") != 0 || ! is_none) { GList *gl, *al; char *sep = ""; out_printf(out, "\tif("); if(strcmp(m->gtktypes->data, "NONE") != 0) { out_printf(out, "%s sizeof(", sep); print_type(out, m->mtype, FALSE); out_printf(out, "%s", m->mtype->postfix ? m->mtype->postfix : ""); out_printf(out, ") != sizeof(%s)", get_cast(m->gtktypes->data, FALSE)); sep = " || "; } for(al = m->args->next, gl = m->gtktypes->next; al != NULL && gl != NULL; al = al->next, gl = gl->next) { FuncArg *arg = al->data; char *gtkarg = gl->data; out_printf(out, "%ssizeof(", sep); print_type(out, arg->atype, FALSE); out_printf(out, "%s", arg->atype->postfix ? arg->atype->postfix : ""); out_printf(out, ") != sizeof(%s)", get_cast(gtkarg, FALSE)); sep = " || "; } out_printf(out, ") {\n" "\t\tg_error(\"%s line %d: Type mismatch " "of \\\"%s\\\" signal signature\");\n" "\t}\n", filename, m->line_no, m->id); } } } static void set_def_handlers(Class *c, const char *oname) { GList *li; gboolean set_line = FALSE; out_printf(out, "\n"); for(li = c->nodes; li; li = g_list_next(li)) { Node *n = li->data; Method *m = (Method *)n; if(n->type != METHOD_NODE || (m->method != SIGNAL_FIRST_METHOD && m->method != SIGNAL_LAST_METHOD && m->method != VIRTUAL_METHOD && m->method != OVERRIDE_METHOD)) continue; if(m->line_no > 0 && m->cbuf) { out_addline_infile(out, m->line_no); set_line = TRUE; } else if(set_line) { out_addline_outfile(out); set_line = FALSE; } if (m->method == OVERRIDE_METHOD) { char *s; s = replace_sep (m->otype, '_'); g_strdown (s); if (need_shutdown && shutdown_handler != NULL && strcmp (m->id, "shutdown") == 0) out_printf (out, "\tg_object_class->shutdown " "= ___shutdown;\n"); else if (need_finalize && finalize_handler && strcmp(m->id, "finalize") == 0) out_printf(out, "\tg_object_class->finalize = ___finalize;\n"); else if (m->cbuf != NULL) out_printf(out, "\t%s_class->%s = ___%x_%s_%s;\n", s, m->id, (guint)m->unique_id, funcbase, m->id); else out_printf(out, "\t%s_class->%s = NULL;\n", s, m->id); } else { if(m->cbuf) out_printf(out, "\t%s->%s = ___real_%s_%s;\n", oname, m->id, funcbase, m->id); else out_printf(out, "\t%s->%s = NULL;\n", oname, m->id); } } if(set_line) out_addline_outfile(out); } static void make_argument (Argument *a) { GString *flags; GList *l; char *s; char *argflags[] = { "CONSTRUCT", "CONSTRUCT_ONLY", "CHILD_ARG", "MASK", NULL }; flags = g_string_new ("(GParamFlags)("); if(a->get && a->set) g_string_append (flags, "G_PARAM_READABLE | G_PARAM_WRITABLE"); else if(a->get) g_string_append (flags, "G_PARAM_READABLE"); else g_string_append (flags, "G_PARAM_WRITABLE"); g_assert(a->get || a->set); for (l = a->flags; l != NULL; l = l->next) { char *flag = l->data; int i; if(strcmp (flag, "READABLE") == 0 || strcmp (flag, "WRITABLE") == 0) { error_print(GOB_WARN, a->line_no, "READABLE and " "WRITABLE argument flags are " "set automatically"); continue; } for(i = 0; argflags[i]; i++) { if(strcmp(argflags[i], flag)==0) break; } /* if we haven't found it in our list */ if( ! argflags[i]) { error_printf(GOB_WARN, a->line_no, "Unknown flag '%s' used, " "perhaps it was misspelled", flag); } g_string_sprintfa(flags, " | G_PARAM_%s", flag); } g_string_append (flags, ")"); s = g_strdup(a->name); g_strup(s); if (!strcmp (a->gtktype, "ENUM")) out_printf(out, "\tparam_spec = g_param_spec_enum (\"%s\", NULL, NULL,\n" "\t\tG_TYPE_ENUM, 0,\n" "\t\t%s);\n", a->name, flags->str); if (!strcmp (a->gtktype, "FLAGS")) out_printf(out, "\tparam_spec = g_param_spec_flags (\"%s\", NULL, NULL,\n" "\t\tG_TYPE_FLAGS, 0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "OBJECT")) out_printf(out, "\tparam_spec = g_param_spec_object (\"%s\", NULL, NULL,\n" "\t\tG_TYPE_OBJECT,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "STRING")) out_printf(out, "\tparam_spec = g_param_spec_string (\"%s\", NULL, NULL,\n" "\t\tNULL,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "INT")) out_printf(out, "\tparam_spec = g_param_spec_int (\"%s\", NULL, NULL,\n" "\t\tG_MININT, G_MAXINT,\n" "\t\t0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "UINT")) out_printf(out, "\tparam_spec = g_param_spec_uint (\"%s\", NULL, NULL,\n" "\t\t0, G_MAXUINT,\n" "\t\t0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "INT")) out_printf(out, "\tparam_spec = g_param_spec_int (\"%s\", NULL, NULL,\n" "\t\tG_MININT, G_MAXINT,\n" "\t\t0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "CHAR")) out_printf(out, "\tparam_spec = g_param_spec_char (\"%s\", NULL, NULL,\n" "\t\t-128, 127,\n" "\t\t0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "UCHAR")) out_printf(out, "\tparam_spec = g_param_spec_uchar (\"%s\", NULL, NULL,\n" "\t\t0, 0xFF,\n" "\t\t0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "BOOL") || !strcmp (a->gtktype, "BOOLEAN")) out_printf(out, "\tparam_spec = g_param_spec_boolean (\"%s\", NULL, NULL,\n" "\t\tFALSE,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "LONG")) out_printf(out, "\tparam_spec = g_param_spec_long (\"%s\", NULL, NULL,\n" "\t\tG_MINLONG, G_MAXLONG,\n" "\t\t0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "ULONG")) out_printf(out, "\tparam_spec = g_param_spec_ulong (\"%s\", NULL, NULL,\n" "\t\t0, G_MAXULONG,\n" "\t\t0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "FLOAT")) out_printf(out, "\tparam_spec = g_param_spec_float (\"%s\", NULL, NULL,\n" "\t\tG_MINFLOAT, G_MAXFLOAT,\n" "\t\t0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "DOUBLE")) out_printf(out, "\tparam_spec = g_param_spec_double (\"%s\", NULL, NULL,\n" "\t\tG_MINDOUBLE, G_MAXDOUBLE,\n" "\t\t0,\n" "\t\t%s);\n", a->name, flags->str); else if (!strcmp (a->gtktype, "POINTER")) out_printf(out, "\tparam_spec = g_param_spec_pointer (\"%s\", NULL, NULL,\n" "\t\t%s);\n", a->name, flags->str); else error_printf (GOB_ERROR, a->line_no, "%s type is not supported for arguments, try using properties", a->gtktype); out_printf(out, "\tg_object_class_install_property (g_object_class,\n" "\t\tPROP_%s, param_spec);\n", s); g_free(s); g_string_free(flags, TRUE); } #define value_for_print(str, alt) (str != NULL ? str : alt) static void make_property (Property *p) { GString *flags; GList *l; char *s; char *argflags[] = { "CONSTRUCT", "CONSTRUCT_ONLY", "CHILD_ARG", "MASK", NULL }; flags = g_string_new ("(GParamFlags)("); if (p->get != NULL && p->set != NULL) g_string_append (flags, "G_PARAM_READABLE | G_PARAM_WRITABLE"); else if (p->get != NULL) g_string_append (flags, "G_PARAM_READABLE"); else g_string_append (flags, "G_PARAM_WRITABLE"); if (p->get == NULL && p->set == NULL) { error_print (GOB_ERROR, p->line_no, "Property has no getter nor setter"); } for (l = p->flags; l != NULL; l = l->next) { char *flag = l->data; int i; if(strcmp (flag, "READABLE") == 0 || strcmp (flag, "WRITABLE") == 0) { error_print(GOB_WARN, p->line_no, "READABLE and " "WRITABLE argument flags are " "set automatically"); continue; } for(i = 0; argflags[i]; i++) { if(strcmp(argflags[i], flag)==0) break; } /* if we haven't found it in our list */ if( ! argflags[i]) { error_printf(GOB_WARN, p->line_no, "Unknown flag '%s' used, " "perhaps it was misspelled", flag); } g_string_sprintfa(flags, " | G_PARAM_%s", flag); } g_string_append (flags, ")"); if (strcmp (p->gtktype, "CHAR") == 0) out_printf (out, "\tparam_spec = g_param_spec_char\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* minimum */,\n" "\t\t %s /* maximum */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->minimum, "-128"), value_for_print (p->maximum, "127"), value_for_print (p->default_value, "0"), flags->str); else if (strcmp (p->gtktype, "UCHAR") == 0) out_printf (out, "\tparam_spec = g_param_spec_uchar\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* minimum */,\n" "\t\t %s /* maximum */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->minimum, "0"), value_for_print (p->maximum, "0xFF"), value_for_print (p->default_value, "0"), flags->str); else if (strcmp (p->gtktype, "BOOLEAN") == 0) out_printf (out, "\tparam_spec = g_param_spec_boolean\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->default_value, "FALSE"), flags->str); else if (strcmp (p->gtktype, "INT") == 0) out_printf (out, "\tparam_spec = g_param_spec_int\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* minimum */,\n" "\t\t %s /* maximum */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->minimum, "G_MININT"), value_for_print (p->maximum, "G_MAXINT"), value_for_print (p->default_value, "0"), flags->str); else if (strcmp (p->gtktype, "UINT") == 0) out_printf (out, "\tparam_spec = g_param_spec_uint\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* minimum */,\n" "\t\t %s /* maximum */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->minimum, "0"), value_for_print (p->maximum, "G_MAXUINT"), value_for_print (p->default_value, "0"), flags->str); else if (strcmp (p->gtktype, "LONG") == 0) out_printf (out, "\tparam_spec = g_param_spec_long\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* minimum */,\n" "\t\t %s /* maximum */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->minimum, "G_MINLONG"), value_for_print (p->maximum, "G_MAXLONG"), value_for_print (p->default_value, "0"), flags->str); else if (strcmp (p->gtktype, "ULONG") == 0) out_printf (out, "\tparam_spec = g_param_spec_ulong\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* minimum */,\n" "\t\t %s /* maximum */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->minimum, "0"), value_for_print (p->maximum, "G_MAXULONG"), value_for_print (p->default_value, "0"), flags->str); else if (strcmp (p->gtktype, "UNICHAR") == 0) out_printf (out, "\tparam_spec = g_param_spec_unichar\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->default_value, "0"), flags->str); else if (strcmp (p->gtktype, "ENUM") == 0) out_printf (out, "\tparam_spec = g_param_spec_enum\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* enum_type */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->extra_gtktype, "G_TYPE_ENUM"), value_for_print (p->default_value, "0"), flags->str); else if (strcmp (p->gtktype, "FLAGS") == 0) out_printf (out, "\tparam_spec = g_param_spec_flags\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* flags_type */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->extra_gtktype, "G_TYPE_FLAGS"), value_for_print (p->default_value, "0"), flags->str); else if (strcmp (p->gtktype, "FLOAT") == 0) out_printf (out, "\tparam_spec = g_param_spec_float\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* minimum */,\n" "\t\t %s /* maximum */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->minimum, "G_MINFLOAT"), value_for_print (p->maximum, "G_MAXFLOAT"), value_for_print (p->default_value, "0.0"), flags->str); else if (strcmp (p->gtktype, "DOUBLE") == 0) out_printf (out, "\tparam_spec = g_param_spec_double\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* minimum */,\n" "\t\t %s /* maximum */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->minimum, "G_MINDOUBLE"), value_for_print (p->maximum, "G_MAXDOUBLE"), value_for_print (p->default_value, "0.0"), flags->str); else if (strcmp (p->gtktype, "STRING") == 0) out_printf (out, "\tparam_spec = g_param_spec_string\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* default_value */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->default_value, "NULL"), flags->str); else if (strcmp (p->gtktype, "PARAM") == 0) out_printf (out, "\tparam_spec = g_param_spec_param\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* param_type */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->extra_gtktype, "G_TYPE_PARAM"), flags->str); else if (strcmp (p->gtktype, "BOXED") == 0) out_printf (out, "\tparam_spec = g_param_spec_boxed\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* boxed_type */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->extra_gtktype, "G_TYPE_BOXED"), flags->str); else if (strcmp (p->gtktype, "POINTER") == 0) out_printf (out, "\tparam_spec = g_param_spec_pointer\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), flags->str); /* FIXME: VALUE_ARRAY */ else if (strcmp (p->gtktype, "CLOSURE") == 0) out_printf (out, "\tparam_spec = g_param_spec_pointer\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), flags->str); else if (strcmp (p->gtktype, "OBJECT") == 0) out_printf (out, "\tparam_spec = g_param_spec_object\n" "\t\t(\"%s\" /* name */,\n" "\t\t %s /* nick */,\n" "\t\t %s /* blurb */,\n" "\t\t %s /* object_type */,\n" "\t\t %s);\n", p->name, value_for_print (p->nick, "NULL"), value_for_print (p->blurb, "NULL"), value_for_print (p->extra_gtktype, "G_TYPE_OBJECT"), flags->str); else error_printf (GOB_ERROR, p->line_no, "%s type is not supported by properties", p->gtktype); s = g_strdup (p->name); g_strup (s); out_printf (out, "\tg_object_class_install_property (g_object_class,\n" "\t\tPROP_%s,\n" "\t\tparam_spec);\n", s); g_free (s); g_string_free (flags, TRUE); } static void make_arguments(Class *c) { GList *li; out_printf (out, " {\n" "\tGParamSpec *param_spec;\n\n"); for (li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; if (n->type == PROPERTY_NODE) make_property ((Property *)n); else if (n->type == ARGUMENT_NODE) make_argument ((Argument *)n); } out_printf(out, " }\n"); if (get_properties > 0) out_printf(out, "\tg_object_class->get_property = ___object_get_property;\n"); if (set_properties > 0) out_printf(out, "\tg_object_class->set_property = ___object_set_property;\n"); } static void print_initializer(Method *m, Variable *v) { char *root; if(v->initializer == NULL) return; if(v->scope == PRIVATE_SCOPE) root = g_strconcat(((FuncArg *)m->args->data)->name, "->_priv", NULL); else root = g_strdup(((FuncArg *)m->args->data)->name); if(v->initializer_line > 0) out_addline_infile(out, v->initializer_line); out_printf(out, "\t%s->%s = %s;\n", root, v->id, v->initializer); if(v->initializer_line > 0) out_addline_outfile(out); g_free(root); } static void print_destructor (Variable *v) { char *root; if(v->destructor == NULL) return; if(v->scope == PRIVATE_SCOPE) root = "self->_priv"; else root = "self"; if(v->destructor_simple) { if(v->destructor_line > 0) out_addline_infile(out, v->destructor_line); out_printf(out, "\tif(%s->%s) { " "((*(void (*)(void *))%s)) (%s->%s); " "%s->%s = NULL; }\n", root, v->id, v->destructor, root, v->id, root, v->id); if(v->destructor_line > 0) out_addline_outfile(out); } else { out_printf(out, "#define %s (%s->%s)\n", v->id, root, v->id); out_printf(out, "#define VAR %s\n", v->id); out_printf(out, "\t{\n"); if(v->destructor_line > 0) out_addline_infile(out, v->destructor_line); out_printf(out, "\t%s}\n", v->destructor); if(v->destructor_line > 0) out_addline_outfile(out); out_printf(out, "\tmemset(&%s, 0, sizeof(%s));\n", v->id, v->id); out_printf(out, "#undef VAR\n"); out_printf(out, "#undef %s\n", v->id); } } static void add_shutdown (Class *c) { out_printf(out, "\nstatic void\n" "___shutdown (GObject *obj_self)\n" "{\n"); out_printf(out, "#define __GOB_FUNCTION__ \"%s::shutdown\"\n", c->otype); if (unreftors > 0) { out_printf (out, "\t%s *self = %s (obj_self);\n", typebase, macrobase); } if (shutdown_handler != NULL) { /* so we get possible bad argument warning */ if (shutdown_handler->line_no > 0) out_addline_infile (out, shutdown_handler->line_no); out_printf (out, "\t___%x_%s_shutdown(obj_self);\n", (guint)shutdown_handler->unique_id, funcbase); if (shutdown_handler->line_no > 0) out_addline_outfile (out); } else { out_printf (out, "\tif (G_OBJECT_CLASS (parent_class)->shutdown) \\\n" "\t\t(* G_OBJECT_CLASS (parent_class)->shutdown) (obj_self);\n"); } if (unreftors > 0) { GList *li; for(li = ((Class *)class)->nodes; li != NULL; li = li->next) { Node *n = li->data; Variable *v = (Variable *)n; if (n->type == VARIABLE_NODE && v->scope != CLASS_SCOPE && v->destructor_unref) print_destructor (v); } } out_printf (out, "\treturn;\n"); if (unreftors > 0) out_printf(out, "\tself = NULL;\n"); out_printf(out, "}\n" "#undef __GOB_FUNCTION__\n\n"); } static void add_finalize (Class *c) { out_printf(out, "\nstatic void\n" "___finalize(GObject *obj_self)\n" "{\n"); out_printf(out, "#define __GOB_FUNCTION__ \"%s::finalize\"\n", c->otype); if (privates > 0 || destructors > 0) { out_printf(out, "\t%s *self = %s (obj_self);\n", typebase, macrobase); } if (privates > 0) { out_printf(out, "\tgpointer priv = self->_priv;\n"); } if(finalize_handler) { /* so we get possible bad argument warning */ if(finalize_handler->line_no > 0) out_addline_infile(out, finalize_handler->line_no); out_printf(out, "\t___%x_%s_finalize(obj_self);\n", (guint)finalize_handler->unique_id, funcbase); if(finalize_handler->line_no > 0) out_addline_outfile(out); } else { out_printf(out, "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n" "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n"); } if (destructors > 0) { GList *li; for (li = ((Class *)class)->nodes; li != NULL; li = li->next) { Node *n = li->data; Variable *v = (Variable *)n; if (n->type == VARIABLE_NODE && v->scope != CLASS_SCOPE && ! v->destructor_unref) print_destructor (v); } } if (privates > 0) { out_printf(out, "\tg_free (priv);\n"); } out_printf (out, "\treturn;\n"); if (destructors > 0 || privates > 0) out_printf (out, "\tself = NULL;\n"); out_printf(out, "}\n" "#undef __GOB_FUNCTION__\n\n"); } static void make_bonobo_x_epv (Class *c, const char *classname) { GList *li; gboolean added_line = FALSE; for (li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; Method *m = (Method *)n; if(n->type != METHOD_NODE || m->method == OVERRIDE_METHOD) continue; if (m->bonobo_x_func) { if(m->line_no > 0) { out_addline_infile(out, m->line_no); added_line = TRUE; } else if (m->line_no == 0 && added_line) { out_addline_outfile(out); added_line = FALSE; } out_printf (out, "\t%s->_epv.%s = %s;\n", classname, m->id, m->id); } } if (added_line) out_addline_outfile(out); } static void add_inits(Class *c) { GList *li; for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; Method *m; gboolean add_unused_class = FALSE; if(n->type != METHOD_NODE) continue; m = (Method *)n; if(m->method == INIT_METHOD) { if(m->line_no > 0) out_addline_infile(out, m->line_no); print_method(out, "static ", "\n", "", " ", "", "\n", m, FALSE, FALSE, TRUE); if(m->line_no > 0) out_addline_outfile(out); out_printf(out, "{\n" "#define __GOB_FUNCTION__ \"%s::init\"\n", c->otype); if(privates > 0) { out_printf(out, "\t%s->_priv = " "g_new0 (%sPrivate, 1);\n", ((FuncArg *)m->args->data)->name, typebase); } else if(always_private_struct) { out_printf(out, "\t%s->_priv = NULL;\n", ((FuncArg *)m->args->data)->name); } if(initializers > 0) { GList *li; for(li = ((Class *)class)->nodes; li != NULL; li = li->next) { Node *n = li->data; Variable *v = (Variable *)n; if(n->type != VARIABLE_NODE || v->scope == CLASS_SCOPE) continue; print_initializer(m, v); } } } else if(m->method == CLASS_INIT_METHOD) { gboolean did_base_obj = FALSE; if(m->line_no > 0) out_addline_infile(out, m->line_no); print_method(out, "static ", "\n", "", " ", "", "\n", m, FALSE, FALSE, TRUE); if(m->line_no > 0) out_addline_outfile(out); out_printf(out, "{\n" "#define __GOB_FUNCTION__ \"%s::class_init\"\n", c->otype); if (set_properties > 0 || get_properties > 0 || signals > 0 || need_shutdown || need_finalize) { out_printf(out, "\tGObjectClass *" "g_object_class = " "(GObjectClass*) %s;\n", ((FuncArg *)m->args->data)->name); add_unused_class = TRUE; did_base_obj = TRUE; } if (overrides > 0) add_overrides (c, ((FuncArg *)m->args->data)->name, did_base_obj); if (initializers > 0) { GList *li; for(li = ((Class *)class)->nodes; li != NULL; li = li->next) { Node *n = li->data; Variable *v = (Variable *)n; if(n->type == VARIABLE_NODE && v->scope == CLASS_SCOPE) print_initializer(m, v); } } out_printf(out, "\n\tparent_class = "); if(for_cpp) out_printf(out, "(%sClass *)", ptypebase); out_printf(out, "g_type_class_ref (%s);\n", pmacrotype); if(signals > 0) add_signals(c); set_def_handlers(c, ((FuncArg *)m->args->data)->name); /* if there are no handlers for these things, we * need to set them up here */ if(need_shutdown && !shutdown_handler) out_printf(out, "\tg_object_class->shutdown " "= ___shutdown;\n"); if(need_finalize && !finalize_handler) out_printf(out, "\tg_object_class->finalize = " "___finalize;\n"); if(get_properties > 0 || set_properties > 0) make_arguments(c); if (c->bonobo_x_class != NULL) { make_bonobo_x_epv (c, ((FuncArg *)m->args->data)->name); } } else continue; if(m->cbuf) { out_printf(out, " {\n"); out_addline_infile(out, m->ccode_line); out_printf(out, "%s\n", m->cbuf); out_addline_outfile(out); out_printf(out, " }\n"); } out_printf(out, "\treturn;\n"); out_printf(out, "\t%s = NULL;\n", ((FuncArg *)m->args->data)->name); if(add_unused_class) { out_printf (out, "\tg_object_class = NULL;\n"); } out_printf(out, "}\n" "#undef __GOB_FUNCTION__\n"); } } static void add_argument (Argument *a, gboolean is_set) { char *s; char *cbuf; char *the_type_lower; int line_no; if(is_set) { cbuf = a->set; line_no = a->set_line; } else { cbuf = a->get; line_no = a->get_line; } if (cbuf == NULL) return; s = g_strdup(a->name); g_strup(s); out_printf(out, "\tcase PROP_%s:\n\t{", s); the_type_lower = g_strdup (a->gtktype); g_strdown (the_type_lower); if (is_set) { char *cast; if (a->atype != NULL) cast = get_type (a->atype, TRUE); else cast = g_strdup (get_cast (a->gtktype, FALSE)); out_printf (out, "\t%s ARG = (%s) g_value_get_%s (VAL);\n", cast, cast, the_type_lower); g_free (cast); } else if ( ! is_set) { char *cast; if (a->atype != NULL) cast = get_type (a->atype, TRUE); else cast = g_strdup (get_cast (a->gtktype, FALSE)); out_printf (out, "\t%s ARG;\n" "\tmemset (&ARG, 0, sizeof (%s));\n", cast, cast); g_free(cast); } g_free (s); out_printf(out, "\t\t{\n"); if (line_no > 0) out_addline_infile (out, line_no); out_printf (out, "%s\n", cbuf); if (line_no > 0) out_addline_outfile (out); out_printf (out, "\t\t}\n"); if ( ! is_set) { if (strcmp (a->gtktype, "OBJECT") == 0) out_printf (out, "\t\tg_value_set_%s (VAL, G_OBJECT (ARG))\n", the_type_lower); else out_printf (out, "\t\t" "g_value_set_%s (VAL, ARG);\n", the_type_lower); } g_free (the_type_lower); if (is_set) { out_printf (out, "\t\tif (&ARG) ;\n"); } out_printf (out, "\t\tbreak;\n"); out_printf (out, "\t}\n"); } static void add_property (Property *p, gboolean is_set) { const char *cbuf; char *the_type_lower; char *name_upper; int line_no; if (is_set) { cbuf = p->set; line_no = p->set_line; } else { cbuf = p->get; line_no = p->get_line; } if (cbuf == NULL) return; name_upper = g_strdup (p->name); g_strup (name_upper); the_type_lower = g_strdup (p->gtktype); g_strdown (the_type_lower); out_printf (out, "\tcase PROP_%s:\n", name_upper); out_printf(out, "\t\t{\n"); if (line_no > 0) out_addline_infile (out, line_no); out_printf (out, "%s\n", cbuf); if (line_no > 0) out_addline_outfile (out); out_printf (out, "\t\t}\n"); g_free (name_upper); g_free (the_type_lower); out_printf (out, "\t\tbreak;\n"); } static void add_getset_arg(Class *c, gboolean is_set) { GList *li; out_printf(out, "\nstatic void\n" "___object_%s_property (GObject *object,\n" "\tguint property_id,\n" "\t%sGValue *VAL,\n" "\tGParamSpec *pspec)\n" "#define __GOB_FUNCTION__ \"%s::%s_property\"\n" "{\n" "\t%s *self;\n\n" "\tself = %s (object);\n\n" "\tswitch (property_id) {\n", is_set ? "set" : "get", is_set ? "const " : "", c->otype, is_set ? "set" : "get", typebase, macrobase); for (li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; if (n->type == PROPERTY_NODE) add_property ((Property *)n, is_set); else if (n->type == ARGUMENT_NODE) add_argument ((Argument *)n, is_set); } out_printf (out, "\tdefault:\n" "/* Apparently in g++ this is needed, glib is b0rk */\n" "#ifndef __PRETTY_FUNCTION__\n" "# undef G_STRLOC\n" "# define G_STRLOC __FILE__ \":\" G_STRINGIFY (__LINE__)\n" "#endif\n" "\t\tG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);\n" "\t\tbreak;\n\t}\n" "\treturn;\n\tself = NULL;\n\tVAL = NULL;\n\tpspec = NULL;\n}\n" "#undef __GOB_FUNCTION__\n"); } static void print_checks (Method *m, FuncArg *fa) { GList *li; gboolean is_void; gboolean checked_null = FALSE; is_void = (strcmp(m->mtype->name, "void")==0 && m->mtype->pointer == NULL); for(li = fa->checks; li != NULL; li = li->next) { Check *ch = li->data; char *s; /* point to the method prot in .gob for failed checks */ if(m->line_no > 0) out_addline_infile(out, m->line_no); if(is_void) out_printf(out, "\tg_return_if_fail ("); else out_printf(out, "\tg_return_val_if_fail ("); switch(ch->chtype) { case NULL_CHECK: out_printf(out, "%s != NULL", fa->name); checked_null = TRUE; break; case TYPE_CHECK: s = make_pre_macro(fa->atype->name, "IS"); if(checked_null) out_printf(out, "%s (%s)", s, fa->name); else /* if not check null, null may be valid */ out_printf(out, "!(%s) || %s (%s)", fa->name, s, fa->name); g_free(s); break; case LT_CHECK: out_printf(out, "%s < %s", fa->name, ch->number); break; case GT_CHECK: out_printf(out, "%s > %s", fa->name, ch->number); break; case LE_CHECK: out_printf(out, "%s <= %s", fa->name, ch->number); break; case GE_CHECK: out_printf(out, "%s >= %s", fa->name, ch->number); break; case EQ_CHECK: out_printf(out, "%s == %s", fa->name, ch->number); break; case NE_CHECK: out_printf(out, "%s != %s", fa->name, ch->number); break; } if(is_void) out_printf(out, ");\n"); else { out_printf(out, ", ("); print_type(out, m->mtype, TRUE); out_printf(out, ")%s);\n", m->onerror?m->onerror:"0"); } } } static void print_preconditions(Method *m) { GList *li; for(li=m->args;li;li=g_list_next(li)) { FuncArg *fa = li->data; if(fa->checks) print_checks(m, fa); } if(m->line_no>0) out_addline_outfile(out); } static void print_method_body(Method *m, int pre) { if (m->line_no > 0) out_addline_outfile(out); out_printf(out, "{\n" "#define __GOB_FUNCTION__ \"%s::%s\"\n", ((Class *)class)->otype, m->id); if(pre) print_preconditions(m); /* Note: the trailing }'s are on one line, this is so that we get the no return warning correctly and point to the correct line in the .gob file, yes this is slightly ugly in the .c file, but that is not supposed to be human readable anyway. */ if(m->cbuf) { out_printf(out, "{\n"); if(m->ccode_line>0) out_addline_infile(out, m->ccode_line); out_printf(out, "\t%s}", m->cbuf); } /* Note, there is no \n between the last } and this } so that * errors/warnings reported on the end of the body get pointed to the * right line in the .gob source */ out_printf(out, "}\n"); if(m->cbuf) out_addline_outfile(out); out_printf(out, "#undef __GOB_FUNCTION__\n"); } static void put_signal_args (Method *m) { GList *li; GList *ali; for (ali = m->gtktypes->next, li=m->args->next; li != NULL && ali != NULL; li = li->next, ali = ali->next) { FuncArg *fa = li->data; char *cast = g_strdup (get_cast (ali->data, FALSE)); if (cast == NULL) { cast = get_type (fa->atype, TRUE); } /* we should have already proved before that the we know all the types */ g_assert (cast != NULL); out_printf (out, ",\n\t\t(%s)%s", cast, fa->name); g_free (cast); } } static char * get_arg_names_for_macro(Method *m) { char *p; GList *li; GString *gs = g_string_new(NULL); p = ""; for(li=m->args;li;li=g_list_next(li)) { FuncArg *arg = li->data; g_string_sprintfa(gs, "%s___%s", p, arg->name); p = ","; } p = gs->str; g_string_free(gs, FALSE); return p; } static void put_method(Method *m) { char *s, *args, *doc; gboolean is_void; is_void = (strcmp(m->mtype->name, "void")==0 && m->mtype->pointer == NULL); out_printf(out, "\n"); if(m->method != OVERRIDE_METHOD) { doc = get_gtk_doc(m->id); if(doc) { out_printf(out, "%s", doc); g_free(doc); } } switch(m->method) { case REGULAR_METHOD: if(m->line_no > 0) out_addline_infile(out, m->line_no); if(m->scope == PRIVATE_SCOPE) print_method(out, "static ", "\n", "", " ", "", "\n", m, FALSE, FALSE, TRUE); else /* PUBLIC, PROTECTED */ print_method(out, "", "\n", "", " ", "", "\n", m, FALSE, FALSE, TRUE); print_method_body(m, TRUE); /* the outfile line was added above */ break; case SIGNAL_FIRST_METHOD: case SIGNAL_LAST_METHOD: if(m->line_no > 0) out_addline_infile(out, m->line_no); if(m->scope == PRIVATE_SCOPE) print_method(out, "static ", "\n", "", " ", "", "\n", m, FALSE, FALSE, TRUE); else /* PUBLIC, PROTECTED */ print_method(out, "", "\n", "", " ", "", "\n", m, FALSE, FALSE, TRUE); out_addline_outfile(out); out_printf(out, "{\n"); s = g_strdup(m->id); g_strup(s); if(strcmp(m->mtype->name, "void") == 0 && m->mtype->pointer == NULL) { print_preconditions(m); if(((FuncArg *)m->args->data)->name) out_printf(out, "\tg_signal_emit (G_OBJECT (%s),\n" "\t\tobject_signals[%s_SIGNAL], 0", ((FuncArg *)m->args->data)->name, s); put_signal_args (m); out_printf(out, ");\n}\n"); } else { out_printf(out, "\t"); print_type(out, m->mtype, TRUE); out_printf(out, "return_val = ("); print_type(out, m->mtype, TRUE); if(m->defreturn) out_printf(out, ")(%s);\n", m->defreturn); else if(m->onerror) out_printf(out, ")(%s);\n", m->onerror); else out_printf(out, ")(0);\n"); print_preconditions(m); out_printf(out, "\tg_signal_emit (G_OBJECT (%s),\n" "\t\tobject_signals[%s_SIGNAL], 0", ((FuncArg *)m->args->data)->name, s); put_signal_args(m); out_printf(out, ",\n\t\t&return_val);\n" "\treturn return_val;\n}\n"); } if(!m->cbuf) break; if(m->line_no > 0) out_addline_infile(out, m->line_no); print_method(out, "static ", "\n___real_", "", " ", "", "\n", m, FALSE, FALSE, TRUE); print_method_body(m, FALSE); /* the outfile line was added above */ break; case VIRTUAL_METHOD: if(m->line_no > 0) out_addline_infile(out, m->line_no); if(m->scope==PRIVATE_SCOPE) print_method(out, "static ", "\n", "", " ", "", "\n", m, FALSE, FALSE, TRUE); else /* PUBLIC, PROTECTED */ print_method(out, "", "\n", "", " ", "", "\n", m, FALSE, FALSE, TRUE); out_addline_outfile(out); out_printf(out, "{\n" "\t%sClass *klass;\n", typebase); print_preconditions(m); out_printf(out, "\tklass = %s_GET_CLASS(%s);\n\n" "\tif(klass->%s)\n", macrobase, ((FuncArg *)m->args->data)->name, m->id); if(strcmp(m->mtype->name, "void") == 0 && m->mtype->pointer == NULL) { GList *li; out_printf(out, "\t\t(*klass->%s)(%s", m->id, ((FuncArg *)m->args->data)->name); for(li=m->args->next;li;li=g_list_next(li)) { FuncArg *fa = li->data; out_printf(out, ",%s", fa->name); } out_printf(out, ");\n}\n"); } else { GList *li; out_printf(out, "\t\treturn (*klass->%s)(%s", m->id, ((FuncArg *)m->args->data)->name); for(li=m->args->next;li;li=g_list_next(li)) { FuncArg *fa = li->data; out_printf(out, ",%s", fa->name); } out_printf(out, ");\n" "\telse\n" "\t\treturn ("); print_type(out, m->mtype, TRUE); if(m->defreturn) out_printf(out, ")(%s);\n}\n", m->defreturn); else if(m->onerror) out_printf(out, ")(%s);\n}\n", m->onerror); else out_printf(out, ")(0);\n}\n"); } if(!m->cbuf) break; if(m->line_no > 0) out_addline_infile(out, m->line_no); print_method(out, "static ", "\n___real_", "", " ", "", "\n", m, FALSE, FALSE, TRUE); print_method_body(m, FALSE); /* the outfile line was added above */ break; case OVERRIDE_METHOD: if(!m->cbuf) break; if(m->line_no > 0) out_addline_infile(out, m->line_no); s = g_strdup_printf("\n___%x_", (guint)m->unique_id); print_method(out, "static ", s, "", " ", "", "\n", m, FALSE, FALSE, FALSE); g_free(s); out_addline_outfile(out); s = replace_sep(m->otype, '_'); g_strup(s); args = get_arg_names_for_macro(m); if(is_void) { out_printf(out, "#define PARENT_HANDLER(%s) \\\n" "\t{ if(%s_CLASS(parent_class)->%s) \\\n" "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n", args, s, m->id, s, m->id, args); } else { out_printf(out, "#define PARENT_HANDLER(%s) \\\n" "\t((%s_CLASS(parent_class)->%s)? \\\n" "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n" "\t\t(", args, s, m->id, s, m->id, args); out_printf(out, "("); print_type(out, m->mtype, TRUE); out_printf(out, ")%s))\n", m->onerror?m->onerror:"0"); } g_free(args); g_free(s); print_method_body(m, TRUE); /* the outfile line was added above */ out_printf(out, "#undef PARENT_HANDLER\n"); break; default: break; } } static void open_files(void) { char *outfile, *outfileh, *outfileph; if ( ! for_cpp) outfile = g_strconcat (filebase, ".c", NULL); else outfile = g_strconcat (filebase, ".cc", NULL); if (no_touch_headers) outfileh = g_strconcat ("#gob#", filebase, ".h#gob#", NULL); else outfileh = g_strconcat (filebase, ".h", NULL); if ((privates > 0 || protecteds > 0 || private_header == PRIVATE_HEADER_ALWAYS) && private_header != PRIVATE_HEADER_NEVER) outfileph = g_strconcat (filebase, "-private.h", NULL); else outfileph = NULL; if (no_write) { devnull = fopen ("/dev/null", "w"); if (devnull == NULL) g_error ("Cannot open null device"); out = devnull; outh = devnull; if (outfileph != NULL) outph = devnull; } else { out = fopen (outfile, "w"); if (out == NULL) { g_error ("Cannot open outfile: %s", outfile); } outh = fopen (outfileh, "w"); if (outh == NULL) g_error ("Cannot open outfile: %s", outfileh); if (outfileph != NULL) { outph = fopen (outfileph, "w"); if (outph == NULL) g_error ("Cannot open outfile: %s", outfileh); } } } static void put_argument_nongnu_wrappers (Class *c) { GList *li; if (get_properties < 0 && set_properties < 0) return; for (li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; const char *name, *gtktype; gboolean get, set; Type *atype; char *aname; char *cast; if (n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; name = a->name; gtktype = a->gtktype; atype = a->atype; get = a->get != NULL; set = a->set != NULL; } else if (n->type == PROPERTY_NODE) { Property *p = (Property *)n; name = p->name; gtktype = p->gtktype; atype = p->ptype; get = p->get != NULL; set = p->set != NULL; } else { continue; } aname = g_strdup (name); g_strup (aname); if (atype != NULL) cast = get_type (atype, TRUE); else cast = g_strdup (get_cast (gtktype, TRUE)); if (cast != NULL) { if (set) out_printf (outh, "#define %s_PROP_%s(arg) \t" "\"%s\",(%s)(arg)\n", macrobase, aname, name, cast); if (get) out_printf (outh, "#define %s_GET_PROP_%s(arg)\t" "\"%s\",(%s*)(arg)\n", macrobase, aname, name, cast); } else { if(set) out_printf (outh, "#define %s_PROP_%s(arg) \t" "\"%s\",(arg)\n", macrobase, aname, name); if(get) out_printf (outh, "#define %s_GET_PROP_%s(arg)\t" "\"%s\",(arg)\n", macrobase, aname, name); } g_free (cast); g_free (aname); } } static void put_argument_gnu_wrappers(Class *c) { GList *li; if(get_properties < 0 && set_properties < 0) return; for (li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; const char *name, *gtktype; gboolean get, set; Type *atype; char *aname; char *cast; if (n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; name = a->name; gtktype = a->gtktype; atype = a->atype; get = a->get != NULL; set = a->set != NULL; } else if (n->type == PROPERTY_NODE) { Property *p = (Property *)n; name = p->name; gtktype = p->gtktype; atype = p->ptype; get = p->get != NULL; set = p->set != NULL; } else { continue; } aname = g_strdup (name); g_strup (aname); if (atype != NULL) cast = get_type (atype, TRUE); else cast = g_strdup (get_cast (gtktype, TRUE)); if (cast != NULL) { if (set) out_printf (outh, "#define %s_PROP_%s(arg) \t" "\"%s\",({%sz = (arg); z;})\n", macrobase, aname, name, cast); if (get) out_printf (outh, "#define %s_GET_PROP_%s(arg)\t" "\"%s\",({%s*z = (arg); z;})\n", macrobase, aname, name, cast); } else { if (set) out_printf (outh, "#define %s_PROP_%s(arg) \t" "\"%s\",(arg)\n", macrobase, aname, name); if (get) out_printf (outh, "#define %s_GET_PROP_%s(arg)\t" "\"%s\",(arg)\n", macrobase, aname, name); } g_free (cast); g_free (aname); } } static void print_ccode_block(CCode *cc) { FILE *fp; switch(cc->cctype) { case HT_CCODE: /* HT code is printed exactly like normal header code but is printed before */ case H_CCODE: fp = outh; out_printf(fp, "\n"); break; case AT_CCODE: /* AT code is printed exactly like normal 'all' code but is printed before */ case A_CCODE: if(outph) { out_printf(outph, "\n"); out_printf(outph, "%s\n", cc->cbuf); out_addline_infile(outph, cc->line_no); out_addline_outfile(outph); } out_printf(outh, "\n"); out_printf(outh, "%s\n", cc->cbuf); fp = out; out_printf(fp, "\n"); out_addline_infile(fp, cc->line_no); break; default: case C_CCODE: fp = out; out_printf(fp, "\n"); out_addline_infile(fp, cc->line_no); break; case PH_CCODE: if(outph) fp = outph; else fp = out; out_printf(fp, "\n"); out_addline_infile(fp, cc->line_no); break; } out_printf(fp, "%s\n", cc->cbuf); if(cc->cctype == C_CCODE || cc->cctype == A_CCODE || cc->cctype == AT_CCODE || cc->cctype == PH_CCODE) out_addline_outfile(fp); } static void print_class_block(Class *c) { GList *li; char *s; gboolean printed_private = FALSE; if(any_special) { out_printf(out, "/* utility types we may need */\n"); if(special_array[SPECIAL_2POINTER]) out_printf(out, "typedef struct { " "gpointer a; gpointer b; " "} ___twopointertype;\n"); if(special_array[SPECIAL_3POINTER]) out_printf(out, "typedef struct { " "gpointer a; gpointer b; " "gpointer c; " "} ___threepointertype;\n"); if(special_array[SPECIAL_INT_POINTER]) out_printf(out, "typedef struct { " "gint a; gpointer b; " "} ___intpointertype;\n"); out_printf(out, "\n"); } out_printf(outh, "\n/*\n" " * Type checking and casting macros\n" " */\n"); out_printf(outh, "#define %s\t" "(%s_get_type())\n", macrotype, funcbase); out_printf(outh, "#define %s(obj)\t" "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s)\n", macrobase, funcbase, typebase); out_printf(outh, "#define %s_CONST(obj)\t" "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s const)\n", macrobase, funcbase, typebase); out_printf(outh, "#define %s_CLASS(klass)\t" "G_TYPE_CHECK_CLASS_CAST((klass), %s_get_type(), %sClass)\n", macrobase, funcbase, typebase); out_printf(outh, "#define %s(obj)\t" "G_TYPE_CHECK_INSTANCE_TYPE((obj), %s_get_type ())\n\n", macrois, funcbase); out_printf(outh, "#define %s_GET_CLASS(obj)\t" "G_TYPE_INSTANCE_GET_CLASS((obj), %s_get_type(), %sClass)\n", macrobase, funcbase, typebase); if ( ! no_self_alias) { out_printf(out, "/* self casting macros */\n"); out_printf(out, "#define SELF(x) %s(x)\n", macrobase); out_printf(out, "#define SELF_CONST(x) %s_CONST(x)\n", macrobase); out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois); out_printf(out, "#define TYPE_SELF %s\n", macrotype); out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n", macrobase); out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n", macrobase); out_printf(out, "/* self typedefs */\n"); out_printf(out, "typedef %s Self;\n", typebase); out_printf(out, "typedef %sClass SelfClass;\n\n", typebase); } if (privates > 0 || always_private_struct) { out_printf (outh, "\n/* Private structure type */\n"); out_printf (outh, "typedef struct _%sPrivate %sPrivate;\n", typebase, typebase); if (privates == 0) out_printf (outh, "/* There are no privates, this " "structure is thus never defined */\n"); } out_printf (outh, "\n/*\n" " * Main object structure\n" " */\n"); s = replace_sep (c->otype, '_'); g_strup (s); out_printf (outh, "#ifndef __TYPEDEF_%s__\n" "#define __TYPEDEF_%s__\n", s, s); g_free (s); out_printf (outh, "typedef struct _%s %s;\n" "#endif\n", typebase, typebase); out_printf (outh, "struct _%s {\n\t%s __parent__;\n", typebase, ptypebase); for (li = c->nodes; li; li=li->next) { static gboolean printed_public = FALSE; Node *n = li->data; Variable *v = (Variable *)n; if(n->type == VARIABLE_NODE && v->scope == PUBLIC_SCOPE) { if( ! printed_public) { out_printf(outh, "\t/*< public >*/\n"); printed_public = TRUE; } put_variable((Variable *)n, outh); } } /* put protecteds always AFTER publics */ for (li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; Variable *v = (Variable *)n; if (n->type == VARIABLE_NODE && v->scope == PROTECTED_SCOPE) { if ( ! printed_private) { out_printf (outh, "\t/*< private >*/\n"); printed_private = TRUE; } put_variable ((Variable *)n, outh); } } if (privates > 0 || always_private_struct) { if ( ! printed_private) out_printf (outh, "\t/*< private >*/\n"); out_printf (outh, "\t%sPrivate *_priv;\n", typebase); } out_printf (outh, "};\n"); if (privates > 0) { FILE *outfp; /* if we are to stick this into the private header, if not stick it directly into the C file */ if (outph != NULL) outfp = outph; else outfp = out; out_printf (outfp, "struct _%sPrivate {\n", typebase); for(li=c->nodes; li; li=li->next) { Node *n = li->data; Variable *v = (Variable *)n; if(n->type == VARIABLE_NODE && v->scope == PRIVATE_SCOPE) { out_addline_infile(outfp, v->line_no); put_variable(v, outfp); } } out_addline_outfile(outfp); out_printf(outfp, "};\n"); } out_printf(outh, "\n/*\n" " * Class definition\n" " */\n"); out_printf(outh, "typedef struct _%sClass %sClass;\n", typebase, typebase); out_printf(outh, "struct _%sClass {\n\t%sClass __parent__;\n", typebase, ptypebase); for(li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; if(n->type == METHOD_NODE) put_vs_method((Method *)n); } /* If BonoboX type class put down the epv */ if (c->bonobo_x_class != NULL) { out_printf (outh, "\t/* Bonobo object epv */\n" "\tPOA_%s__epv _epv;\n", c->bonobo_x_class); } /* put class scope variables */ for (li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; Variable *v = (Variable *)n; if (n->type == VARIABLE_NODE && v->scope == CLASS_SCOPE) put_variable ((Variable *)n, outh); } out_printf (outh, "};\n\n"); out_printf (out, "/* here are local prototypes */\n"); if (set_properties > 0) { out_printf (out, "static void ___object_set_property " "(GObject *object, guint property_id, " "const GValue *value, GParamSpec *pspec);\n"); } if (get_properties > 0) { out_printf (out, "static void ___object_get_property " "(GObject *object, guint property_id, " "GValue *value, GParamSpec *pspec);\n"); } out_printf (outh, "\n/*\n" " * Public methods\n" " */\n"); if ( ! overrode_get_type) { out_printf (outh, "GType\t%s_get_type\t(void)", funcbase); if ( ! no_gnu) { out_printf (outh, " G_GNUC_CONST;\n"); } else { out_printf (outh, ";\n"); } } for(li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; if(n->type == METHOD_NODE) { put_pub_method((Method *)n); put_prot_method((Method *)n); put_priv_method_prot((Method *)n); } } /* this idea is less and less apealing to me */ if (signals > 0) { out_printf (outh, "\n/*\n" " * Signal connection wrapper macros\n" " */\n"); if( ! no_gnu) { out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n"); put_signal_macros (c, TRUE); out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n"); put_signal_macros (c, FALSE); out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n"); } else { put_signal_macros (c, FALSE); } } /* argument wrapping macros */ if(get_properties > 0 || set_properties > 0) { out_printf(outh, "\n/*\n" " * Argument wrapping macros\n" " */\n"); if( ! no_gnu) { out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n"); put_argument_gnu_wrappers(c); out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n"); put_argument_nongnu_wrappers(c); out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n"); } else { put_argument_nongnu_wrappers(c); } } if(signals > 0) { for(li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; if(n->type == METHOD_NODE) add_signal_prots((Method *)n); } } add_enums(c); if ( ! overrode_get_type) { if (c->bonobo_x_class != NULL) add_bonobo_x_get_type (); else add_get_type (); } if(any_method_to_alias(c)) { if( ! no_gnu) { out_printf(out, "/* Short form macros */\n"); out_printf(out, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n"); make_method_gnu_aliases(c); out_printf(out, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n"); } make_method_nongnu_aliases(c); } out_printf (out, "/* a macro for creating a new object of our type */\n"); out_printf (out, "#define GET_NEW ((%s *)g_object_new(%s_get_type(), NULL))\n\n", typebase, funcbase); out_printf (out, "/* a function for creating a new object of our type */\n"); out_printf (out, "#include \n"); out_printf (out, "static %s * GET_NEW_VARG (const char *first, ...)%s;\n" "static %s *\nGET_NEW_VARG (const char *first, ...)\n" "{\n\t%s *ret;\n\tva_list ap;\n" "\tva_start (ap, first);\n" "\tret = (%s *)g_object_new_valist (%s_get_type (), " "first, ap);\n" "\tva_end (ap);\n" "\treturn ret;\n}\n\n", typebase, no_gnu ? "" : " G_GNUC_UNUSED", typebase, typebase, typebase, funcbase); if (need_shutdown) add_shutdown (c); if (need_finalize) add_finalize (c); add_inits(c); if(set_properties > 0) { add_getset_arg(c, TRUE); } if(get_properties > 0) { add_getset_arg(c, FALSE); } for(li = c->nodes; li != NULL; li = li->next) { Node *n = li->data; if(n->type == METHOD_NODE) put_method((Method *)n); } add_bad_hack_to_avoid_unused_warnings(c); } static void print_useful_macros(void) { int major = 0, minor = 0, pl = 0; /* Version stuff */ sscanf (VERSION, "%d.%d.%d", &major, &minor, &pl); out_printf (out, "#define GOB_VERSION_MAJOR %d\n", major); out_printf (out, "#define GOB_VERSION_MINOR %d\n", minor); out_printf (out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl); /* Useful priv macro thingie */ /* FIXME: this should be done the same way that priv is, as a var, * not a define */ out_printf (out, "#define selfp (self->_priv)\n\n"); } static void print_file_comments(void) { time_t curtime; time(&curtime); out_printf(outh, "/* Generated by GOB (v%s)" " (do not edit directly) */\n\n", VERSION); if(outph) out_printf(outph, "/* Generated by GOB (v%s)" " (do not edit directly) */\n\n", VERSION); out_printf(out, "/* Generated by GOB (v%s) on %s" " (do not edit directly) */\n\n", VERSION, ctime(&curtime)); out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n"); } static void print_includes(void) { gboolean found_header; char *p; /* We may need string.h for memset */ if(destructors > 0 && ! g_list_find_custom(include_files, "string.h", (GCompareFunc)strcmp)) { out_printf(out, "#include /* memset() */\n\n"); } p = g_strconcat(filebase, ".h", NULL); found_header = TRUE; if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) { out_printf(out, "#include \"%s.h\"\n\n", filebase); found_header = FALSE; } g_free(p); /* if we are creating a private header see if it was included */ if(outph) { p = g_strconcat(filebase, "-private.h", NULL); if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) { out_printf(out, "#include \"%s-private.h\"\n\n", filebase); if(found_header) error_printf(GOB_WARN, 0, "Implicit private header include " "added to top of\n" "\tsource file, while public " "header is at a custom location, " "you should\n" "\texplicitly include " "the private header below the " "public one."); } g_free(p); } } static void print_header_prefixes(void) { char *p; p = replace_sep(((Class *)class)->otype, '_'); g_strup(p); out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p); if(outph) out_printf(outph, "#ifndef __%s_PRIVATE_H__\n" "#define __%s_PRIVATE_H__\n\n" "#include \"%s.h\"\n\n", p, p, filebase); g_free(p); if( ! no_extern_c) { out_printf(outh, "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif /* __cplusplus */\n\n"); if(outph) out_printf(outph, "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif /* __cplusplus */\n\n"); } } static void print_header_postfixes(void) { if( ! no_extern_c) out_printf(outh, "\n#ifdef __cplusplus\n" "}\n" "#endif /* __cplusplus */\n"); out_printf(outh, "\n#endif\n"); if(outph) { if( ! no_extern_c) out_printf(outph, "\n#ifdef __cplusplus\n" "}\n" "#endif /* __cplusplus */\n"); out_printf(outph, "\n#endif\n"); } } static void print_all_top(void) { GList *li; /* print the AT_CCODE blocks */ for(li = nodes; li != NULL; li = li->next) { Node *node = li->data; if(node->type == CCODE_NODE) { CCode *cc = (CCode *)node; if(cc->cctype == AT_CCODE) print_ccode_block((CCode *)node); } } } static void print_header_top(void) { GList *li; /* mandatory includes */ out_printf(outh, "#include \n"); out_printf(outh, "#include \n"); out_printf(outh, "#include \n"); out_printf(outh, "#include \n"); out_printf(outh, "#include \n"); out_printf(outh, "#include \n\n"); /* print the HT_CCODE blocks */ for (li = nodes; li != NULL; li = li->next) { Node *node = li->data; if(node->type == CCODE_NODE) { CCode *cc = (CCode *)node; if(cc->cctype == HT_CCODE) print_ccode_block((CCode *)node); } } } static void generate_outfiles(void) { GList *li; print_file_comments(); print_all_top(); print_header_top(); print_header_prefixes(); print_useful_macros(); print_includes(); for(li=nodes;li;li=g_list_next(li)) { Node *node = li->data; if(node->type == CCODE_NODE) { CCode *cc = (CCode *)node; if(cc->cctype != HT_CCODE && cc->cctype != AT_CCODE) print_ccode_block((CCode *)node); } else if(node->type == CLASS_NODE) { print_class_block((Class *)node); } else g_assert_not_reached(); } print_header_postfixes(); } static void print_help(void) { fprintf(stderr, "Gob version %s\n\n", VERSION); fprintf(stderr, "gob [options] file.gob\n\n"); fprintf(stderr, "Options:\n" "\t--help,-h,-? Display this help\n" "\t--version Display version\n" "\t--exit-on-warn,-w Exit with an error on warnings\n" "\t--no-exit-on-warn Don't exit on warnings [default]\n" "\t--for-cpp Create C++ files\n" "\t--no-extern-c Never print extern \"C\" into the " "header\n" "\t--no-gnu Never use GNU extentions\n" "\t--no-touch-headers Don't touch headers unless they " "really changed\n" "\t--always-private-header Always create a private header " "file,\n" "\t even if it would be empty " "[default]\n" "\t--ondemand-private-header Create private header only when " "needed\n" "\t--no-private-header Don't create a private header, " "put private\n" "\t structure and protected " "prototypes inside c file\n" "\t--always-private-struct Always create a private pointer " "in\n" "\t the object structure\n" "\t--no-write,-n Don't write output files, just " "check syntax\n" "\t--no-lines Don't print '#line' to output\n" "\t--no-self-alias Don't create self type and macro " "aliases\n" "\t--no-kill-underscores Ignored for compatibility\n"); } static void parse_options(int argc, char *argv[]) { int i; int got_file = FALSE; int no_opts = FALSE; filename = NULL; for(i = 1 ; i < argc; i++) { if(no_opts || argv[i][0] != '-') { /*must be a file*/ if(got_file) { fprintf(stderr, "Specify only one file!\n"); print_help(); exit(1); } filename = argv[i]; got_file = TRUE; } else if(strcmp(argv[i], "--help")==0) { print_help(); exit(0); } else if(strcmp(argv[i], "--version")==0) { fprintf(stderr, "Gob version %s\n", VERSION); exit(0); } else if(strcmp(argv[i], "--exit-on-warn")==0) { exit_on_warn = TRUE; } else if(strcmp(argv[i], "--no-exit-on-warn")==0) { exit_on_warn = FALSE; } else if(strcmp(argv[i], "--for-cpp")==0) { for_cpp = TRUE; } else if(strcmp(argv[i], "--no-touch-headers")==0) { no_touch_headers = TRUE; } else if(strcmp(argv[i], "--ondemand-private-header")==0) { private_header = PRIVATE_HEADER_ONDEMAND; } else if(strcmp(argv[i], "--always-private-header")==0) { private_header = PRIVATE_HEADER_ALWAYS; } else if(strcmp(argv[i], "--no-private-header")==0) { private_header = PRIVATE_HEADER_NEVER; } else if(strcmp(argv[i], "--no-gnu")==0) { no_gnu = TRUE; } else if(strcmp(argv[i], "--no-extern-c")==0) { no_extern_c = TRUE; } else if(strcmp(argv[i], "--no-write")==0) { no_write = TRUE; } else if(strcmp(argv[i], "--no-lines")==0) { no_lines = TRUE; } else if(strcmp(argv[i], "--no-self-alias")==0) { no_self_alias = TRUE; } else if(strcmp(argv[i], "--no-kill-underscores")==0) { /* no op */; } else if(strcmp(argv[i], "--always-private-struct")==0) { always_private_struct = TRUE; } else if(strcmp(argv[i], "--")==0) { /*further arguments are files*/ no_opts = TRUE; } else if(strncmp(argv[i], "--", 2)==0) { /*unknown long option*/ fprintf(stderr, "Unknown option '%s'!\n", argv[i]); print_help(); exit(1); } else { /*by now we know we have a string starting with - which is a short option string*/ char *p; for(p = argv[i] + 1; *p; p++) { switch(*p) { case 'w': exit_on_warn=TRUE; break; case 'n': no_write = TRUE; break; case 'h': case '?': print_help(); exit(0); default: fprintf(stderr, "Unknown option '%c'!\n", *p); print_help(); exit(1); } } } } } /* this is a somewhat ugly hack, but it appears to work */ static void compare_and_move_header(void) { char *hfnew = g_strconcat("#gob#", filebase, ".h#gob#", NULL); char *hf = g_strconcat(filebase, ".h", NULL); struct stat s; if(stat(hf, &s) == 0) { char *s; s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew); if(system(s) == 0) { if(unlink(hfnew) != 0) error_printf(GOB_ERROR, 0, "Can't remove new header file"); g_free(hfnew); g_free(hf); g_free(s); return; } g_free(s); if(unlink(hf) != 0) error_printf(GOB_ERROR, 0, "Can't remove old header file"); } if(rename(hfnew, hf) != 0) error_printf(GOB_ERROR, 0, "Can't rename new header file"); g_free(hfnew); g_free(hf); } int main(int argc, char *argv[]) { parse_options(argc, argv); if(filename) { yyin = fopen(filename, "r"); if(!yyin) { fprintf(stderr, "Error: can't open file '%s'\n", filename); exit(1); } } else filename = "stdin"; /* This is where parsing is done */ /*yydebug = 1;*/ if(yyparse() != 0) g_error("Parsing errors, quitting"); if( ! class) error_print(GOB_ERROR, 0, " no class defined"); exit_on_error = FALSE; signals = count_signals ((Class *)class); set_properties = count_set_properties ((Class *)class) + count_set_arguments ((Class *)class); get_properties = count_get_properties ((Class *)class) + count_get_arguments ((Class *)class); overrides = count_overrides ((Class *)class); privates = count_privates ((Class *)class); protecteds = count_protecteds ((Class *)class); unreftors = count_unreftors ((Class *)class); destructors = count_destructors ((Class *)class); initializers = count_initializers ((Class *)class); overrode_get_type = find_get_type ((Class *)class); make_bases (); make_inits ((Class *)class); if(unreftors > 0) { need_shutdown = TRUE; find_shutdown ((Class *)class); } if (destructors > 0 || privates > 0) { need_finalize = TRUE; find_finalize ((Class *)class); } check_bad_symbols ((Class *)class); check_duplicate_symbols ((Class *)class); check_duplicate_overrides ((Class *)class); check_duplicate_signals_args ((Class *)class); check_public_new ((Class *)class); check_vararg ((Class *)class); check_firstarg ((Class *)class); check_nonvoidempty ((Class *)class); check_signal_args ((Class *)class); check_property_types ((Class *)class); check_argument_types ((Class *)class); check_func_arg_checks ((Class *)class); exit_on_error = TRUE; if (got_error) exit (1); any_special = setup_special_array ((Class *)class, special_array); open_files (); generate_outfiles (); if (devnull) { fclose (devnull); } else { fclose (out); fclose (outh); if (outph) fclose (outph); } if (no_touch_headers && ! no_write) compare_and_move_header (); return 0; }