/* GOB C Preprocessor * Copyright (C) 1999 the Free Software Foundation. * * 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 #if 0 #include #endif #include #include #include #include #include #include "tree.h" #include "parse.h" #include "out.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; char *filebase; static char *funcbase; static char *pfuncbase; static char *macrobase; static char *macrois; static char *macrotype; static char *typebase; static char *ptypebase; static int signals = 0; /* number of signals */ static int arguments = 0; /* number of named arguments */ 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 gboolean made_aliases = FALSE; /* if we made any shorthand aliases and need the REALLY UGLY HACK to avoid warnings */ FILE *out = NULL; FILE *outh = NULL; FILE *outph = 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; gboolean always_private_header = FALSE; gboolean no_private_header = FALSE; void print_error(int is_warn, char *error,int line) { char *w; if(is_warn) w = "Warning:"; else { w = "Error:"; got_error = TRUE; } if(line>0) fprintf(stderr,"%s:%d: %s %s\n",filename,line,w,error); else fprintf(stderr,"%s: %s %s\n",filename,w,error); if((!is_warn || exit_on_warn) && exit_on_error) exit(1); } static char * remove_sep(char *base) { char *p; char *s = g_strdup(base); while((p=strchr(s,':'))) strcpy(p,p+1); return s; } static char * replace_sep(char *base, char r) { char *p; char *s = g_strdup(base); while((p=strchr(s,':'))) *p = r; if(*s == r) { p = g_strdup(s+1); g_free(s); return p; } return s; } /*separate the namespace part and then replace rest of separators with r*/ static void separns_replace_sep(char *base, char **ns, char **name, char r) { char *p; char *s = g_strdup(base); *ns = NULL; if((p=strchr(s,':')) && p!=s) { *p = '\0'; *ns = g_strdup(s); p = g_strdup(p+1); g_free(s); s = p; } while((p=strchr(s,':'))) *p = r; if(*s == r) { *name = g_strdup(s+1); g_free(s); } else *name = s; } /* make a macro with some prefix before the name but after namespace */ static char * make_pre_macro(char *base, char *pre) { char *s1,*s2; char *s; separns_replace_sep(base,&s1,&s2,'_'); if(s1) s = g_strconcat(s1,"_",pre,"_",s2,NULL); else s = g_strconcat(pre,"_",s2,NULL); g_strup(s); g_free(s1); g_free(s2); return s; } 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"); macrotype = make_pre_macro(((Class *)class)->otype,"TYPE"); typebase = remove_sep(((Class *)class)->otype); ptypebase = remove_sep(((Class *)class)->ptype); } static char * get_type(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) { 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,' '); for(i=0;i<(t->stars+extra);i++) g_string_append_c(gs,'*'); s = gs->str; g_string_free(gs,FALSE); return s; } static void print_type(FILE *fp, 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, char *typeprefix, char *nameprefix, char *namepostfix,char *postfix, Method *m, gboolean no_funcbase) { GList *li; out_printf(fp,"%s",typeprefix); print_type(fp,m->mtype,TRUE); if(no_funcbase) out_printf(fp,"%s%s%s(", nameprefix,m->id,namepostfix); else out_printf(fp,"%s%s_%s%s(", nameprefix,funcbase,m->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, ",arg->name, arg->atype->postfix? arg->atype->postfix:""); else out_printf(fp,"%s%s",arg->name, arg->atype->postfix? arg->atype->postfix:""); } if(m->vararg) out_printf(fp,", ..."); } else { out_printf(fp,"void"); } out_printf(fp,")%s",postfix); } static void make_method_gnu_aliases(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; /* in C++ mode don't alias new */ if(for_cpp && strcmp(m->id, "new")==0) continue; out_printf(out, "static const typeof(&%s_%s) %s " "__attribute__ ((__unused__)) " "= %s_%s;\n", funcbase, m->id, m->id, funcbase, m->id); out_printf(out, "#define %s(args...) " "%s_%s(##args)\n", m->id, funcbase, m->id); } } } static void make_method_nongnu_aliases(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; /* in C++ mode don't alias new */ if(for_cpp && strcmp(m->id,"new")==0) continue; print_method(out,"static ","(* ",") ","",m,TRUE); out_printf(out," = %s_%s;\n",funcbase,m->id); 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#ifndef __GNUC__\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); 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))%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__ */\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(Method *m) { if(m->method != SIGNAL_LAST_METHOD && m->method != SIGNAL_FIRST_METHOD && m->method != VIRTUAL_METHOD) return; print_method(outh,"\t","(* ",") ",";\n",m,TRUE); } static void put_pub_method(Method *m) { if(m->scope != PUBLIC_SCOPE) return; print_method(outh,"","\t","\t",";\n",m,FALSE); } static void put_prot_method(Method *m) { if(m->scope != PROTECTED_SCOPE) return; if(outph) print_method(outph,"","\t","\t",";\n",m,FALSE); else print_method(out,"","\t","\t",";\n",m,FALSE); } 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); } if(m->scope == PRIVATE_SCOPE || m->method == INIT_METHOD || m->method == CLASS_INIT_METHOD || (m->method == OVERRIDE_METHOD && m->cbuf)) print_method(out,"static ",""," ", no_gnu?";\n":" ___NO_UNUSED_WARNING;\n" ,m,FALSE); } 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 = new_type(1,tn,NULL); node = new_funcarg((Type *)type,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) print_error(FALSE,"init defined more then once",m->line_no); got_init = TRUE; } else if(m->method == CLASS_INIT_METHOD) { if(got_class_init) print_error(FALSE,"class_init defined more then once",m->line_no); got_class_init = TRUE; } } } if(!got_class_init) { node = new_method(NO_SCOPE, CLASS_INIT_METHOD, (Type *)new_type(0,g_strdup("void"),NULL), NULL,NULL,g_strdup("class_init"), make_func_arg(cl->otype,TRUE,g_strdup("c")), NULL, NULL,0,0,FALSE); cl->nodes = g_list_prepend(cl->nodes,node); } if(!got_init) { node = new_method(NO_SCOPE, INIT_METHOD, (Type *)new_type(0,g_strdup("void"),NULL), NULL,NULL,g_strdup("init"), make_func_arg(cl->otype,FALSE,g_strdup("o")), NULL, NULL,0,0,FALSE); cl->nodes = g_list_prepend(cl->nodes,node); } } static void make_finalize(Class *cl) { int got_finalize = 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 == OVERRIDE_METHOD && strcmp(m->id,"finalize")==0) { if(strcmp(m->otype,"Gtk:Object")==0) { got_finalize = TRUE; break; } else { print_error(FALSE,"finalize method override " "of class other then Gtk:Object", m->line_no); } } } } if(!got_finalize) { node = new_method(NO_SCOPE, OVERRIDE_METHOD, (Type *)new_type(0,g_strdup("void"),NULL), g_strdup("Gtk:Object"), NULL,g_strdup("finalize"), make_func_arg("Gtk:Object",FALSE,g_strdup("o")), NULL, g_strdup("PARENT_HANDLER (o);\n"), 0,0,FALSE); cl->nodes = g_list_append(cl->nodes,node); overrides++; } } /* here we will find out how inconsistent gtk really is :) */ /* the commented out types mean that these types don't actually exist. so we "emulate them" with an equivalent */ const struct { gboolean simple; char *gtkname; char *typename; } our_gtk_type_table[] = { { TRUE, "NONE", "void " }, { TRUE, "CHAR", "gchar " }, { TRUE, "UCHAR", "guchar " }, { TRUE, "BOOL", "gboolean " }, { TRUE, "INT", "gint " }, { TRUE, "UINT", "guint " }, { TRUE, "LONG", "glong " }, { TRUE, "ULONG", "gulong " }, { TRUE, "FLOAT", "gfloat " }, { TRUE, "DOUBLE", "gdouble " }, { TRUE, "STRING", /*"GtkString"*/"gchar *" }, { TRUE, "ENUM", /*"GtkEnum"*/"gint " }, { TRUE, "FLAGS", /*"GtkFlags"*/"guint " }, { TRUE, "BOXED", /*"GtkBoxed"*/"gpointer " }, { TRUE, "POINTER", "gpointer " }, { TRUE, "OBJECT", "GtkObject *" }, { FALSE, "SIGNAL", /*"GtkSignal"*/"___twopointertype " }, { FALSE, "ARGS", /*"GtkArgs"*/"___twopointertype " }, { FALSE, "CALLBACK", /*"GtkCallback"*/"___threepointertype " }, { FALSE, "C_CALLBACK", /*"GtkCCallback"*/"___twopointertype " }, { FALSE, "FOREIGN", /*"GtkForeign"*/"___twopointertype " }, { FALSE, NULL, NULL } }; static const char * get_cast(char *type, gboolean simple_only) { int i; for(i=0;our_gtk_type_table[i].gtkname;i++) { if(strcmp(our_gtk_type_table[i].gtkname,type)==0) { if(simple_only && !our_gtk_type_table[i].simple) return NULL; return our_gtk_type_table[i].typename; } } return NULL; } /* 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; i++,li=g_list_next(li)) { if(!for_cpp) out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])", (char *)li->data,i); else { out_printf(out, ",\n\t\t(%s)" "GTK_VALUE_%s(args[%d])", get_cast(li->data,FALSE), (char *)li->data,i); } } } out_printf(out, ",\n\t\tfunc_data);\n}\n\n"); } static void add_signal_prots(Method *m) { GList *li; static int sig = 1; char *s; Method *mm; if(m->method != SIGNAL_LAST_METHOD && m->method != SIGNAL_FIRST_METHOD) return; if(!marsh) marsh = g_hash_table_new(NULL,NULL); if(strcmp(m->gtktypes->data,"NONE")==0 && strcmp(m->gtktypes->next->data,"NONE")==0) return; /* if we already did a signal prototype just use that */ mm = find_same_type_signal(m); if(mm) { s = g_hash_table_lookup(marsh,mm); g_hash_table_insert(marsh,m,s); return; } 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); for(li=m->gtktypes->next;li;li=g_list_next(li)) out_printf(out,"%s, ",get_cast(li->data,FALSE)); out_printf(out,"gpointer);\n"); out_printf(out,"\nstatic void\n" "___marshal_%s (GtkObject * object,\n" "\tGtkSignalFunc func,\n" "\tgpointer func_data,\n" "\tGtkArg * args)\n" "{\n",s); if(strcmp(m->gtktypes->data,"NONE")==0) { out_printf(out, "\t%s rfunc;\n\n" "\trfunc = (%s)func;\n\n" "\t(*rfunc)((%s *)object",s,s,typebase); } else { out_printf(out, "\t%s rfunc;\n\t",s); print_type(out,m->mtype,TRUE); out_printf(out, " *retval;\n\n" "\trfunc = (%s)func;\n\n" "\tretval = GTK_RETLOC_%s(args[%d]);\n\n" "\t*retval = (*rfunc)((%s *)object", s,(char *)m->gtktypes->data, g_list_length(m->gtktypes)-1,typebase); } print_signal_marsal_args(m); } 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(arguments>0) { out_printf(out,"enum {\n\tARG_0,\n"); for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; if(n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; char *s = g_strdup(a->name); g_strup(s); out_printf(out,"\tARG_%s,\n",s); g_free(s); } } out_printf(out, "};\n\n"); } if(signals>0) out_printf(out, "static guint object_signals[LAST_SIGNAL] = {0};\n\n"); out_printf(out, "static %sClass *parent_class = NULL;\n\n",ptypebase); } static void add_get_type(void) { out_printf(out, "guint\n" "%s_get_type (void)\n" "{\n" "\tstatic guint type = 0;\n\n" "\tif (!type) {\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 = gtk_type_unique (%s_get_type(), &info);\n" "\t}\n\n" "\treturn type;\n" "}\n\n", funcbase,typebase,typebase,typebase, funcbase,funcbase,pfuncbase); } static void add_overrides(Class *c, char *oname, gboolean did_gtk_obj) { GList *li; GHashTable *done; char *s; done = g_hash_table_new(g_str_hash,g_str_equal); if(did_gtk_obj) { s = g_strdup("GtkObject"); /* This was already done */ g_hash_table_insert(done,s,s); } for(li=c->nodes;li;li=g_list_next(li)) { 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 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; char *sig; int is_none; int 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("gtk_signal_default_marshaller"); is_none = (strcmp(m->gtktypes->next->data,"NONE")==0); sig = g_strdup(m->id); g_strup(sig); out_printf(out,"\tobject_signals[%s_SIGNAL] =\n" "\t\tgtk_signal_new (\"%s\",\n" "\t\t\tGTK_RUN_%s,\n" "\t\t\tgtk_object_class->type,\n" "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n" "\t\t\t%s,\n" "\t\t\tGTK_TYPE_%s, %d", sig,m->id, last?"LAST":"FIRST", typebase,m->id,mar,(char *)m->gtktypes->data, is_none?0:g_list_length(m->gtktypes->next)); g_free(mar); g_free(sig); if(!is_none) { GList *l; for(l=m->gtktypes->next;l;l=g_list_next(l)) out_printf(out,",\n\t\t\tGTK_TYPE_%s", (char *)l->data); } out_printf(out,");\n"); } out_printf(out,"\tgtk_object_class_add_signals (gtk_object_class,\n" "\t\tobject_signals, LAST_SIGNAL);\n\n"); } static void set_def_handlers(Class *c, char *oname) { GList *li; 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->method == OVERRIDE_METHOD) { char *s; s = replace_sep(m->otype,'_'); g_strdown(s); if(m->cbuf) out_printf(out,"\t%s_class->%s = %s_%s;\n", s,m->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); } } } static void make_arguments(Class *c) { GList *li; char *argflags[] = { "CONSTRUCT", "CONSTRUCT_ONLY", "CHILD_ARG", "MASK", NULL }; out_printf(out,"\n"); for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; Argument *a; GString *flags; GList *l; char *s; if(n->type != ARGUMENT_NODE) continue; a = (Argument *)n; if(a->get && a->set) flags = g_string_new("GTK_ARG_READWRITE"); else if(a->get) flags = g_string_new("GTK_ARG_READABLE"); else flags = g_string_new("GTK_ARG_WRITABLE"); for(l=a->flags;l;l=g_list_next(l)) { char *flag = l->data; int i; if(strcmp(flag,"READWRITE")==0 || strcmp(flag,"READABLE")==0 || strcmp(flag,"WRITABLE")==0) { print_error(TRUE,"READWRITE, READABLE and " "WRITABLE argument flags are " "set automatically",a->line_no); 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]) { char *s; s = g_strdup_printf("Unknown flag '%s' used, " "perhaps it was misspelled", flag); print_error(TRUE,s,a->line_no); g_free(s); } g_string_sprintfa(flags, " | GTK_ARG_%s",flag); } s = g_strdup(a->name); g_strup(s); out_printf(out,"\tgtk_object_add_arg_type(\"%s::%s\",\n" "\t\tGTK_TYPE_%s,\n" "\t\t%s,\n" "\t\tARG_%s);\n", typebase,a->name,a->gtktype,flags->str,s); g_free(s); g_string_free(flags,TRUE); } out_printf(out, "\n\tgtk_object_class->set_arg = ___object_set_arg;\n" "\tgtk_object_class->get_arg = ___object_get_arg;\n"); } static void add_inits(Class *c) { GList *li; for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; Method *m; 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); if(m->line_no>0) out_addline_outfile(out); out_printf(out,"{\n"); if(privates>0) { out_printf(out,"\t%s->_priv = " "g_new0 (%sPrivate,1);\n", ((FuncArg *)m->args->data)->name, typebase); } } else if(m->method == CLASS_INIT_METHOD) { if(m->line_no>0) out_addline_infile(out,m->line_no); print_method(out,"static ","\n"," ","\n",m,FALSE); if(m->line_no>0) out_addline_outfile(out); out_printf(out,"{\n"); if(signals>0 || arguments>0) out_printf(out, "\tGtkObjectClass *" "gtk_object_class = " "(GtkObjectClass*) %s;\n", ((FuncArg *)m->args->data)->name); if(overrides>0) add_overrides(c, ((FuncArg *)m->args->data)->name, (signals>0 || arguments>0)); out_printf(out,"\n\tparent_class = "); if(for_cpp) out_printf(out,"(%sClass *)",ptypebase); out_printf(out,"gtk_type_class (%s_get_type ());\n", pfuncbase); if(signals>0) add_signals(c); set_def_handlers(c, ((FuncArg *)m->args->data)->name); if(arguments>0) make_arguments(c); } 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"); } else { out_printf(out,"return;\n"); } out_printf(out,"}\n"); } } static void add_getset_arg(Class *c, int is_set) { GList *li; out_printf(out,"\nstatic void\n" "___object_%s_arg (GtkObject *object,\n" "\tGtkArg *arg,\n" "\tguint arg_id)\n" "{\n" "\t%s *self;\n\n" "\tself = %s (object);\n\n" "\tswitch (arg_id) {\n", is_set?"set":"get",typebase,macrobase); for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; Argument *a; char *s; char *cbuf; int line_no; if(n->type != ARGUMENT_NODE) continue; a = (Argument *)n; if(is_set) { cbuf = a->set; line_no = a->set_line; } else { cbuf = a->get; line_no = a->get_line; } if(!cbuf) continue; s = g_strdup(a->name); g_strup(s); out_printf(out,"\tcase ARG_%s:\n" "#define ARG (GTK_VALUE_%s(*arg))\n" "\t\t{\n", s,a->gtktype); g_free(s); out_addline_infile(out,line_no); out_printf(out,"%s\n",cbuf); out_addline_outfile(out); out_printf(out,"\t\t}\n\t\tbreak;\n" "#undef ARG\n"); } out_printf(out,"\tdefault:\n\t\tbreak;\n\t}\n}\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->stars == 0); for(li=fa->checks;li;li=g_list_next(li)) { 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); } /* put in code if it's needed */ static void put_in_gen_code(Method *m) { /* now we only have the freeing of the private structure */ if(privates>0 && m->method == OVERRIDE_METHOD && strcmp(m->id,"finalize")==0) { out_printf(out,"\tg_free (%s (%s)->_priv);\n" "\t%s (%s)->_priv = NULL;\n", macrobase, ((FuncArg *)m->args->data)->name, macrobase, ((FuncArg *)m->args->data)->name); } } static void print_method_body(Method *m, int pre) { out_printf(out,"{\n"); if(pre) print_preconditions(m); put_in_gen_code(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); } out_printf(out,"}\n"); if(m->cbuf) out_addline_outfile(out); } static void put_signal_args(Method *m) { GList *li; GList *ali; for(ali = m->gtktypes->next,li=m->args->next; li && ali; li=li->next, ali=ali->next) { FuncArg *fa = li->data; const char *cast = get_cast(ali->data,FALSE); /* we should have already proved before that the we know all the types */ g_assert(cast); out_printf(out,",\n\t\t(%s)%s",cast, fa->name); } } static char * get_arg_names_for_macro(Method *m) { char *p; GList *li; GString *gs = g_string_new(""); 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; gboolean is_void; is_void = (strcmp(m->mtype->name,"void")==0 && m->mtype->stars == 0); out_printf(out,"\n"); 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); else /* PUBLIC, PROTECTED */ print_method(out,"","\n"," ","\n",m,FALSE); print_method_body(m,TRUE); 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); else print_method(out,"","\n"," ","\n",m,FALSE); 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->stars==0) { print_preconditions(m); if(((FuncArg *)m->args->data)->name) out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n" "\t\tobject_signals[%s_SIGNAL]", ((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;\n"); print_preconditions(m); out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n" "\t\tobject_signals[%s_SIGNAL]", ((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); print_method_body(m,FALSE); 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); else print_method(out,"","\n"," ","\n",m,FALSE); out_addline_outfile(out); out_printf(out,"{\n" "\t%sClass *klass;\n",typebase); print_preconditions(m); out_printf(out,"\tklass = %s_CLASS(GTK_OBJECT(%s)->klass);\n\n" "\tif(klass->%s)\n", macrobase, ((FuncArg *)m->args->data)->name, m->id); if(strcmp(m->mtype->name,"void")==0 && m->mtype->stars==0) { 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); out_printf(out,")(%s);\n}\n", m->onerror?m->onerror:"0"); } 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); print_method_body(m,FALSE); break; case OVERRIDE_METHOD: if(!m->cbuf) break; if(m->line_no>0) out_addline_infile(out,m->line_no); print_method(out,"static ","\n"," ","\n",m,FALSE); 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); out_printf(out,"#undef PARENT_HANDLER\n"); break; default: break; } } static void check_duplicate(Class *c, Node *node, char *id, int line_no) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; char *nid; int nline_no; char *s; if(n->type == METHOD_NODE) { Method *m = (Method *)n; nid = m->id; nline_no = m->line_no; } else if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; nid = v->id; nline_no = v->line_no; } else continue; if(n==node || line_no>=nline_no || strcmp(nid,id)!=0 || n->type != node->type) continue; s = g_strdup_printf("symbol '%s' redefined, " "first defined on line %d", id,line_no); print_error(FALSE,s,nline_no); } } static void check_duplicate_symbols(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; check_duplicate(c,n,m->id,m->line_no); } else if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; check_duplicate(c,n,v->id,v->line_no); } } } static void check_bad_symbols(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if((m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD || m->method == VIRTUAL_METHOD) && strcmp(m->id,"__parent__")==0) { char *s; s = g_strdup_printf("'%s' not allowed as an " "identifier of signal " "or virtual methods", m->id); print_error(FALSE,s,m->line_no); g_free(s); } if(m->method != INIT_METHOD && m->method != CLASS_INIT_METHOD && (strcmp(m->id,"init")==0 || strcmp(m->id,"class_init")==0)) { print_error(FALSE,"init, or class_init not " "allowed as an " "identifier of non-" "constructor methods",m->line_no); } } else if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; if(strcmp(v->id,"_priv")==0 || strcmp(v->id,"__parent__")==0) { char *s; s = g_strdup_printf("'%s' not allowed as a " "data member name",v->id); print_error(FALSE,s,v->line_no); g_free(s); } } } } static void check_duplicate_named(Class *c,Node *node,char *id, int line_no) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; char *nid; int nline_no; char *s; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD) { nid = m->id; nline_no = m->line_no; } else continue; } else if(n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; nid = a->name; nline_no = a->line_no; } else continue; if(n==node || line_no>=nline_no || strcmp(nid,id)!=0) continue; s = g_strdup_printf("named symbol (argument or signal) '%s' " "redefined, first defined on line %d", id,line_no); print_error(FALSE,s,nline_no); } } static void check_duplicate_signals_args(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD) check_duplicate_named(c,n,m->id,m->line_no); } else if(n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; check_duplicate_named(c,n,a->name,a->line_no); } } } static void check_public_new(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if((strcmp(m->id,"new")==0) && (m->method != REGULAR_METHOD || m->scope != PUBLIC_SCOPE)) print_error(TRUE, "'new' should be a regular\n" "public method", m->line_no); } } } static void check_vararg(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(!m->vararg) continue; if(m->method == OVERRIDE_METHOD || m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD || m->method == VIRTUAL_METHOD) { print_error(FALSE, "signals, overrides and virtuals, " "can't have variable argument " "lists", m->line_no); } } } } static void check_firstarg(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->args) continue; if(m->method == OVERRIDE_METHOD || m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD || m->method == VIRTUAL_METHOD) { print_error(FALSE, "signals, overrides and virtuals, " "can't have no arguments", m->line_no); } } } } static void check_nonvoidempty(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method != REGULAR_METHOD) continue; if(!(strcmp(m->mtype->name,"void")==0 && m->mtype->stars == 0) && !m->cbuf) { print_error(TRUE, "non-void empty method found, " "regular non-void function should " "not be empty.", m->line_no); /* add a body here, so that the user will also get a warning from gcc, and so that it will at least point him to the prototype of the function in the .gob file */ m->cbuf = g_strdup("/*empty*/"); m->ccode_line = m->line_no; } } } } static void check_signal_args(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; GList *l; if(m->method != SIGNAL_LAST_METHOD && m->method != SIGNAL_FIRST_METHOD) continue; for(l=m->gtktypes;l;l=l->next) { char *s; if(get_cast(l->data,FALSE)) continue; s = g_strdup_printf("Unknown GTK+ type '%s' " "among signal types", (char *)l->data); print_error(FALSE, s, m->line_no); g_free(s); } } } } static void check_argument_types(Class *c) { GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == ARGUMENT_NODE) { Argument *a = (Argument *)n; char *s; if(get_cast(a->gtktype,FALSE)) continue; s = g_strdup_printf("Unknown GTK+ type '%s' " "as argument type", a->gtktype); /* this could perhaps be a warning, but can there really be a type beyond the fundementals? */ print_error(FALSE, s, a->line_no); g_free(s); } } } static int count_signals(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == SIGNAL_LAST_METHOD || m->method == SIGNAL_FIRST_METHOD) num++; } } return num; } static int count_arguments(Class *c) { int num = 0; GList *li; for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; if(n->type == ARGUMENT_NODE) num ++; } return num; } static int count_overrides(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->method == OVERRIDE_METHOD) num++; } } return num; } static int count_privates(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == VARIABLE_NODE) { Variable *v = (Variable *)n; if(v->scope == PRIVATE_SCOPE) num++; } } return num; } static int count_protecteds(Class *c) { int num = 0; GList *l; for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { Method *m = (Method *)n; if(m->scope == PROTECTED_SCOPE) num++; } } return num; } 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 || always_private_header) && !no_private_header) outfileph = g_strconcat(filebase,"-private.h",NULL); else outfileph = NULL; out = fopen(outfile,"w"); if(!out) { g_error("Cannot open outfile: %s",outfile); } outh = fopen(outfileh,"w"); if(!outh) { g_error("Cannot open outfile: %s",outfileh); } if(outfileph) { outph = fopen(outfileph,"w"); if(!outph) { g_error("Cannot open outfile: %s",outfileh); } } } static void put_argument_nongnu_wrappers(Class *c) { GList *li; if(arguments<0) return; for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; Argument *a = (Argument *)n; char *s; char *cast; if(n->type != ARGUMENT_NODE) continue; s = g_strdup(a->name); g_strup(s); if(a->atype) cast = get_type(a->atype,TRUE); else cast = g_strdup(get_cast(a->gtktype,TRUE)); if(cast) { if(a->set) out_printf(outh, "#define %s_ARG_%s(arg) \t" "\"%s\",(%s)(arg)\n", macrobase, s, a->name, cast); if(a->get) out_printf(outh, "#define %s_GET_ARG_%s(arg)\t" "\"%s\",(%s*)(arg)\n", macrobase, s, a->name, cast); } else { if(a->set) out_printf(outh, "#define %s_ARG_%s(arg) \t" "\"%s\",(arg)\n", macrobase, s, a->name); if(a->get) out_printf(outh, "#define %s_GET_ARG_%s(arg)\t" "\"%s\",(arg)\n", macrobase, s, a->name); } g_free(cast); g_free(s); } } static void put_argument_gnu_wrappers(Class *c) { GList *li; if(arguments<0) return; for(li=c->nodes;li;li=g_list_next(li)) { Node *n = li->data; Argument *a = (Argument *)n; char *s; char *cast; if(n->type != ARGUMENT_NODE) continue; s = g_strdup(a->name); g_strup(s); if(a->atype) cast = get_type(a->atype,TRUE); else cast = g_strdup(get_cast(a->gtktype,TRUE)); if(cast) { if(a->set) out_printf(outh, "#define %s_ARG_%s(arg) \t" "\"%s\",({%sz = (arg); z;})\n", macrobase, s, a->name, cast); if(a->get) out_printf(outh, "#define %s_GET_ARG_%s(arg)\t" "\"%s\",({%s*z = (arg); z;})\n", macrobase, s, a->name, cast); } else { if(a->set) out_printf(outh, "#define %s_ARG_%s(arg) \t" "\"%s\",(arg)\n", macrobase, s, a->name); if(a->get) out_printf(outh, "#define %s_GET_ARG_%s(arg)\t" "\"%s\",(arg)\n", macrobase, s, a->name); } g_free(cast); g_free(s); } } static void generate_outfiles(void) { char *p; GList *li; time_t curtime; gboolean found_header; 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)); { int major=0,minor=0,pl=0; 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); } p = replace_sep(((Class *)class)->otype,'_'); g_strup(p); out_printf(outh,"#ifndef __%s_H__\n#define __%s_H__\n\n" "#include \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(!for_cpp) { 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"); } 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) print_error(TRUE, "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.", 0); } g_free(p); } for(li=nodes;li;li=g_list_next(li)) { Node *node = li->data; if(node->type == CCODE_NODE) { CCode *cc = (CCode *)node; FILE *fp; if(cc->header) { fp = outh; out_printf(fp,"\n"); } else { fp = out; out_printf(fp,"\n"); out_addline_infile(fp,cc->line_no); } out_printf(fp,"%s\n",cc->cbuf); if(!cc->header) out_addline_outfile(fp); } else if(node->type == CLASS_NODE) { Class *c = (Class *)class; GList *l; out_printf(out,"/* utility types we may need */\n"); out_printf(out,"typedef struct { " "gpointer a; gpointer b; " "} ___twopointertype;\n"); out_printf(out,"typedef struct { " "gpointer a; gpointer b; " "gpointer c; " "} ___threepointertype;\n"); out_printf(outh,"\n#define %s\t" "(%s_get_type())\n", macrotype,funcbase); out_printf(outh,"#define %s(obj)\t" "GTK_CHECK_CAST((obj),%s_get_type(),%s)\n", macrobase,funcbase,typebase); out_printf(outh,"#define %s_CLASS(klass)\t" "GTK_CHECK_CLASS_CAST((klass),%s_get_type(),%sClass)\n", macrobase,funcbase,typebase); out_printf(outh,"#define %s(obj)\t" "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n", macrois,funcbase); /* argument wrapping macros */ if(arguments>0 && !no_gnu) { out_printf(outh,"\n#ifdef __GNUC__\n"); put_argument_gnu_wrappers(c); out_printf(outh,"#else /* __GNUC__ */\n"); put_argument_nongnu_wrappers(c); out_printf(outh,"#endif /* __GNUC__ */\n\n"); } else if(arguments>0 && no_gnu) { put_argument_nongnu_wrappers(c); } if(privates>0) out_printf(outh,"\ntypedef struct _%sPrivate %sPrivate;\n",typebase,typebase); out_printf(outh,"\ntypedef struct _%s %s;\n",typebase,typebase); out_printf(outh,"struct _%s {\n\t%s __parent__;\n", typebase,ptypebase); for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; Variable *v = (Variable *)n; if(n->type == VARIABLE_NODE && v->scope == PUBLIC_SCOPE) put_variable((Variable *)n,outh); } /* put protecteds always AFTER publics */ for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; Variable *v = (Variable *)n; if(n->type == VARIABLE_NODE && v->scope == PROTECTED_SCOPE) put_variable((Variable *)n,outh); } if(privates>0) 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) outfp = outph; else outfp = out; out_printf(outfp,"struct _%sPrivate {\n", typebase); for(l=c->nodes;l;l=l->next) { Node *n = l->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,"\ntypedef struct _%sClass %sClass;\n", typebase,typebase); out_printf(outh, "struct _%sClass {\n\t%sClass __parent__;\n", typebase,ptypebase); for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) put_vs_method((Method *)n); } out_printf(outh,"};\n\n"); out_printf(outh,"guint\t%s_get_type\t(void);\n",funcbase); out_printf(out,"/* here are local prototypes */\n"); if(!no_gnu) { out_printf(out,"#ifdef __GNUC__\n" "#define ___NO_UNUSED_WARNING " "__attribute__ ((__unused__))\n" "#else /* __GNUC__ */\n" "#define ___NO_UNUSED_WARNING\n" "#endif /* __GNUC__ */\n"); } if(arguments>0) { out_printf(out,"static void ___object_set_arg " "(GtkObject *object, GtkArg *arg, " "guint arg_id);\n" "static void ___object_get_arg " "(GtkObject *object, GtkArg *arg, " "guint arg_id);\n"); } for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { put_pub_method((Method *)n); put_prot_method((Method *)n); put_priv_method_prot((Method *)n); } } if(signals>0) { for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) add_signal_prots((Method *)n); } } if(!no_gnu) out_printf(out,"#undef ___NO_UNUSED_WARNING\n"); add_enums(c); add_get_type(); if(no_gnu) make_method_nongnu_aliases(c); else { out_printf(out,"\n#ifdef __GNUC__\n"); make_method_gnu_aliases(c); out_printf(out,"#else /* __GNUC__ */\n"); make_method_nongnu_aliases(c); out_printf(out,"#endif /* __GNUC__ */\n\n"); } out_printf(out,"#define GET_NEW (gtk_type_new(%s_get_type()))\n", funcbase); add_inits(c); if(arguments>0) { add_getset_arg(c, TRUE); add_getset_arg(c, FALSE); } for(l=c->nodes;l;l=g_list_next(l)) { Node *n = l->data; if(n->type == METHOD_NODE) { put_method((Method *)n); } } out_printf(out,"#undef GET_NEW\n"); add_bad_hack_to_avoid_unused_warnings(c); } else g_assert_not_reached(); } if(!for_cpp) out_printf(outh,"\n#ifdef __cplusplus\n" "}\n" "#endif /* __cplusplus */\n"); out_printf(outh,"\n#endif"); if(outph) { if(!for_cpp) out_printf(outph,"\n#ifdef __cplusplus\n" "}\n" "#endif /* __cplusplus */\n"); out_printf(outph,"\n#endif"); } } #if 0 static void usage(poptContext optCon, int exitcode, char *error, char *addl) { poptPrintUsage(optCon, stderr, 0); if (error) fprintf(stderr, "%s: %s", error, addl); exit(exitcode); } #endif static void print_help(void) { fprintf(stderr,"Gob version %s\n\n",VERSION); 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-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\n" "\t--no-private-header Don't create a private header, " "put private\n" "\t structure and protected " "prototypes inside c file\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 /dev/null",hf,hfnew); if(system(s)==0) { if(unlink(hfnew)!=0) print_error(FALSE,"Can't remove new header file",0); g_free(hfnew); g_free(hf); g_free(s); return; } g_free(s); if(unlink(hf)!=0) print_error(FALSE,"Can't remove old header file",0); } if(rename(hfnew,hf)!=0) print_error(FALSE,"Can't rename new header file",0); g_free(hfnew); g_free(hf); } int main(int argc, char *argv[]) { #if 0 int c; poptContext optCon; struct poptOption optionsTable[] = { { "exit-on-warn", 'w', 0, &exit_on_warn, 0, "exit on warnings" }, POPT_AUTOHELP { NULL, 0, 0, NULL, 0 } }; optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); poptSetOtherOptionHelp(optCon, "[OPTIONS]* [filename]"); while ((c = poptGetNextOpt(optCon)) >= 0) ; filename = poptGetArg(optCon); if(!(poptPeekArg(optCon) == NULL)) usage(optCon, 1, "Specify only one file", ".e.g., filename.gob"); if (c < -1) { /* an error occurred during option processing */ fprintf(stderr, "%s: %s\n", poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(c)); return 1; } #endif 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"; /*yydebug = 1;*/ if(yyparse()!=0) g_error("Parsing errors, quitting"); if(!class) print_error(FALSE," no class defined",0); exit_on_error = FALSE; signals = count_signals((Class *)class); arguments = count_arguments((Class *)class); overrides = count_overrides((Class *)class); privates = count_privates((Class *)class); protecteds = count_protecteds((Class *)class); make_bases(); make_inits((Class *)class); if(privates>0) make_finalize((Class *)class); check_bad_symbols((Class *)class); check_duplicate_symbols((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_argument_types((Class *)class); exit_on_error = TRUE; if(got_error) exit(1); open_files(); generate_outfiles(); fclose(out); fclose(outh); if(no_touch_headers) compare_and_move_header(); #if 0 poptFreeContext(optCon); #endif return 0; }