2 * Copyright (C) 1999 the Free Software Foundation.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
38 char *filename = NULL;
47 extern GList *include_files;
50 static char *funcbase;
51 static char *pfuncbase;
52 static char *macrobase;
54 static char *macrotype;
55 static char *typebase;
56 static char *ptypebase;
58 static int signals = 0; /* number of signals */
59 static int arguments = 0; /* number of named arguments */
60 static int overrides = 0; /* number of override functions */
61 static int privates = 0; /* number of private data members */
67 gboolean no_touch_headers = FALSE;
68 gboolean for_cpp = FALSE;
69 gboolean exit_on_warn = FALSE;
70 gboolean exit_on_error = TRUE;
71 gboolean got_error = FALSE;
72 gboolean always_private_header = FALSE;
73 gboolean no_private_header = FALSE;
76 print_error(int is_warn, char *error,int line)
86 fprintf(stderr,"%s:%d: %s %s\n",filename,line,w,error);
88 fprintf(stderr,"%s: %s %s\n",filename,w,error);
89 if((!is_warn || exit_on_warn) && exit_on_error)
94 remove_sep(char *base)
97 char *s = g_strdup(base);
98 while((p=strchr(s,':')))
104 replace_sep(char *base, char r)
107 char *s = g_strdup(base);
108 while((p=strchr(s,':')))
118 /*separate the namespace part and then replace rest of
121 separns_replace_sep(char *base, char **ns, char **name, char r)
124 char *s = g_strdup(base);
126 if((p=strchr(s,':')) && p!=s) {
133 while((p=strchr(s,':')))
136 *name = g_strdup(s+1);
142 /* make a macro with some prefix before the name but after
145 make_pre_macro(char *base, char *pre)
150 separns_replace_sep(base,&s1,&s2,'_');
152 s = g_strconcat(s1,"_",pre,"_",s2,NULL);
154 s = g_strconcat(pre,"_",s2,NULL);
167 filebase = replace_sep(((Class *)class)->otype,'-');
170 funcbase = replace_sep(((Class *)class)->otype,'_');
173 pfuncbase = replace_sep(((Class *)class)->ptype,'_');
174 g_strdown(pfuncbase);
176 macrobase = replace_sep(((Class *)class)->otype,'_');
179 macrois = make_pre_macro(((Class *)class)->otype,"IS");
180 macrotype = make_pre_macro(((Class *)class)->otype,"TYPE");
182 typebase = remove_sep(((Class *)class)->otype);
184 ptypebase = remove_sep(((Class *)class)->ptype);
188 print_type(FILE *fp, Type *t, gboolean postfix_to_stars)
194 s = remove_sep(t->name);
195 out_printf(fp,"%s ",s);
199 if(postfix_to_stars) {
201 /*XXX: this is ugly perhaps we can do this whole postfix thing
202 in a nicer way, we just count the number of '[' s and from that
203 we deduce the number of dimensions */
204 for(p=t->postfix; p && *p; p++)
205 if(*p == '[') extra++;
208 for(i=0;i<(t->stars+extra);i++)
213 print_method(FILE *fp, char *typeprefix, char *nameprefix,
214 char *namepostfix,char *postfix, Method *m,
215 gboolean no_funcbase)
219 out_printf(fp,"%s",typeprefix);
220 print_type(fp,m->mtype,TRUE);
222 out_printf(fp,"%s%s%s(",
223 nameprefix,m->id,namepostfix);
225 out_printf(fp,"%s%s_%s%s(",
226 nameprefix,funcbase,m->id,namepostfix);
229 for(li=m->args;li;li=g_list_next(li)) {
230 FuncArg *arg = li->data;
231 print_type(fp,arg->atype,FALSE);
233 out_printf(fp,"%s%s, ",arg->name,
235 arg->atype->postfix:"");
237 out_printf(fp,"%s%s",arg->name,
239 arg->atype->postfix:"");
242 out_printf(fp,", ...");
244 out_printf(fp,"void");
246 out_printf(fp,")%s",postfix);
251 make_method_pointers(Class *c)
255 out_printf(out,"\n");
256 for(li=c->nodes;li;li=g_list_next(li)) {
257 Node *node = li->data;
258 if(node->type == METHOD_NODE) {
259 Method *m = (Method *)node;
261 if(m->scope == INIT_METHOD ||
262 m->scope == CLASS_INIT_METHOD ||
263 m->scope == OVERRIDE_METHOD)
266 /* in C++ mode don't alias new */
267 if(for_cpp && strcmp(m->id,"new")==0)
270 print_method(out,"static ","(* ",") ","",m,TRUE);
271 out_printf(out," = %s_%s;\n",funcbase,m->id);
274 out_printf(out,"\n");
278 add_bad_hack_to_avoid_unused_warnings(Class *c)
282 out_printf(out,"\n\n/*REALLY BAD HACK\n"
283 " This is to avoid unused warnings if you don't call\n"
284 " some method, it pollutes the namespace but the call\n"
285 " is weird enough. I need to find a better way to do\n"
287 out_printf(out,"void __%s_really_bad_hack_to_avoid_warnings(void);\n",
289 out_printf(out,"void\n__%s_really_bad_hack_to_avoid_warnings(void)\n"
291 for(li=c->nodes;li;li=g_list_next(li)) {
292 Node *node = li->data;
293 if(node->type == METHOD_NODE) {
294 Method *m = (Method *)node;
296 if(m->scope == INIT_METHOD ||
297 m->scope == CLASS_INIT_METHOD ||
298 m->scope == OVERRIDE_METHOD)
301 /* in C++ mode we don't alias new */
302 if(for_cpp && strcmp(m->id,"new")==0)
305 out_printf(out,"\t((void (*)(void))%s)();\n",m->id);
308 out_printf(out,"}\n\n");
312 put_variable(Variable *v, FILE *fp)
315 print_type(fp,v->vtype,FALSE);
316 out_printf(fp,"%s%s;\n",v->id,
318 v->vtype->postfix:"");
322 put_vs_method(Method *m)
324 if(m->scope != SIGNAL_LAST_METHOD &&
325 m->scope != SIGNAL_FIRST_METHOD &&
326 m->scope != PRIVATE_SIGNAL_LAST_METHOD &&
327 m->scope != PRIVATE_SIGNAL_FIRST_METHOD &&
328 m->scope != VIRTUAL_METHOD &&
329 m->scope != PRIVATE_VIRTUAL_METHOD)
332 print_method(outh,"\t","(* ",") ",";\n",m,TRUE);
336 put_pub_method(Method *m)
338 if(m->scope == PRIVATE_SCOPE ||
339 m->scope == OVERRIDE_METHOD ||
340 m->scope == INIT_METHOD ||
341 m->scope == CLASS_INIT_METHOD ||
342 m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
343 m->scope == PRIVATE_SIGNAL_FIRST_METHOD ||
344 m->scope == PRIVATE_VIRTUAL_METHOD)
347 print_method(outh,"","\t","\t",";\n",m,FALSE);
351 put_priv_method_prot(Method *m)
353 if(m->scope == PUBLIC_SCOPE)
356 if(m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
357 m->scope == PRIVATE_SIGNAL_FIRST_METHOD ||
358 m->scope == PRIVATE_VIRTUAL_METHOD) {
360 print_method(out,"static ","_real_"," ",";\n",m,FALSE);
361 print_method(out,"static ",""," ",";\n",m,FALSE);
362 } else if(m->scope == SIGNAL_LAST_METHOD ||
363 m->scope == SIGNAL_FIRST_METHOD ||
364 m->scope == VIRTUAL_METHOD) {
367 print_method(out,"static ","_real_"," ",";\n",m,FALSE);
369 print_method(out,"static ",""," ",";\n",m,FALSE);
374 make_func_arg(char *typename, int is_class, char *name)
381 tn = g_strconcat(typename,":Class",NULL);
383 tn = g_strdup(typename);
385 type = new_type(1,tn,NULL);
386 node = new_funcarg((Type *)type,name,NULL);
387 return g_list_prepend(NULL, node);
391 make_inits(Class *cl)
393 int got_class_init = FALSE;
394 int got_init = FALSE;
397 for(li=cl->nodes;li;li=g_list_next(li)) {
399 if(n->type == METHOD_NODE) {
400 Method *m = (Method *)n;
401 if(m->scope == INIT_METHOD) {
403 print_error(FALSE,"init defined more then once",m->line_no);
405 } else if(m->scope == CLASS_INIT_METHOD) {
407 print_error(FALSE,"class_init defined more then once",m->line_no);
408 got_class_init = TRUE;
412 if(!got_class_init) {
413 node = new_method(CLASS_INIT_METHOD,
414 (Type *)new_type(0,g_strdup("void"),NULL),
415 NULL,NULL,g_strdup("class_init"),
416 make_func_arg(cl->otype,TRUE,g_strdup("c")),
417 NULL, NULL,0,0,FALSE);
418 cl->nodes = g_list_prepend(cl->nodes,node);
421 node = new_method(INIT_METHOD,
422 (Type *)new_type(0,g_strdup("void"),NULL),
423 NULL,NULL,g_strdup("init"),
424 make_func_arg(cl->otype,FALSE,g_strdup("o")),
425 NULL, NULL,0,0,FALSE);
426 cl->nodes = g_list_prepend(cl->nodes,node);
431 make_destroy(Class *cl)
433 int got_destroy = FALSE;
436 for(li=cl->nodes;li;li=g_list_next(li)) {
438 if(n->type == METHOD_NODE) {
439 Method *m = (Method *)n;
440 if(m->scope == OVERRIDE_METHOD &&
441 strcmp(m->id,"destroy")==0) {
442 if(strcmp(m->otype,"Gtk:Object")==0) {
446 print_error(FALSE,"destroy method override "
447 "of class other then Gtk:Object",
455 node = new_method(OVERRIDE_METHOD,
456 (Type *)new_type(0,g_strdup("void"),NULL),
457 g_strdup("Gtk:Object"),
458 NULL,g_strdup("destroy"),
459 make_func_arg("Gtk:Object",FALSE,g_strdup("o")),
461 g_string_new("PARENT_HANDLER (o);\n"),
463 cl->nodes = g_list_append(cl->nodes,node);
468 static GHashTable *marsh = NULL;
471 add_signal_prots(Method *m)
477 if(m->scope != SIGNAL_LAST_METHOD &&
478 m->scope != SIGNAL_FIRST_METHOD &&
479 m->scope != PRIVATE_SIGNAL_LAST_METHOD &&
480 m->scope != PRIVATE_SIGNAL_FIRST_METHOD)
484 marsh = g_hash_table_new(NULL,NULL);
486 if(strcmp(m->gtktypes->data,"NONE")==0 &&
487 strcmp(m->gtktypes->next->data,"NONE")==0)
490 s = g_strdup_printf("__Sig%d",sig++);
492 g_hash_table_insert(marsh,m,s);
494 out_printf(out,"\ntypedef ");
495 print_type(out,m->mtype,TRUE);
497 out_printf(out,"(*%s) (",s);
499 for(li=m->args;li;li=g_list_next(li)) {
500 FuncArg *arg = li->data;
501 print_type(out,arg->atype,TRUE);
502 out_printf(out,", ");
504 out_printf(out,"gpointer);\n");
506 out_printf(out,"\nstatic void\n"
507 "marshal_%s (GtkObject * object,\n"
508 "\tGtkSignalFunc func,\n"
509 "\tgpointer func_data,\n"
513 if(strcmp(m->gtktypes->data,"NONE")==0) {
515 out_printf(out, "\t%s rfunc;\n\n"
516 "\trfunc = (%s)func;\n\n"
517 "\t(*rfunc)((%s *)object",s,s,typebase);
518 if(strcmp(m->gtktypes->next->data,"NONE")!=0) {
519 GList *ali = m->args->next;
520 for(i=0,li=m->gtktypes->next;li;
521 i++,li=g_list_next(li)) {
523 out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
526 FuncArg *fa = ali->data;
527 out_printf(out, ",\n\t\t(");
528 print_type(out,fa->atype,TRUE);
529 out_printf(out, ")GTK_VALUE_%s(args[%d])",
533 if(ali) ali = ali->next;
536 out_printf(out, ",\n\t\tfunc_data);\n}\n\n");
539 out_printf(out, "\t%s rfunc;\n\t",s);
540 print_type(out,m->mtype,TRUE);
541 out_printf(out, " *retval;\n\n"
542 "\trfunc = (%s)func;\n\n"
543 "\tretval = GTK_RETLOC_%s(args[%d]);\n\n"
544 "\t*retval = (*rfunc)((%s *)object",
545 s,(char *)m->gtktypes->data,
546 g_list_length(m->gtktypes)-1,typebase);
547 if(strcmp(m->gtktypes->next->data,"NONE")!=0) {
548 GList *ali = m->args->next;
549 for(i=0,li=m->gtktypes->next;li;
550 i++,li=g_list_next(li)) {
552 out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
555 FuncArg *fa = ali->data;
556 out_printf(out, ",\n\t\t(");
557 print_type(out,fa->atype,TRUE);
558 out_printf(out, ")GTK_VALUE_%s(args[%d])",
562 if(ali) ali = ali->next;
565 out_printf(out, ",\n\t\tfunc_data);\n}\n\n");
574 out_printf(out,"\n");
576 out_printf(out,"enum {\n");
577 for(li=c->nodes;li;li=g_list_next(li)) {
579 if(n->type == METHOD_NODE) {
580 Method *m = (Method *)n;
581 if(m->scope == SIGNAL_LAST_METHOD ||
582 m->scope == SIGNAL_FIRST_METHOD ||
583 m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
584 m->scope == PRIVATE_SIGNAL_FIRST_METHOD) {
585 char *s = g_strdup(m->id);
587 out_printf(out,"\t%s_SIGNAL,\n",s);
592 out_printf(out,"\tLAST_SIGNAL\n};\n\n");
595 out_printf(out,"enum {\n\tARG_0,\n");
596 for(li=c->nodes;li;li=g_list_next(li)) {
598 if(n->type == ARGUMENT_NODE) {
599 Argument *a = (Argument *)n;
600 char *s = g_strdup(a->name);
602 out_printf(out,"\tARG_%s,\n",s);
606 out_printf(out, "};\n\n");
611 "static guint object_signals[LAST_SIGNAL] = {0};\n\n");
613 out_printf(out, "static %sClass *parent_class = NULL;\n\n",ptypebase);
619 out_printf(out, "guint\n"
620 "%s_get_type (void)\n"
622 "\tstatic guint type = 0;\n\n"
624 "\t\tstatic const GtkTypeInfo info = {\n"
626 "\t\t\tsizeof (%s),\n"
627 "\t\t\tsizeof (%sClass),\n"
628 "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
629 "\t\t\t(GtkObjectInitFunc) %s_init,\n"
630 "\t\t\t/* reserved_1 */ NULL,\n"
631 "\t\t\t/* reserved_2 */ NULL,\n"
632 "\t\t\t(GtkClassInitFunc) NULL,\n"
634 "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n"
638 funcbase,typebase,typebase,typebase,
639 funcbase,funcbase,pfuncbase);
643 add_overrides(Class *c, char *oname, gboolean did_gtk_obj)
649 done = g_hash_table_new(g_str_hash,g_str_equal);
651 s = g_strdup("GtkObject"); /* This was already done */
652 g_hash_table_insert(done,s,s);
654 for(li=c->nodes;li;li=g_list_next(li)) {
658 if(n->type != METHOD_NODE ||
659 ((Method *)n)->scope != OVERRIDE_METHOD)
663 s = remove_sep(m->otype);
665 if(g_hash_table_lookup(done,s)) {
669 g_hash_table_insert(done,s,s);
671 f = replace_sep(m->otype,'_');
674 out_printf(out,"\t%sClass *%s_class = (%sClass *)%s;\n",
679 g_hash_table_foreach(done,(GHFunc)g_free,NULL);
680 g_hash_table_destroy(done);
684 add_signals(Class *c)
688 out_printf(out,"\n");
689 for(li=c->nodes;li;li=g_list_next(li)) {
696 if(n->type != METHOD_NODE ||
697 (((Method *)n)->scope != SIGNAL_FIRST_METHOD &&
698 ((Method *)n)->scope != SIGNAL_LAST_METHOD &&
699 ((Method *)n)->scope != PRIVATE_SIGNAL_FIRST_METHOD &&
700 ((Method *)n)->scope != PRIVATE_SIGNAL_LAST_METHOD))
705 if(m->scope == SIGNAL_FIRST_METHOD ||
706 m->scope == PRIVATE_SIGNAL_FIRST_METHOD)
711 if(g_hash_table_lookup(marsh,m))
712 mar = g_strconcat("marshal_",
713 (char *)g_hash_table_lookup(marsh,m),
716 mar = g_strdup("gtk_signal_default_marshaller");
718 is_none = (strcmp(m->gtktypes->next->data,"NONE")==0);
720 sig = g_strdup(m->id);
722 out_printf(out,"\tobject_signals[%s_SIGNAL] =\n"
723 "\t\tgtk_signal_new (\"%s\",\n"
724 "\t\t\tGTK_RUN_%s,\n"
725 "\t\t\tgtk_object_class->type,\n"
726 "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n"
728 "\t\t\tGTK_TYPE_%s, %d",
731 typebase,m->id,mar,(char *)m->gtktypes->data,
732 is_none?0:g_list_length(m->gtktypes->next));
738 for(l=m->gtktypes->next;l;l=g_list_next(l))
739 out_printf(out,",\n\t\t\tGTK_TYPE_%s",
743 out_printf(out,");\n");
745 out_printf(out,"\tgtk_object_class_add_signals (gtk_object_class,\n"
746 "\t\tobject_signals, LAST_SIGNAL);\n\n");
750 set_def_handlers(Class *c, char *oname)
754 out_printf(out,"\n");
755 for(li=c->nodes;li;li=g_list_next(li)) {
758 if(n->type != METHOD_NODE ||
759 (((Method *)n)->scope != SIGNAL_FIRST_METHOD &&
760 ((Method *)n)->scope != SIGNAL_LAST_METHOD &&
761 ((Method *)n)->scope != PRIVATE_SIGNAL_FIRST_METHOD &&
762 ((Method *)n)->scope != PRIVATE_SIGNAL_LAST_METHOD &&
763 ((Method *)n)->scope != VIRTUAL_METHOD &&
764 ((Method *)n)->scope != PRIVATE_VIRTUAL_METHOD &&
765 ((Method *)n)->scope != OVERRIDE_METHOD))
770 if(m->scope == OVERRIDE_METHOD) {
772 s = replace_sep(m->otype,'_');
774 out_printf(out,"\t%s_class->%s = %s_%s;\n",
775 s,m->id,funcbase,m->id);
778 out_printf(out,"\t%s->%s = _real_%s_%s;\n",
779 oname,m->id,funcbase,m->id);
781 out_printf(out,"\t%s->%s = NULL;\n",
788 make_arguments(Class *c)
792 out_printf(out,"\n");
793 for(li=c->nodes;li;li=g_list_next(li)) {
799 if(n->type != ARGUMENT_NODE)
805 flags = g_string_new("GTK_ARG_READWRITE");
807 flags = g_string_new("GTK_ARG_READABLE");
809 flags = g_string_new("GTK_ARG_WRITABLE");
811 for(l=a->flags;l;l=g_list_next(l))
812 g_string_sprintfa(flags," | GTK_ARG_%s",(char *)l->data);
814 s = g_strdup(a->name);
816 out_printf(out,"\tgtk_object_add_arg_type(\"%s::%s\",\n"
820 typebase,a->name,a->gtktype,flags->str,s);
822 g_string_free(flags,TRUE);
826 "\n\tgtk_object_class->set_arg = __object_set_arg;\n"
827 "\tgtk_object_class->get_arg = __object_get_arg;\n");
834 for(li=c->nodes;li;li=g_list_next(li)) {
837 if(n->type != METHOD_NODE)
840 if(m->scope == INIT_METHOD) {
842 out_addline_infile(out,m->line_no);
843 print_method(out,"static ","\n"," ","\n",m,FALSE);
845 out_addline_outfile(out);
846 out_printf(out,"{\n");
848 out_printf(out,"\t%s->_priv = "
849 "g_new0 (%sPrivate,1);\n",
850 ((FuncArg *)m->args->data)->name,
853 } else if(m->scope == CLASS_INIT_METHOD) {
855 out_addline_infile(out,m->line_no);
856 print_method(out,"static ","\n"," ","\n",m,FALSE);
858 out_addline_outfile(out);
859 out_printf(out,"{\n");
864 "gtk_object_class = "
865 "(GtkObjectClass*) %s;\n",
866 ((FuncArg *)m->args->data)->name);
870 ((FuncArg *)m->args->data)->name,
871 (signals>0 || arguments>0));
873 out_printf(out,"\n\tparent_class = ");
875 out_printf(out,"(%sClass *)",ptypebase);
876 out_printf(out,"gtk_type_class (%s_get_type ());\n",
882 set_def_handlers(c, ((FuncArg *)m->args->data)->name);
891 out_printf(out," {\n");
892 out_addline_infile(out,m->ccode_line);
893 out_printf(out,"%s\n",m->cbuf->str);
894 out_addline_outfile(out);
895 out_printf(out," }\n",m->cbuf->str);
897 out_printf(out,"return;\n");
899 out_printf(out,"}\n");
904 add_getset_arg(Class *c, int is_set)
907 out_printf(out,"\nstatic void\n"
908 "__object_%s_arg (GtkObject *object,\n"
913 "\tself = %s (object);\n\n"
914 "\tswitch (arg_id) {\n",
915 is_set?"set":"get",typebase,macrobase);
917 for(li=c->nodes;li;li=g_list_next(li)) {
923 if(n->type != ARGUMENT_NODE)
928 line_no = a->set_line;
931 line_no = a->get_line;
935 s = g_strdup(a->name);
937 out_printf(out,"\tcase ARG_%s:\n"
938 "#define ARG (GTK_VALUE_%s(*arg))\n"
942 out_addline_infile(out,line_no);
943 out_printf(out,"%s\n",cbuf->str);
944 out_addline_outfile(out);
945 out_printf(out,"\t\t}\n\t\tbreak;\n"
948 out_printf(out,"\tdefault:\n\t\tbreak;\n\t}\n}\n");
952 print_checks(Method *m, FuncArg *fa)
956 is_void = (strcmp(m->mtype->name,"void")==0 &&
957 m->mtype->stars == 0);
959 for(li=fa->checks;li;li=g_list_next(li)) {
960 Check *ch = li->data;
963 out_printf(out,"\tg_return_if_fail (");
965 out_printf(out,"\tg_return_val_if_fail (");
968 out_printf(out,"%s != NULL",fa->name);
971 s = make_pre_macro(fa->atype->name,"IS");
972 out_printf(out,"%s (%s)",s,fa->name);
976 out_printf(out,"%s < %s",fa->name,ch->number);
979 out_printf(out,"%s > %s",fa->name,ch->number);
982 out_printf(out,"%s <= %s",fa->name,ch->number);
985 out_printf(out,"%s >= %s",fa->name,ch->number);
988 out_printf(out,"%s == %s",fa->name,ch->number);
991 out_printf(out,"%s != %s",fa->name,ch->number);
995 out_printf(out,");\n");
997 out_printf(out,", (");
998 print_type(out,m->mtype,TRUE);
999 out_printf(out,")%s);\n",
1000 m->onerror?m->onerror:"0");
1006 print_preconditions(Method *m)
1010 for(li=m->args;li;li=g_list_next(li)) {
1011 FuncArg *fa = li->data;
1017 /* put in code if it's needed */
1019 put_in_gen_code(Method *m)
1021 /* now we only have the freeing of the private structure */
1023 m->scope == OVERRIDE_METHOD &&
1024 strcmp(m->id,"destroy")==0) {
1025 out_printf(out,"\tg_free (%s (%s)->_priv);\n"
1026 "\t%s (%s)->_priv = NULL;\n",
1028 ((FuncArg *)m->args->data)->name,
1030 ((FuncArg *)m->args->data)->name);
1036 print_method_body(Method *m, int pre)
1038 out_printf(out,"{\n");
1040 print_preconditions(m);
1043 out_printf(out,"\t{\n");
1045 out_addline_infile(out,m->ccode_line);
1046 out_printf(out,"\t\t%s\n",m->cbuf->str);
1047 out_addline_outfile(out);
1049 out_printf(out,"\t}\n");
1050 out_printf(out,"}\n");
1054 put_method(Method *m)
1057 int private = FALSE;
1058 out_printf(out,"\n");
1061 out_addline_infile(out,m->line_no);
1062 print_method(out,"","\n"," ","\n",m,FALSE);
1063 print_method_body(m,TRUE);
1066 out_addline_infile(out,m->line_no);
1067 print_method(out,"static ","\n"," ","\n",m,FALSE);
1068 print_method_body(m,TRUE);
1070 case PRIVATE_SIGNAL_FIRST_METHOD:
1071 case PRIVATE_SIGNAL_LAST_METHOD:
1073 case SIGNAL_FIRST_METHOD:
1074 case SIGNAL_LAST_METHOD:
1075 out_addline_infile(out,m->line_no);
1076 print_method(out,private?"static ":"","\n"," ","\n",m,FALSE);
1077 out_addline_outfile(out);
1078 out_printf(out,"{\n");
1079 s = g_strdup(m->id);
1081 if(strcmp(m->mtype->name,"void")==0 &&
1082 m->mtype->stars==0) {
1084 print_preconditions(m);
1085 if(((FuncArg *)m->args->data)->name)
1086 out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1087 "\t\tobject_signals[%s_SIGNAL]",
1088 ((FuncArg *)m->args->data)->name,s);
1089 for(li=m->args->next;li;li=g_list_next(li)) {
1090 FuncArg *fa = li->data;
1091 out_printf(out,",\n\t\t%s",fa->name);
1093 out_printf(out,");\n}\n");
1096 out_printf(out,"\t");
1097 print_type(out,m->mtype,TRUE);
1098 out_printf(out,"return_val;\n");
1099 print_preconditions(m);
1100 out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1101 "\t\tobject_signals[%s_SIGNAL]",
1102 ((FuncArg *)m->args->data)->name,s);
1103 for(li=m->args->next;li;li=g_list_next(li)) {
1104 FuncArg *fa = li->data;
1105 out_printf(out,",\n\t\t%s",fa->name);
1107 out_printf(out,",\n\t\t&return_val);\n"
1108 "\treturn return_val;\n}\n");
1113 out_addline_infile(out,m->line_no);
1114 print_method(out,"static ","\n_real_"," ","\n",m,FALSE);
1115 print_method_body(m,FALSE);
1117 case PRIVATE_VIRTUAL_METHOD:
1119 case VIRTUAL_METHOD:
1120 out_addline_infile(out,m->line_no);
1121 print_method(out,private?"static ":"","\n"," ","\n",m,FALSE);
1122 out_addline_outfile(out);
1123 out_printf(out,"{\n"
1124 "\t%sClass *klass;\n",typebase);
1125 print_preconditions(m);
1126 out_printf(out,"\tklass = %s_CLASS(GTK_OBJECT(%s)->klass);\n\n"
1127 "\tif(klass->%s)\n",
1128 macrobase, ((FuncArg *)m->args->data)->name, m->id);
1129 if(strcmp(m->mtype->name,"void")==0 &&
1130 m->mtype->stars==0) {
1132 out_printf(out,"\t\t(*klass->%s)(%s",m->id,
1133 ((FuncArg *)m->args->data)->name);
1134 for(li=m->args->next;li;li=g_list_next(li)) {
1135 FuncArg *fa = li->data;
1136 out_printf(out,",%s",fa->name);
1138 out_printf(out,");\n}\n");
1141 out_printf(out,"\t\treturn (*klass->%s)(%s",m->id,
1142 ((FuncArg *)m->args->data)->name);
1143 for(li=m->args->next;li;li=g_list_next(li)) {
1144 FuncArg *fa = li->data;
1145 out_printf(out,",%s",fa->name);
1147 out_printf(out,");\n"
1150 print_type(out,m->mtype,TRUE);
1151 out_printf(out,")(%s);\n}\n",
1152 m->onerror?m->onerror:"0");
1157 out_addline_infile(out,m->line_no);
1158 print_method(out,"static ","\n_real_"," ","\n",m,FALSE);
1159 print_method_body(m,FALSE);
1161 case OVERRIDE_METHOD:
1162 out_addline_infile(out,m->line_no);
1163 print_method(out,"static ","\n"," ","\n",m,FALSE);
1164 s = replace_sep(m->otype,'_');
1166 out_printf(out,"#define PARENT_HANDLER(args...) \\\n"
1167 "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
1168 "\t\t(* %s_CLASS(parent_class)->%s)(##args); }\n",
1171 print_method_body(m,TRUE);
1172 out_printf(out,"#undef PARENT_HANDLER\n");
1180 check_duplicate(Class *c,Node *node,char *id, int line_no)
1183 for(l=c->nodes;l;l=g_list_next(l)) {
1188 if(n->type == METHOD_NODE) {
1189 Method *m = (Method *)n;
1191 nline_no = m->line_no;
1192 } else if(n->type == VARIABLE_NODE) {
1193 Variable *v = (Variable *)n;
1195 nline_no = v->line_no;
1199 line_no>=nline_no ||
1200 strcmp(nid,id)!=0 ||
1201 n->type != node->type)
1203 s = g_strdup_printf("symbol '%s' redefined, "
1204 "first defined on line %d",
1206 print_error(FALSE,s,nline_no);
1211 check_duplicate_symbols(Class *c)
1214 for(l=c->nodes;l;l=g_list_next(l)) {
1216 if(n->type == METHOD_NODE) {
1217 Method *m = (Method *)n;
1218 check_duplicate(c,n,m->id,m->line_no);
1219 } else if(n->type == VARIABLE_NODE) {
1220 Variable *v = (Variable *)n;
1221 check_duplicate(c,n,v->id,v->line_no);
1227 check_bad_symbols(Class *c)
1230 for(l=c->nodes;l;l=g_list_next(l)) {
1232 if(n->type == METHOD_NODE) {
1233 Method *m = (Method *)n;
1234 if((m->scope == SIGNAL_LAST_METHOD ||
1235 m->scope == SIGNAL_FIRST_METHOD ||
1236 m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1237 m->scope == PRIVATE_SIGNAL_FIRST_METHOD ||
1238 m->scope == VIRTUAL_METHOD ||
1239 m->scope == PRIVATE_VIRTUAL_METHOD) &&
1240 strcmp(m->id,"__parent__")==0) {
1242 s = g_strdup_printf("'%s' not allowed as an "
1243 "identifier of signal "
1244 "or virtual methods",
1246 print_error(FALSE,s,m->line_no);
1249 } else if(n->type == VARIABLE_NODE) {
1250 Variable *v = (Variable *)n;
1251 if(strcmp(v->id,"_priv")==0 ||
1252 strcmp(v->id,"__parent__")==0) {
1254 s = g_strdup_printf("'%s' not allowed as a data "
1255 "member name",v->id);
1256 print_error(FALSE,s,v->line_no);
1265 check_duplicate_named(Class *c,Node *node,char *id, int line_no)
1268 for(l=c->nodes;l;l=g_list_next(l)) {
1273 if(n->type == METHOD_NODE) {
1274 Method *m = (Method *)n;
1275 if(m->scope == SIGNAL_LAST_METHOD ||
1276 m->scope == SIGNAL_FIRST_METHOD ||
1277 m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1278 m->scope == PRIVATE_SIGNAL_FIRST_METHOD) {
1280 nline_no = m->line_no;
1283 } else if(n->type == ARGUMENT_NODE) {
1284 Argument *a = (Argument *)n;
1286 nline_no = a->line_no;
1290 line_no>=nline_no ||
1293 s = g_strdup_printf("named symbol (argument or signal) '%s' "
1294 "redefined, first defined on line %d",
1296 print_error(FALSE,s,nline_no);
1301 check_duplicate_signals_args(Class *c)
1304 for(l=c->nodes;l;l=g_list_next(l)) {
1306 if(n->type == METHOD_NODE) {
1307 Method *m = (Method *)n;
1308 if(m->scope == SIGNAL_LAST_METHOD ||
1309 m->scope == SIGNAL_FIRST_METHOD ||
1310 m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1311 m->scope == PRIVATE_SIGNAL_FIRST_METHOD)
1312 check_duplicate_named(c,n,m->id,m->line_no);
1313 } else if(n->type == ARGUMENT_NODE) {
1314 Argument *a = (Argument *)n;
1315 check_duplicate_named(c,n,a->name,a->line_no);
1321 check_public_new(Class *c)
1324 for(l=c->nodes;l;l=g_list_next(l)) {
1326 if(n->type == METHOD_NODE) {
1327 Method *m = (Method *)n;
1328 if(m->scope!=PUBLIC_SCOPE &&
1329 strcmp(m->id,"new")==0)
1331 "'new' should be a public method",
1338 check_vararg(Class *c)
1341 for(l=c->nodes;l;l=g_list_next(l)) {
1343 if(n->type == METHOD_NODE) {
1344 Method *m = (Method *)n;
1347 if(m->scope == OVERRIDE_METHOD ||
1348 m->scope == SIGNAL_LAST_METHOD ||
1349 m->scope == SIGNAL_FIRST_METHOD ||
1350 m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1351 m->scope == PRIVATE_SIGNAL_FIRST_METHOD ||
1352 m->scope == VIRTUAL_METHOD ||
1353 m->scope == PRIVATE_VIRTUAL_METHOD) {
1355 "signals, overrides and virtuals, "
1356 "can't have variable argument "
1365 check_firstarg(Class *c)
1368 for(l=c->nodes;l;l=g_list_next(l)) {
1370 if(n->type == METHOD_NODE) {
1371 Method *m = (Method *)n;
1374 if(m->scope == OVERRIDE_METHOD ||
1375 m->scope == SIGNAL_LAST_METHOD ||
1376 m->scope == SIGNAL_FIRST_METHOD ||
1377 m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1378 m->scope == PRIVATE_SIGNAL_FIRST_METHOD ||
1379 m->scope == VIRTUAL_METHOD ||
1380 m->scope == PRIVATE_VIRTUAL_METHOD) {
1382 "signals, overrides and virtuals, "
1383 "can't have no arguments",
1391 count_signals(Class *c)
1395 for(l=c->nodes;l;l=g_list_next(l)) {
1397 if(n->type == METHOD_NODE) {
1398 Method *m = (Method *)n;
1399 if(m->scope == SIGNAL_LAST_METHOD ||
1400 m->scope == SIGNAL_FIRST_METHOD ||
1401 m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1402 m->scope == PRIVATE_SIGNAL_FIRST_METHOD)
1410 count_arguments(Class *c)
1415 for(li=c->nodes;li;li=g_list_next(li)) {
1417 if(n->type == ARGUMENT_NODE)
1424 count_overrides(Class *c)
1428 for(l=c->nodes;l;l=g_list_next(l)) {
1430 if(n->type == METHOD_NODE) {
1431 Method *m = (Method *)n;
1432 if(m->scope == OVERRIDE_METHOD)
1440 count_privates(Class *c)
1444 for(l=c->nodes;l;l=g_list_next(l)) {
1446 if(n->type == VARIABLE_NODE) {
1447 Variable *v = (Variable *)n;
1448 if(v->scope == PRIVATE_SCOPE)
1459 char *outfile,*outfileh,*outfileph;
1462 outfile = g_strconcat(filebase,".c",NULL);
1464 outfile = g_strconcat(filebase,".cc",NULL);
1465 if(no_touch_headers)
1466 outfileh = g_strconcat("#gob#",filebase,".h#gob#",NULL);
1468 outfileh = g_strconcat(filebase,".h",NULL);
1470 if((privates>0 || always_private_header) &&
1472 outfileph = g_strconcat(filebase,"-private.h",NULL);
1477 out = fopen(outfile,"w");
1479 g_error("Cannot open outfile: %s",outfile);
1481 outh = fopen(outfileh,"w");
1483 g_error("Cannot open outfile: %s",outfileh);
1486 outph = fopen(outfileph,"w");
1488 g_error("Cannot open outfile: %s",outfileh);
1494 generate_outfiles(void)
1499 gboolean found_header;
1502 out_printf(outh,"/* Generated by GOB (v%s)"
1503 " (do not edit directly) */\n\n",VERSION);
1505 out_printf(outph,"/* Generated by GOB (v%s)"
1506 " (do not edit directly) */\n\n",VERSION);
1507 out_printf(out,"/* Generated by GOB (v%s) on %s"
1508 " (do not edit directly) */\n\n",VERSION,ctime(&curtime));
1510 p = replace_sep(((Class *)class)->otype,'_');
1512 out_printf(outh,"#ifndef __%s_H__\n#define __%s_H__\n\n"
1513 "#include <gtk/gtk.h>\n\n",p,p);
1515 out_printf(outph,"#ifndef __%s_PRIVATE_H__\n"
1516 "#define __%s_PRIVATE_H__\n\n"
1517 "#include \"%s.h\"\n\n",p,p,filebase);
1521 out_printf(outh,"#ifdef __cplusplus\n"
1523 "#endif /* __cplusplus */\n\n");
1525 out_printf(outph,"#ifdef __cplusplus\n"
1527 "#endif /* __cplusplus */\n\n");
1530 p = g_strconcat(filebase,".h",NULL);
1531 found_header = TRUE;
1532 if(!g_list_find_custom(include_files,p,(GCompareFunc)strcmp)) {
1533 out_printf(out,"#include \"%s.h\"\n\n",filebase);
1534 found_header = FALSE;
1538 /* if we are creating a private header see if it was included */
1540 p = g_strconcat(filebase,"-private.h",NULL);
1541 if(!g_list_find_custom(include_files,p,(GCompareFunc)strcmp)) {
1542 out_printf(out,"#include \"%s-private.h\"\n\n",
1546 "Implicit private header include "
1548 "\tsource file, while public "
1549 "header is at a custom location, "
1551 "\texplicitly include "
1552 "the private header below the "
1558 for(li=nodes;li;li=g_list_next(li)) {
1559 Node *node = li->data;
1560 if(node->type == CCODE_NODE) {
1561 CCode *cc = (CCode *)node;
1565 out_printf(fp,"\n");
1568 out_printf(fp,"\n");
1569 out_addline_infile(fp,cc->line_no);
1571 out_printf(fp,"%s\n",cc->cbuf->str);
1573 out_addline_outfile(fp);
1574 } else if(node->type == CLASS_NODE) {
1575 Class *c = (Class *)class;
1578 out_printf(outh,"\n#define %s\t"
1579 "(%s_get_type())\n",
1580 macrotype,funcbase);
1581 out_printf(outh,"#define %s(obj)\t"
1582 "GTK_CHECK_CAST((obj),%s_get_type(),%s)\n",
1583 macrobase,funcbase,typebase);
1584 out_printf(outh,"#define %s_CLASS(klass)\t"
1585 "GTK_CHECK_CLASS_CAST((klass),%s_get_type(),%sClass)\n",
1586 macrobase,funcbase,typebase);
1587 out_printf(outh,"#define %s(obj)\t"
1588 "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
1592 out_printf(outh,"\ntypedef struct _%sPrivate %sPrivate;\n",typebase,typebase);
1594 out_printf(outh,"\ntypedef struct _%s %s;\n",typebase,typebase);
1595 out_printf(outh,"struct _%s {\n\t%s __parent__;\n",
1596 typebase,ptypebase);
1597 for(l=c->nodes;l;l=g_list_next(l)) {
1599 Variable *v = (Variable *)n;
1600 if(n->type == VARIABLE_NODE &&
1601 v->scope == PUBLIC_SCOPE)
1602 put_variable((Variable *)n,outh);
1605 out_printf(outh,"\t%sPrivate *_priv;\n",typebase);
1606 out_printf(outh,"};\n");
1611 /* if we are to stick this into the private
1612 header, otherwise stick it directly into the
1619 out_printf(outfp,"struct _%sPrivate {\n",
1621 for(l=c->nodes;l;l=l->next) {
1623 Variable *v = (Variable *)n;
1624 if(n->type == VARIABLE_NODE &&
1625 v->scope == PRIVATE_SCOPE) {
1626 out_addline_infile(outfp,v->line_no);
1627 put_variable(v,outfp);
1630 out_addline_outfile(outfp);
1631 out_printf(outfp,"};\n");
1634 out_printf(outh,"\ntypedef struct _%sClass %sClass;\n",
1637 "struct _%sClass {\n\t%sClass __parent__;\n",
1638 typebase,ptypebase);
1639 for(l=c->nodes;l;l=g_list_next(l)) {
1641 if(n->type == METHOD_NODE)
1642 put_vs_method((Method *)n);
1644 out_printf(outh,"};\n\n");
1646 out_printf(outh,"guint\t%s_get_type\t(void);\n",funcbase);
1649 out_printf(out,"static void __object_set_arg "
1650 "(GtkObject *object, GtkArg *arg, "
1652 "static void __object_get_arg "
1653 "(GtkObject *object, GtkArg *arg, "
1654 "guint arg_id);\n");
1657 for(l=c->nodes;l;l=g_list_next(l)) {
1659 if(n->type == METHOD_NODE) {
1660 put_pub_method((Method *)n);
1661 put_priv_method_prot((Method *)n);
1666 for(l=c->nodes;l;l=g_list_next(l)) {
1668 if(n->type == METHOD_NODE) {
1669 add_signal_prots((Method *)n);
1678 make_method_pointers(c);
1680 out_printf(out,"#define GET_NEW (gtk_type_new(%s_get_type()))\n",
1686 add_getset_arg(c, TRUE);
1687 add_getset_arg(c, FALSE);
1690 for(l=c->nodes;l;l=g_list_next(l)) {
1692 if(n->type == METHOD_NODE) {
1693 put_method((Method *)n);
1697 out_printf(out,"#undef GET_NEW\n");
1699 add_bad_hack_to_avoid_unused_warnings(c);
1701 g_assert_not_reached();
1705 out_printf(outh,"\n#ifdef __cplusplus\n"
1707 "#endif /* __cplusplus */\n");
1708 out_printf(outh,"\n#endif");
1711 out_printf(outph,"\n#ifdef __cplusplus\n"
1713 "#endif /* __cplusplus */\n");
1714 out_printf(outph,"\n#endif");
1720 usage(poptContext optCon, int exitcode, char *error, char *addl)
1722 poptPrintUsage(optCon, stderr, 0);
1723 if (error) fprintf(stderr, "%s: %s", error, addl);
1731 fprintf(stderr,"Gob version %s\n\n",VERSION);
1732 fprintf(stderr,"Options:\n"
1733 "\t--help,-h,-? Display this help\n"
1734 "\t--exit-on-warn,-w Exit with an error on warnings\n"
1735 "\t--no-exit-on-warn Don't exit on warnings [default]\n"
1736 "\t--for-cpp Create C++ files\n"
1737 "\t--no-touch-headers Don't touch headers unless they "
1739 "\t--always-private-header Always create a private header "
1740 "file, even if it would be empty\n"
1741 "\t--no-private-header Don't create a private header, "
1742 "put private structure inside c "
1747 parse_options(int argc, char *argv[])
1750 int got_file = FALSE;
1751 int no_opts = FALSE;
1755 for(i=1;i<argc;i++) {
1756 if(no_opts || argv[i][0]!='-') {
1759 fprintf(stderr,"Specify only one file!\n");
1765 } else if(strcmp(argv[i],"--help")==0) {
1768 } else if(strcmp(argv[i],"--exit-on-warn")==0) {
1769 exit_on_warn = TRUE;
1770 } else if(strcmp(argv[i],"--no-exit-on-warn")==0) {
1771 exit_on_warn = FALSE;
1772 } else if(strcmp(argv[i],"--for-cpp")==0) {
1774 } else if(strcmp(argv[i],"--no-touch-headers")==0) {
1775 no_touch_headers = TRUE;
1776 } else if(strcmp(argv[i],"--always-private-header")==0) {
1777 no_private_header = FALSE;
1778 always_private_header = TRUE;
1779 } else if(strcmp(argv[i],"--no-private-header")==0) {
1780 always_private_header = FALSE;
1781 no_private_header = TRUE;
1782 } else if(strcmp(argv[i],"--")==0) {
1783 /*further arguments are files*/
1785 } else if(strncmp(argv[i],"--",2)==0) {
1786 /*unknown long option*/
1787 fprintf(stderr,"Unknown option '%s'!\n",argv[i]);
1791 /*by now we know we have a string starting with
1792 - which is a short option string*/
1793 char *p = argv[i]+1;
1794 for(p=argv[i]+1;*p;p++) {
1805 "Unknown option '%c'!\n",*p);
1815 compare_and_move_header(void)
1817 char *hfnew = g_strconcat("#gob#",filebase,".h#gob#",NULL);
1818 char *hf = g_strconcat(filebase,".h",NULL);
1820 if(stat(hf,&s)==0) {
1822 s = g_strdup_printf("cmp '%s' '%s' > /dev/null",hf,hfnew);
1824 if(unlink(hfnew)!=0)
1825 print_error(FALSE,"Can't remove new header file",0);
1833 print_error(FALSE,"Can't remove old header file",0);
1835 if(rename(hfnew,hf)!=0)
1836 print_error(FALSE,"Can't rename new header file",0);
1842 main(int argc, char *argv[])
1848 struct poptOption optionsTable[] = {
1849 { "exit-on-warn", 'w', 0, &exit_on_warn, 0,
1850 "exit on warnings" },
1852 { NULL, 0, 0, NULL, 0 }
1855 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
1856 poptSetOtherOptionHelp(optCon, "[OPTIONS]* [filename]");
1858 while ((c = poptGetNextOpt(optCon)) >= 0)
1861 filename = poptGetArg(optCon);
1862 if(!(poptPeekArg(optCon) == NULL))
1863 usage(optCon, 1, "Specify only one file",
1864 ".e.g., filename.gob");
1867 /* an error occurred during option processing */
1868 fprintf(stderr, "%s: %s\n",
1869 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
1875 parse_options(argc,argv);
1878 yyin = fopen(filename,"r");
1880 fprintf(stderr,"Error: can't open file '%s'\n",
1889 g_error("Parsing errors, quitting");
1891 print_error(FALSE," no class defined",0);
1894 exit_on_error = FALSE;
1896 signals = count_signals((Class *)class);
1897 arguments = count_arguments((Class *)class);
1898 overrides = count_overrides((Class *)class);
1899 privates = count_privates((Class *)class);
1902 make_inits((Class *)class);
1904 make_destroy((Class *)class);
1905 check_bad_symbols((Class *)class);
1906 check_duplicate_symbols((Class *)class);
1907 check_duplicate_signals_args((Class *)class);
1908 check_public_new((Class *)class);
1909 check_vararg((Class *)class);
1910 check_firstarg((Class *)class);
1912 exit_on_error = TRUE;
1919 generate_outfiles();
1924 if(no_touch_headers)
1925 compare_and_move_header();
1928 poptFreeContext(optCon);