]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
Release 0.92.0
[gob-dx.git] / src / main.c
1 /* GOB C Preprocessor
2  * Copyright (C) 1999 the Free Software Foundation.
3  *
4  * Author: George Lebl
5  *
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.
10  *
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.
15  *
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,
19  * USA.
20  */
21
22 #include "config.h"
23 #include <glib.h>
24 #if 0
25 #include <popt.h>
26 #endif
27 #include <time.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32
33 #include "tree.h"
34 #include "parse.h"
35 #include "out.h"
36 #include "main.h"
37
38 char *filename = NULL;
39
40 int yyparse(void);
41
42 extern int yydebug;
43 extern FILE * yyin;
44 extern Node *class;
45 extern GList *nodes;
46
47 extern GList *include_files;
48
49 char *filebase;
50 static char *funcbase;
51 static char *pfuncbase;
52 static char *macrobase;
53 static char *macrois;
54 static char *macrotype;
55 static char *typebase;
56 static char *ptypebase;
57
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 methods */
61 static int privates = 0; /* number of private data members */
62 static int protecteds = 0; /* number of protected methods */
63
64 static gboolean made_aliases = FALSE;  /* if we made any shorthand aliases
65                                           and need the REALLY UGLY HACK to
66                                           avoid warnings */
67
68 FILE *out = NULL;
69 FILE *outh = NULL;
70 FILE *outph = NULL;
71
72 gboolean no_touch_headers = FALSE;
73 gboolean for_cpp = FALSE;
74 gboolean exit_on_warn = FALSE;
75 gboolean exit_on_error = TRUE;
76 gboolean got_error = FALSE;
77 gboolean always_private_header = FALSE;
78 gboolean no_private_header = FALSE;
79
80 void
81 print_error(int is_warn, char *error,int line)
82 {
83         char *w;
84         if(is_warn)
85                 w = "Warning:";
86         else {
87                 w = "Error:";
88                 got_error = TRUE;
89         }
90         if(line>0)
91                 fprintf(stderr,"%s:%d: %s %s\n",filename,line,w,error);
92         else
93                 fprintf(stderr,"%s: %s %s\n",filename,w,error);
94         if((!is_warn || exit_on_warn) && exit_on_error)
95                 exit(1);
96 }
97
98 static char *
99 remove_sep(char *base)
100 {
101         char *p;
102         char *s = g_strdup(base);
103         while((p=strchr(s,':')))
104                 strcpy(p,p+1);
105         return s;
106 }
107
108 static char *
109 replace_sep(char *base, char r)
110 {
111         char *p;
112         char *s = g_strdup(base);
113         while((p=strchr(s,':')))
114                 *p = r;
115         if(*s == r) {
116                 p = g_strdup(s+1);
117                 g_free(s);
118                 return p;
119         }
120         return s;
121 }
122
123 /*separate the namespace part and then replace rest of
124   separators with r*/
125 static void
126 separns_replace_sep(char *base, char **ns, char **name, char r)
127 {
128         char *p;
129         char *s = g_strdup(base);
130         *ns = NULL;
131         if((p=strchr(s,':')) && p!=s) {
132                 *p = '\0';
133                 *ns = g_strdup(s);
134                 p = g_strdup(p+1);
135                 g_free(s);
136                 s = p;
137         }
138         while((p=strchr(s,':')))
139                 *p = r;
140         if(*s == r) {
141                 *name = g_strdup(s+1);
142                 g_free(s);
143         } else
144                 *name = s;
145 }
146
147 /* make a macro with some prefix before the name but after
148    namespace */
149 static char *
150 make_pre_macro(char *base, char *pre)
151 {
152         char *s1,*s2;
153         char *s;
154
155         separns_replace_sep(base,&s1,&s2,'_');
156         if(s1)
157                 s = g_strconcat(s1,"_",pre,"_",s2,NULL);
158         else
159                 s = g_strconcat(pre,"_",s2,NULL);
160
161         g_strup(s);
162         
163         g_free(s1);
164         g_free(s2);
165
166         return s;
167 }
168
169 static void
170 make_bases(void)
171 {
172         filebase = replace_sep(((Class *)class)->otype,'-');
173         g_strdown(filebase);
174
175         funcbase = replace_sep(((Class *)class)->otype,'_');
176         g_strdown(funcbase);
177
178         pfuncbase = replace_sep(((Class *)class)->ptype,'_');
179         g_strdown(pfuncbase);
180
181         macrobase = replace_sep(((Class *)class)->otype,'_');
182         g_strup(macrobase);
183         
184         macrois = make_pre_macro(((Class *)class)->otype,"IS");
185         macrotype = make_pre_macro(((Class *)class)->otype,"TYPE");
186
187         typebase = remove_sep(((Class *)class)->otype);
188
189         ptypebase = remove_sep(((Class *)class)->ptype);
190 }
191
192 static void
193 print_type(FILE *fp, Type *t, gboolean postfix_to_stars)
194 {
195         char *s;
196         int i;
197         int extra;
198
199         s = remove_sep(t->name);
200         out_printf(fp,"%s ",s); 
201         g_free(s);
202
203         extra = 0;
204         if(postfix_to_stars) {
205                 char *p;
206                 /*XXX: this is ugly perhaps we can do this whole postfix thing
207                   in a nicer way, we just count the number of '[' s and from
208                   that we deduce the number of dimensions, so that we can print
209                   that many stars */
210                 for(p=t->postfix; p && *p; p++)
211                         if(*p == '[') extra++;
212         }
213         
214         for(i=0;i<(t->stars+extra);i++)
215                 out_printf(fp,"*"); 
216 }
217
218 static void
219 print_method(FILE *fp, char *typeprefix, char *nameprefix,
220              char *namepostfix,char *postfix, Method *m,
221              gboolean no_funcbase)
222 {
223         GList *li;
224
225         out_printf(fp,"%s",typeprefix); 
226         print_type(fp,m->mtype,TRUE);
227         if(no_funcbase)
228                 out_printf(fp,"%s%s%s(",
229                            nameprefix,m->id,namepostfix); 
230         else
231                 out_printf(fp,"%s%s_%s%s(",
232                            nameprefix,funcbase,m->id,namepostfix); 
233         
234         if(m->args) {
235                 for(li=m->args;li;li=g_list_next(li)) {
236                         FuncArg *arg = li->data;
237                         print_type(fp,arg->atype,FALSE);
238                         if(li->next)
239                                 out_printf(fp,"%s%s, ",arg->name,
240                                            arg->atype->postfix?
241                                            arg->atype->postfix:""); 
242                         else
243                                 out_printf(fp,"%s%s",arg->name,
244                                            arg->atype->postfix?
245                                            arg->atype->postfix:""); 
246                 }
247                 if(m->vararg)
248                         out_printf(fp,", ..."); 
249         } else {
250                 out_printf(fp,"void"); 
251         }
252         out_printf(fp,")%s",postfix); 
253 }
254
255
256 static void
257 make_method_pointers(Class *c)
258 {
259         GList *li;
260         
261         out_printf(out,"\n");
262         for(li=c->nodes;li;li=g_list_next(li)) {
263                 Node *node = li->data;
264                 if(node->type == METHOD_NODE) {
265                         Method *m = (Method *)node;
266                         
267                         if(m->method == INIT_METHOD ||
268                            m->method == CLASS_INIT_METHOD ||
269                            m->method == OVERRIDE_METHOD)
270                                 continue;
271
272                         /* in C++ mode don't alias new */
273                         if(for_cpp && strcmp(m->id,"new")==0)
274                                 continue;
275
276                         print_method(out,"static ","(* ",") ","",m,TRUE);
277                         out_printf(out," = %s_%s;\n",funcbase,m->id);
278
279                         made_aliases = TRUE;
280                 }
281         }
282         out_printf(out,"\n");
283 }
284
285 static void
286 add_bad_hack_to_avoid_unused_warnings(Class *c)
287 {
288         GList *li;
289
290         /* if we haven't had any methods, just return */
291         if(!made_aliases)
292                 return;
293         
294         out_printf(out,"\n\n/*REALLY BAD HACK\n"
295                    "  This is to avoid unused warnings if you don't call\n"
296                    "  some method.  I need to find a better way to do\n"
297                    "  this */\n");
298         out_printf(out,"static void\n"
299                    "__%s_really_bad_hack_to_avoid_warnings(void)\n"
300                    "{\n",funcbase);
301         for(li=c->nodes;li;li=g_list_next(li)) {
302                 Node *node = li->data;
303                 if(node->type == METHOD_NODE) {
304                         Method *m = (Method *)node;
305                         
306                         if(m->method == INIT_METHOD ||
307                            m->method == CLASS_INIT_METHOD ||
308                            m->method == OVERRIDE_METHOD)
309                                 continue;
310
311                         /* in C++ mode we don't alias new */
312                         if(for_cpp && strcmp(m->id,"new")==0)
313                                 continue;
314
315                         out_printf(out,"\t((void (*)(void))%s)();\n",m->id);
316                 }
317         }
318         out_printf(out, "\t__%s_really_bad_hack_to_avoid_warnings();\n",
319                    funcbase);
320         out_printf(out,"}\n\n");
321 }
322
323 static void
324 put_variable(Variable *v, FILE *fp)
325 {
326         out_printf(fp,"\t");
327         print_type(fp,v->vtype,FALSE);
328         out_printf(fp,"%s%s;",v->id,
329                    v->vtype->postfix?
330                    v->vtype->postfix:""); 
331         if(v->scope == PROTECTED_SCOPE)
332                 out_printf(fp," /* protected */");
333         out_printf(fp,"\n");
334 }
335
336 static void
337 put_vs_method(Method *m)
338 {
339         if(m->method != SIGNAL_LAST_METHOD &&
340            m->method != SIGNAL_FIRST_METHOD &&
341            m->method != VIRTUAL_METHOD)
342                 return;
343
344         print_method(outh,"\t","(* ",") ",";\n",m,TRUE);
345 }
346
347 static void
348 put_pub_method(Method *m)
349 {
350         if(m->scope != PUBLIC_SCOPE)
351                 return;
352
353         print_method(outh,"","\t","\t",";\n",m,FALSE);
354 }
355
356 static void
357 put_prot_method(Method *m)
358 {
359         if(m->scope != PROTECTED_SCOPE)
360                 return;
361
362         if(outph)
363                 print_method(outph,"","\t","\t",";\n",m,FALSE);
364         else
365                 print_method(out,"","\t","\t",";\n",m,FALSE);
366 }
367
368 static void
369 put_priv_method_prot(Method *m)
370 {
371         if(m->method == SIGNAL_LAST_METHOD ||
372            m->method == SIGNAL_FIRST_METHOD ||
373            m->method == VIRTUAL_METHOD) {
374                 if(m->cbuf)
375                         print_method(out,"static ","_real_"," ",";\n",m,FALSE);
376         }
377
378         if(m->scope == PRIVATE_SCOPE ||
379            m->method == INIT_METHOD ||
380            m->method == CLASS_INIT_METHOD ||
381            (m->method == OVERRIDE_METHOD &&
382             m->cbuf))
383                 print_method(out,"static ",""," ",";\n",m,FALSE);
384 }
385
386 static GList *
387 make_func_arg(char *typename, int is_class, char *name)
388 {
389         Node *node;
390         Node *type;
391         char *tn;
392         
393         if(is_class)
394                 tn = g_strconcat(typename,":Class",NULL);
395         else
396                 tn = g_strdup(typename);
397
398         type = new_type(1,tn,NULL);
399         node = new_funcarg((Type *)type,name,NULL);
400         return g_list_prepend(NULL, node);
401 }
402
403 static void
404 make_inits(Class *cl)
405 {
406         int got_class_init = FALSE;
407         int got_init = FALSE;
408         GList *li;
409         Node *node;
410         for(li=cl->nodes;li;li=g_list_next(li)) {
411                 Node *n = li->data;
412                 if(n->type == METHOD_NODE) {
413                         Method *m = (Method *)n;
414                         if(m->method == INIT_METHOD) {
415                                 if(got_init)
416                                         print_error(FALSE,"init defined more then once",m->line_no);
417                                 got_init = TRUE;
418                         } else if(m->method == CLASS_INIT_METHOD) {
419                                 if(got_class_init)
420                                         print_error(FALSE,"class_init defined more then once",m->line_no);
421                                 got_class_init = TRUE;
422                         }
423                 }
424         }
425         if(!got_class_init) {
426                 node = new_method(NO_SCOPE, CLASS_INIT_METHOD,
427                                   (Type *)new_type(0,g_strdup("void"),NULL),
428                                   NULL,NULL,g_strdup("class_init"),
429                                   make_func_arg(cl->otype,TRUE,g_strdup("c")),
430                                   NULL, NULL,0,0,FALSE);
431                 cl->nodes = g_list_prepend(cl->nodes,node);
432         }
433         if(!got_init) {
434                 node = new_method(NO_SCOPE, INIT_METHOD,
435                                   (Type *)new_type(0,g_strdup("void"),NULL),
436                                   NULL,NULL,g_strdup("init"),
437                                   make_func_arg(cl->otype,FALSE,g_strdup("o")),
438                                   NULL, NULL,0,0,FALSE);
439                 cl->nodes = g_list_prepend(cl->nodes,node);
440         }
441 }
442
443 static void
444 make_destroy(Class *cl)
445 {
446         int got_destroy = FALSE;
447         GList *li;
448         Node *node;
449         for(li=cl->nodes;li;li=g_list_next(li)) {
450                 Node *n = li->data;
451                 if(n->type == METHOD_NODE) {
452                         Method *m = (Method *)n;
453                         if(m->method == OVERRIDE_METHOD &&
454                            strcmp(m->id,"destroy")==0) {
455                                 if(strcmp(m->otype,"Gtk:Object")==0) {
456                                         got_destroy = TRUE;
457                                         break;
458                                 } else {
459                                         print_error(FALSE,"destroy method override "
460                                                     "of class other then Gtk:Object",
461                                                     m->line_no);
462                                 }
463
464                         }
465                 }
466         }
467         if(!got_destroy) {
468                 node = new_method(NO_SCOPE, OVERRIDE_METHOD,
469                                   (Type *)new_type(0,g_strdup("void"),NULL),
470                                   g_strdup("Gtk:Object"),
471                                   NULL,g_strdup("destroy"),
472                                   make_func_arg("Gtk:Object",FALSE,g_strdup("o")),
473                                   NULL,
474                                   g_strdup("PARENT_HANDLER (o);\n"),
475                                   0,0,FALSE);
476                 cl->nodes = g_list_append(cl->nodes,node);
477                 overrides++;
478         }
479 }
480
481 /* here we will find out how inconsistent gtk really is :) */
482 /* the commented out types mean that these types don't actually
483    exist. so we "emulate them" with an equivalent */
484 const struct {
485         char *gtkname;
486         char *typename;
487 } our_gtk_type_table[] = {
488         { "NONE",       "void" },
489         { "CHAR",       "gchar" },
490         { "UCHAR",      "guchar" },
491         { "BOOL",       "gboolean" },
492         { "INT",        "gint" },
493         { "UINT",       "guint" },
494         { "LONG",       "glong" },
495         { "ULONG",      "gulong" },
496         { "FLOAT",      "gfloat" },
497         { "DOUBLE",     "gdouble" },
498         { "STRING",     /*"GtkString"*/"gchar *" },
499         { "ENUM",       /*"GtkEnum"*/"gint" },
500         { "FLAGS",      /*"GtkFlags"*/"guint" },
501         { "BOXED",      /*"GtkBoxed"*/"gpointer" },
502         { "POINTER",    "gpointer" },
503         { "OBJECT",     "GtkObject *" },
504         { "SIGNAL",     /*"GtkSignal"*/"__twopointertype" },
505         { "ARGS",       /*"GtkArgs"*/"__twopointertype" },
506         { "CALLBACK",   /*"GtkCallback"*/"__threepointertype" },
507         { "C_CALLBACK", /*"GtkCCallback"*/"__twopointertype" },
508         { "FOREIGN",    /*"GtkForeign"*/"__twopointertype" },
509
510         { NULL, NULL }
511 };
512
513 static const char *
514 get_cast(char *type)
515 {
516         int i;
517         for(i=0;our_gtk_type_table[i].gtkname;i++) {
518                 if(strcmp(our_gtk_type_table[i].gtkname,type)==0) {
519                         return our_gtk_type_table[i].typename;
520                 }
521         }
522         return NULL;
523 }
524
525
526 /* hash of method -> name of signal prototype */
527 static GHashTable *marsh = NULL;
528
529 /* list of methods with different signal prototypes,
530    we check this list if we can use a signal prototype of a
531    previous signal method, there are only uniques here */
532 static GList *eq_signal_methods = NULL;
533
534 /* compare a list of strings */
535 static gboolean
536 is_list_equal(GList *a, GList *b)
537 {
538         for(;a && b; a=a->next, b=b->next) {
539                 if(strcmp(a->data,b->data)!=0) {
540                         return FALSE;
541                 }
542         }
543         /* the the lists were different length */
544         if(a || b)
545                 return FALSE;
546         return TRUE;
547 }
548
549 static Method *
550 find_same_type_signal(Method *m)
551 {
552         GList *li;
553         for(li=eq_signal_methods;li;li=li->next) {
554                 Method *mm = li->data;
555                 if(is_list_equal(mm->gtktypes,m->gtktypes))
556                         return mm;
557         }
558         return NULL;
559 }
560
561 static void
562 print_signal_marsal_args(Method *m)
563 {
564         if(strcmp(m->gtktypes->next->data,"NONE")!=0) {
565                 GList *li;
566                 int i;
567                 for(i=0,li=m->gtktypes->next;li;
568                     i++,li=g_list_next(li)) {
569                         if(!for_cpp)
570                                 out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
571                                            (char *)li->data,i);
572                         else {
573                                 out_printf(out, ",\n\t\t(%s)"
574                                            "GTK_VALUE_%s(args[%d])",
575                                            get_cast(li->data),
576                                            (char *)li->data,i);
577                         }
578                 }
579         }
580         out_printf(out, ",\n\t\tfunc_data);\n}\n\n");
581 }
582
583
584 static void
585 add_signal_prots(Method *m)
586 {
587         GList *li;
588         static int sig = 1;
589         char *s;
590         Method *mm;
591         
592         if(m->method != SIGNAL_LAST_METHOD &&
593            m->method != SIGNAL_FIRST_METHOD)
594                 return;
595
596         if(!marsh)
597                 marsh = g_hash_table_new(NULL,NULL);
598         
599         if(strcmp(m->gtktypes->data,"NONE")==0 &&
600            strcmp(m->gtktypes->next->data,"NONE")==0)
601                 return;
602
603         /* if we already did a signal prototype just use that */
604         mm = find_same_type_signal(m);
605         if(mm) {
606                 s = g_hash_table_lookup(marsh,mm);
607                 g_hash_table_insert(marsh,m,s);
608                 return;
609         }
610         
611         s = g_strdup_printf("__Sig%d",sig++);
612         
613         g_hash_table_insert(marsh,m,s);
614         eq_signal_methods = g_list_prepend(eq_signal_methods,m);
615         
616         /* we know that we'll know all the gtktypes (so get_cast can't fail) */
617         out_printf(out,"\ntypedef %s (*%s) (%s *, ",
618                    get_cast(m->gtktypes->data),s, typebase);
619         
620         for(li=m->gtktypes->next;li;li=g_list_next(li))
621                 out_printf(out,"%s, ",get_cast(li->data));
622         out_printf(out,"gpointer);\n"); 
623         
624         out_printf(out,"\nstatic void\n"
625                 "marshal_%s (GtkObject * object,\n"
626                 "\tGtkSignalFunc func,\n"
627                 "\tgpointer func_data,\n"
628                 "\tGtkArg * args)\n"
629                 "{\n",s);
630         
631         if(strcmp(m->gtktypes->data,"NONE")==0) {
632                 out_printf(out, "\t%s rfunc;\n\n"
633                         "\trfunc = (%s)func;\n\n"
634                         "\t(*rfunc)((%s *)object",s,s,typebase);
635         } else {
636                 out_printf(out, "\t%s rfunc;\n\t",s);
637                 print_type(out,m->mtype,TRUE);
638                 out_printf(out, " *retval;\n\n"
639                         "\trfunc = (%s)func;\n\n"
640                         "\tretval = GTK_RETLOC_%s(args[%d]);\n\n"
641                         "\t*retval = (*rfunc)((%s *)object",
642                         s,(char *)m->gtktypes->data,
643                         g_list_length(m->gtktypes)-1,typebase);
644         }
645         print_signal_marsal_args(m);
646
647 }
648
649 static void
650 add_enums(Class *c)
651 {
652         GList *li;
653         out_printf(out,"\n");
654         if(signals>0) {
655                 out_printf(out,"enum {\n");
656                 for(li=c->nodes;li;li=g_list_next(li)) {
657                         Node *n = li->data;
658                         if(n->type == METHOD_NODE) {
659                                 Method *m = (Method *)n;
660                                 if(m->method == SIGNAL_LAST_METHOD ||
661                                    m->method == SIGNAL_FIRST_METHOD) {
662                                         char *s = g_strdup(m->id);
663                                         g_strup(s);
664                                         out_printf(out,"\t%s_SIGNAL,\n",s);
665                                         g_free(s);
666                                 }
667                         }
668                 }
669                 out_printf(out,"\tLAST_SIGNAL\n};\n\n");
670         }
671         if(arguments>0) {
672                 out_printf(out,"enum {\n\tARG_0,\n");
673                 for(li=c->nodes;li;li=g_list_next(li)) {
674                         Node *n = li->data;
675                         if(n->type == ARGUMENT_NODE) {
676                                 Argument *a = (Argument *)n;
677                                 char *s = g_strdup(a->name);
678                                 g_strup(s);
679                                 out_printf(out,"\tARG_%s,\n",s);
680                                 g_free(s);
681                         }
682                 }
683                 out_printf(out, "};\n\n");
684         }
685
686         if(signals>0)
687                 out_printf(out,
688                            "static guint object_signals[LAST_SIGNAL] = {0};\n\n");
689
690         out_printf(out, "static %sClass *parent_class = NULL;\n\n",ptypebase);
691 }
692
693 static void
694 add_get_type(void)
695 {
696         out_printf(out, "guint\n"
697                 "%s_get_type (void)\n"
698                 "{\n"
699                 "\tstatic guint type = 0;\n\n"
700                 "\tif (!type) {\n"
701                 "\t\tstatic const GtkTypeInfo info = {\n"
702                 "\t\t\t\"%s\",\n"
703                 "\t\t\tsizeof (%s),\n"
704                 "\t\t\tsizeof (%sClass),\n"
705                 "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
706                 "\t\t\t(GtkObjectInitFunc) %s_init,\n"
707                 "\t\t\t/* reserved_1 */ NULL,\n"
708                 "\t\t\t/* reserved_2 */ NULL,\n"
709                 "\t\t\t(GtkClassInitFunc) NULL,\n"
710                 "\t\t};\n\n"
711                 "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n"
712                 "\t}\n\n"
713                 "\treturn type;\n"
714                 "}\n\n",
715                 funcbase,typebase,typebase,typebase,
716                 funcbase,funcbase,pfuncbase);
717 }
718
719 static void
720 add_overrides(Class *c, char *oname, gboolean did_gtk_obj)
721 {
722         GList *li;
723         GHashTable *done;
724         char *s;
725         
726         done = g_hash_table_new(g_str_hash,g_str_equal);
727         if(did_gtk_obj) {
728                 s = g_strdup("GtkObject"); /* This was already done */
729                 g_hash_table_insert(done,s,s);
730         }
731         for(li=c->nodes;li;li=g_list_next(li)) {
732                 Node *n = li->data;
733                 char *f;
734                 Method *m = (Method *)n;
735                 if(n->type != METHOD_NODE ||
736                    m->method != OVERRIDE_METHOD)
737                         continue;
738                 
739                 s = remove_sep(m->otype);
740                 
741                 if(g_hash_table_lookup(done,s)) {
742                         g_free(s);
743                         continue;
744                 }
745                 g_hash_table_insert(done,s,s);
746
747                 f = replace_sep(m->otype,'_');
748                 g_strdown(f);
749
750                 out_printf(out,"\t%sClass *%s_class = (%sClass *)%s;\n",
751                         s,f,s,oname);
752                 
753                 g_free(f);
754         }
755         g_hash_table_foreach(done,(GHFunc)g_free,NULL);
756         g_hash_table_destroy(done);
757 }
758
759 static void
760 add_signals(Class *c)
761 {
762         GList *li;
763
764         out_printf(out,"\n");
765         for(li=c->nodes;li;li=g_list_next(li)) {
766                 Node *n = li->data;
767                 char *mar;
768                 char *sig;
769                 int is_none;
770                 int last = FALSE;
771                 Method *m = (Method *)n;
772                 if(n->type != METHOD_NODE ||
773                    (m->method != SIGNAL_FIRST_METHOD &&
774                     m->method != SIGNAL_LAST_METHOD))
775                         continue;
776
777                 
778                 if(m->method == SIGNAL_FIRST_METHOD)
779                         last = FALSE;
780                 else
781                         last = TRUE;
782
783                 if(g_hash_table_lookup(marsh,m))
784                         mar = g_strconcat("marshal_",
785                                           (char *)g_hash_table_lookup(marsh,m),
786                                           NULL);
787                 else
788                         mar = g_strdup("gtk_signal_default_marshaller");
789                 
790                 is_none = (strcmp(m->gtktypes->next->data,"NONE")==0);
791                 
792                 sig = g_strdup(m->id);
793                 g_strup(sig);
794                 out_printf(out,"\tobject_signals[%s_SIGNAL] =\n"
795                         "\t\tgtk_signal_new (\"%s\",\n"
796                         "\t\t\tGTK_RUN_%s,\n"
797                         "\t\t\tgtk_object_class->type,\n"
798                         "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n"
799                         "\t\t\t%s,\n"
800                         "\t\t\tGTK_TYPE_%s, %d",
801                         sig,m->id,
802                         last?"LAST":"FIRST",
803                         typebase,m->id,mar,(char *)m->gtktypes->data,
804                         is_none?0:g_list_length(m->gtktypes->next));
805                 g_free(mar);
806                 g_free(sig);
807                 
808                 if(!is_none) {
809                         GList *l;
810                         for(l=m->gtktypes->next;l;l=g_list_next(l))
811                                 out_printf(out,",\n\t\t\tGTK_TYPE_%s",
812                                         (char *)l->data);
813                 }
814
815                 out_printf(out,");\n");
816         }
817         out_printf(out,"\tgtk_object_class_add_signals (gtk_object_class,\n"
818                 "\t\tobject_signals, LAST_SIGNAL);\n\n");
819 }
820
821 static void
822 set_def_handlers(Class *c, char *oname)
823 {
824         GList *li;
825
826         out_printf(out,"\n");
827         for(li=c->nodes;li;li=g_list_next(li)) {
828                 Node *n = li->data;
829                 Method *m = (Method *)n;
830                 if(n->type != METHOD_NODE ||
831                    (m->method != SIGNAL_FIRST_METHOD &&
832                     m->method != SIGNAL_LAST_METHOD &&
833                     m->method != VIRTUAL_METHOD &&
834                     m->method != OVERRIDE_METHOD))
835                         continue;
836
837
838                 if(m->method == OVERRIDE_METHOD) {
839                         char *s;
840                         s = replace_sep(m->otype,'_');
841                         g_strdown(s);
842                         if(m->cbuf)
843                                 out_printf(out,"\t%s_class->%s = %s_%s;\n",
844                                            s,m->id,funcbase,m->id);
845                         else
846                                 out_printf(out,"\t%s_class->%s = NULL;\n",
847                                            s,m->id);
848                 } else {
849                         if(m->cbuf)
850                                 out_printf(out,"\t%s->%s = _real_%s_%s;\n",
851                                         oname,m->id,funcbase,m->id);
852                         else
853                                 out_printf(out,"\t%s->%s = NULL;\n",
854                                         oname,m->id);
855                 }
856         }
857 }
858
859 static void
860 make_arguments(Class *c)
861 {
862         GList *li;
863
864         out_printf(out,"\n");
865         for(li=c->nodes;li;li=g_list_next(li)) {
866                 Node *n = li->data;
867                 Argument *a;
868                 GString *flags;
869                 GList *l;
870                 char *s;
871                 if(n->type != ARGUMENT_NODE)
872                         continue;
873
874                 a = (Argument *)n;
875                 
876                 if(a->get && a->set)
877                         flags = g_string_new("GTK_ARG_READWRITE");
878                 else if(a->get)
879                         flags = g_string_new("GTK_ARG_READABLE");
880                 else
881                         flags = g_string_new("GTK_ARG_WRITABLE");
882                 
883                 for(l=a->flags;l;l=g_list_next(l))
884                         g_string_sprintfa(flags," | GTK_ARG_%s",(char *)l->data);
885
886                 s = g_strdup(a->name);
887                 g_strup(s);
888                 out_printf(out,"\tgtk_object_add_arg_type(\"%s::%s\",\n"
889                         "\t\tGTK_TYPE_%s,\n"
890                         "\t\t%s,\n"
891                         "\t\tARG_%s);\n",
892                         typebase,a->name,a->gtktype,flags->str,s);
893                 g_free(s);
894                 g_string_free(flags,TRUE);
895         }
896         
897         out_printf(out,
898                    "\n\tgtk_object_class->set_arg = __object_set_arg;\n"
899                    "\tgtk_object_class->get_arg = __object_get_arg;\n");
900 }
901
902 static void
903 add_inits(Class *c)
904 {
905         GList *li;
906         for(li=c->nodes;li;li=g_list_next(li)) {
907                 Node *n = li->data;
908                 Method *m;
909                 if(n->type != METHOD_NODE)
910                         continue;
911                 m = (Method *)n;
912                 if(m->method == INIT_METHOD) {
913                         if(m->line_no>0)
914                                 out_addline_infile(out,m->line_no);
915                         print_method(out,"static ","\n"," ","\n",m,FALSE);
916                         if(m->line_no>0)
917                                 out_addline_outfile(out);
918                         out_printf(out,"{\n");
919                         if(privates>0) {
920                                 out_printf(out,"\t%s->_priv = "
921                                            "g_new0 (%sPrivate,1);\n",
922                                            ((FuncArg *)m->args->data)->name,
923                                            typebase);
924                         }
925                 } else if(m->method == CLASS_INIT_METHOD) {
926                         if(m->line_no>0)
927                                 out_addline_infile(out,m->line_no);
928                         print_method(out,"static ","\n"," ","\n",m,FALSE);
929                         if(m->line_no>0)
930                                 out_addline_outfile(out);
931                         out_printf(out,"{\n");
932                         if(signals>0 ||
933                            arguments>0)
934                                 out_printf(out,
935                                            "\tGtkObjectClass *"
936                                            "gtk_object_class = "
937                                            "(GtkObjectClass*) %s;\n",
938                                            ((FuncArg *)m->args->data)->name);
939
940                         if(overrides>0)
941                                 add_overrides(c,
942                                               ((FuncArg *)m->args->data)->name,
943                                               (signals>0 || arguments>0));
944                         
945                         out_printf(out,"\n\tparent_class = ");
946                         if(for_cpp)
947                                 out_printf(out,"(%sClass *)",ptypebase);
948                         out_printf(out,"gtk_type_class (%s_get_type ());\n",
949                                    pfuncbase);
950
951                         if(signals>0)
952                                 add_signals(c);
953
954                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
955                         
956                         if(arguments>0)
957                                 make_arguments(c);
958
959                 } else
960                         continue;
961
962                 if(m->cbuf) {
963                         out_printf(out," {\n");
964                         out_addline_infile(out,m->ccode_line);
965                         out_printf(out,"%s\n",m->cbuf);
966                         out_addline_outfile(out);
967                         out_printf(out," }\n");
968                 } else {
969                         out_printf(out,"return;\n");
970                 }
971                 out_printf(out,"}\n");
972         }
973 }
974
975 static void
976 add_getset_arg(Class *c, int is_set)
977 {
978         GList *li;
979         out_printf(out,"\nstatic void\n"
980                 "__object_%s_arg (GtkObject *object,\n"
981                 "\tGtkArg *arg,\n"
982                 "\tguint arg_id)\n"
983                 "{\n"
984                 "\t%s *self;\n\n"
985                 "\tself = %s (object);\n\n"
986                 "\tswitch (arg_id) {\n",
987                 is_set?"set":"get",typebase,macrobase);
988
989         for(li=c->nodes;li;li=g_list_next(li)) {
990                 Node *n = li->data;
991                 Argument *a;
992                 char *s;
993                 char *cbuf;
994                 int line_no;
995                 if(n->type != ARGUMENT_NODE)
996                         continue;
997                 a = (Argument *)n;
998                 if(is_set) {
999                         cbuf = a->set;
1000                         line_no = a->set_line;
1001                 } else {
1002                         cbuf = a->get;
1003                         line_no = a->get_line;
1004                 }
1005                 if(!cbuf)
1006                         continue;
1007                 s = g_strdup(a->name);
1008                 g_strup(s);
1009                 out_printf(out,"\tcase ARG_%s:\n"
1010                         "#define ARG (GTK_VALUE_%s(*arg))\n"
1011                         "\t\t{\n",
1012                         s,a->gtktype);
1013                 g_free(s);
1014                 out_addline_infile(out,line_no);
1015                 out_printf(out,"%s\n",cbuf);
1016                 out_addline_outfile(out);
1017                 out_printf(out,"\t\t}\n\t\tbreak;\n"
1018                         "#undef ARG\n");
1019         }
1020         out_printf(out,"\tdefault:\n\t\tbreak;\n\t}\n}\n");
1021 }
1022
1023 static void
1024 print_checks(Method *m, FuncArg *fa)
1025 {
1026         GList *li;
1027         gboolean is_void;
1028         is_void = (strcmp(m->mtype->name,"void")==0 &&
1029                    m->mtype->stars == 0);
1030         
1031         for(li=fa->checks;li;li=g_list_next(li)) {
1032                 Check *ch = li->data;
1033                 char *s;
1034                 if(is_void)
1035                         out_printf(out,"\tg_return_if_fail (");
1036                 else
1037                         out_printf(out,"\tg_return_val_if_fail (");
1038                 switch(ch->chtype) {
1039                 case NULL_CHECK:
1040                         out_printf(out,"%s != NULL",fa->name);
1041                         break;
1042                 case TYPE_CHECK:
1043                         s = make_pre_macro(fa->atype->name,"IS");
1044                         out_printf(out,"%s (%s)",s,fa->name);
1045                         g_free(s);
1046                         break;
1047                 case LT_CHECK:
1048                         out_printf(out,"%s < %s",fa->name,ch->number);
1049                         break;
1050                 case GT_CHECK:
1051                         out_printf(out,"%s > %s",fa->name,ch->number);
1052                         break;
1053                 case LE_CHECK:
1054                         out_printf(out,"%s <= %s",fa->name,ch->number);
1055                         break;
1056                 case GE_CHECK:
1057                         out_printf(out,"%s >= %s",fa->name,ch->number);
1058                         break;
1059                 case EQ_CHECK:
1060                         out_printf(out,"%s == %s",fa->name,ch->number);
1061                         break;
1062                 case NE_CHECK:
1063                         out_printf(out,"%s != %s",fa->name,ch->number);
1064                         break;
1065                 }
1066                 if(is_void)
1067                         out_printf(out,");\n");
1068                 else {
1069                         out_printf(out,", (");
1070                         print_type(out,m->mtype,TRUE);
1071                         out_printf(out,")%s);\n",
1072                                 m->onerror?m->onerror:"0");
1073                 }
1074         }
1075 }
1076
1077 static void
1078 print_preconditions(Method *m)
1079 {
1080         GList *li;
1081         
1082         for(li=m->args;li;li=g_list_next(li)) {
1083                 FuncArg *fa = li->data;
1084                 if(fa->checks)
1085                         print_checks(m,fa);
1086         }
1087 }
1088
1089 /* put in code if it's needed */
1090 static void
1091 put_in_gen_code(Method *m)
1092 {
1093         /* now we only have the freeing of the private structure */
1094         if(privates>0 &&
1095            m->method == OVERRIDE_METHOD &&
1096            strcmp(m->id,"destroy")==0) {
1097                 out_printf(out,"\tg_free (%s (%s)->_priv);\n"
1098                            "\t%s (%s)->_priv = NULL;\n",
1099                            macrobase,
1100                            ((FuncArg *)m->args->data)->name,
1101                            macrobase,
1102                            ((FuncArg *)m->args->data)->name);
1103
1104         }
1105 }
1106
1107 static void
1108 print_method_body(Method *m, int pre)
1109 {
1110         out_printf(out,"{\n");
1111         if(pre)
1112                 print_preconditions(m);
1113         put_in_gen_code(m);
1114
1115         /* Note: the trailing }'s are on one line, this is so
1116            that we get the no return warning correctly and point to
1117            the correct line in the .gob file, yes this is slightly
1118            ugly in the .c file, but that is not supposed to be
1119            human readable anyway. */
1120         if(m->cbuf) {
1121                 out_printf(out,"{\n");
1122                 out_addline_infile(out,m->ccode_line);
1123                 out_printf(out,"\t%s}",m->cbuf);
1124         }
1125
1126         out_printf(out,"}\n");
1127
1128         if(m->cbuf)
1129                 out_addline_outfile(out);
1130 }
1131
1132 static void
1133 put_signal_args(Method *m)
1134 {
1135         GList *li;
1136         GList *ali;
1137         for(ali = m->gtktypes->next,li=m->args->next;
1138             li && ali;
1139             li=li->next, ali=ali->next) {
1140                 FuncArg *fa = li->data;
1141                 const char *cast = get_cast(ali->data);
1142                 /* we should have already proved before that
1143                    the we know all the types */
1144                 g_assert(cast);
1145
1146                 out_printf(out,",\n\t\t(%s)%s",cast,
1147                            fa->name);
1148         }
1149 }
1150
1151 static void
1152 put_method(Method *m)
1153 {
1154         char *s;
1155         gboolean is_void;
1156         is_void = (strcmp(m->mtype->name,"void")==0 &&
1157                    m->mtype->stars == 0);
1158         out_printf(out,"\n");
1159         switch(m->method) {
1160         case REGULAR_METHOD:
1161                 out_addline_infile(out,m->line_no);
1162                 if(m->scope == PRIVATE_SCOPE)
1163                         print_method(out,"static ","\n"," ","\n",m,FALSE);
1164                 else /* PUBLIC, PROTECTED */
1165                         print_method(out,"","\n"," ","\n",m,FALSE);
1166                 print_method_body(m,TRUE);
1167                 break;
1168         case SIGNAL_FIRST_METHOD:
1169         case SIGNAL_LAST_METHOD:
1170                 out_addline_infile(out,m->line_no);
1171                 if(m->scope == PRIVATE_SCOPE)
1172                         print_method(out,"static ","\n"," ","\n",m,FALSE);
1173                 else
1174                         print_method(out,"","\n"," ","\n",m,FALSE);
1175                 out_addline_outfile(out);
1176                 out_printf(out,"{\n");
1177                 s = g_strdup(m->id);
1178                 g_strup(s);
1179                 if(strcmp(m->mtype->name,"void")==0 &&
1180                    m->mtype->stars==0) {
1181                         print_preconditions(m);
1182                         if(((FuncArg *)m->args->data)->name)
1183                         out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1184                                 "\t\tobject_signals[%s_SIGNAL]",
1185                                 ((FuncArg *)m->args->data)->name,s);
1186                         put_signal_args(m);
1187                         out_printf(out,");\n}\n");
1188                 } else {
1189                         out_printf(out,"\t");
1190                         print_type(out,m->mtype,TRUE);
1191                         out_printf(out,"return_val;\n");
1192                         print_preconditions(m);
1193                         out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1194                                 "\t\tobject_signals[%s_SIGNAL]",
1195                                 ((FuncArg *)m->args->data)->name,s);
1196                         put_signal_args(m);
1197                         out_printf(out,",\n\t\t&return_val);\n"
1198                                 "\treturn return_val;\n}\n");
1199                 }
1200
1201                 if(!m->cbuf)
1202                         break;
1203                 out_addline_infile(out,m->line_no);
1204                 print_method(out,"static ","\n_real_"," ","\n",m,FALSE);
1205                 print_method_body(m,FALSE);
1206                 break;
1207         case VIRTUAL_METHOD:
1208                 out_addline_infile(out,m->line_no);
1209                 if(m->scope==PRIVATE_SCOPE)
1210                         print_method(out,"static ","\n"," ","\n",m,FALSE);
1211                 else
1212                         print_method(out,"","\n"," ","\n",m,FALSE);
1213                 out_addline_outfile(out);
1214                 out_printf(out,"{\n"
1215                         "\t%sClass *klass;\n",typebase);
1216                 print_preconditions(m);
1217                 out_printf(out,"\tklass = %s_CLASS(GTK_OBJECT(%s)->klass);\n\n"
1218                         "\tif(klass->%s)\n",
1219                         macrobase, ((FuncArg *)m->args->data)->name, m->id);
1220                 if(strcmp(m->mtype->name,"void")==0 &&
1221                    m->mtype->stars==0) {
1222                         GList *li;
1223                         out_printf(out,"\t\t(*klass->%s)(%s",m->id,
1224                                    ((FuncArg *)m->args->data)->name);
1225                         for(li=m->args->next;li;li=g_list_next(li)) {
1226                                 FuncArg *fa = li->data;
1227                                 out_printf(out,",%s",fa->name);
1228                         }
1229                         out_printf(out,");\n}\n");
1230                 } else {
1231                         GList *li;
1232                         out_printf(out,"\t\treturn (*klass->%s)(%s",m->id,
1233                                    ((FuncArg *)m->args->data)->name);
1234                         for(li=m->args->next;li;li=g_list_next(li)) {
1235                                 FuncArg *fa = li->data;
1236                                 out_printf(out,",%s",fa->name);
1237                         }
1238                         out_printf(out,");\n"
1239                                 "\telse\n"
1240                                 "\t\treturn (");
1241                         print_type(out,m->mtype,TRUE);
1242                         out_printf(out,")(%s);\n}\n",
1243                                 m->onerror?m->onerror:"0");
1244                 }
1245
1246                 if(!m->cbuf)
1247                         break;
1248                 out_addline_infile(out,m->line_no);
1249                 print_method(out,"static ","\n_real_"," ","\n",m,FALSE);
1250                 print_method_body(m,FALSE);
1251                 break;
1252         case OVERRIDE_METHOD:
1253                 if(!m->cbuf)
1254                         break;
1255                 out_addline_infile(out,m->line_no);
1256                 print_method(out,"static ","\n"," ","\n",m,FALSE);
1257                 s = replace_sep(m->otype,'_');
1258                 g_strup(s);
1259                 if(is_void) {
1260                         out_printf(out,"#define PARENT_HANDLER(args...) \\\n"
1261                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
1262                                    "\t\t(* %s_CLASS(parent_class)->%s)(##args); }\n",
1263                                    s,m->id,s,m->id);
1264                 } else {
1265                         out_printf(out,"#define PARENT_HANDLER(args...) \\\n"
1266                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
1267                                    "\t\t(* %s_CLASS(parent_class)->%s)(##args): \\\n"
1268                                    "\t\t(",
1269                                    s,m->id,s,m->id);
1270                         out_printf(out,"(");
1271                         print_type(out,m->mtype,TRUE);
1272                         out_printf(out,")%s))\n",
1273                                    m->onerror?m->onerror:"0");
1274                 }
1275                 g_free(s);
1276                 print_method_body(m,TRUE);
1277                 out_printf(out,"#undef PARENT_HANDLER\n");
1278                 break;
1279         default:
1280                 break;
1281         }
1282 }
1283
1284 static void
1285 check_duplicate(Class *c, Node *node, char *id, int line_no)
1286 {
1287         GList *l;
1288         for(l=c->nodes;l;l=g_list_next(l)) {
1289                 Node *n = l->data;
1290                 char *nid;
1291                 int nline_no;
1292                 char *s;
1293                 if(n->type == METHOD_NODE) {
1294                         Method *m = (Method *)n;
1295                         nid = m->id;
1296                         nline_no = m->line_no;
1297                 } else if(n->type == VARIABLE_NODE) {
1298                         Variable *v = (Variable *)n;
1299                         nid = v->id;
1300                         nline_no = v->line_no;
1301                 } else
1302                         continue;
1303                 if(n==node ||
1304                    line_no>=nline_no ||
1305                    strcmp(nid,id)!=0 ||
1306                    n->type != node->type)
1307                         continue;
1308                 s = g_strdup_printf("symbol '%s' redefined, "
1309                                     "first defined on line %d",
1310                                     id,line_no);
1311                 print_error(FALSE,s,nline_no);
1312         }
1313 }
1314
1315 static void
1316 check_duplicate_symbols(Class *c)
1317 {
1318         GList *l;
1319         for(l=c->nodes;l;l=g_list_next(l)) {
1320                 Node *n = l->data;
1321                 if(n->type == METHOD_NODE) {
1322                         Method *m = (Method *)n;
1323                         check_duplicate(c,n,m->id,m->line_no);
1324                 } else if(n->type == VARIABLE_NODE) {
1325                         Variable *v = (Variable *)n;
1326                         check_duplicate(c,n,v->id,v->line_no);
1327                 }
1328         }
1329 }
1330
1331 static void
1332 check_bad_symbols(Class *c)
1333 {
1334         GList *l;
1335         for(l=c->nodes;l;l=g_list_next(l)) {
1336                 Node *n = l->data;
1337                 if(n->type == METHOD_NODE) {
1338                         Method *m = (Method *)n;
1339                         if((m->method == SIGNAL_LAST_METHOD ||
1340                             m->method == SIGNAL_FIRST_METHOD ||
1341                             m->method == VIRTUAL_METHOD) &&
1342                            strcmp(m->id,"__parent__")==0) {
1343                                 char *s;
1344                                 s = g_strdup_printf("'%s' not allowed as an "
1345                                                     "identifier of signal "
1346                                                     "or virtual methods",
1347                                                     m->id);
1348                                 print_error(FALSE,s,m->line_no);
1349                                 g_free(s);
1350                         }
1351                 } else if(n->type == VARIABLE_NODE) {
1352                         Variable *v = (Variable *)n;
1353                         if(strcmp(v->id,"_priv")==0 ||
1354                            strcmp(v->id,"__parent__")==0) {
1355                         char *s;
1356                                 s = g_strdup_printf("'%s' not allowed as a data "
1357                                                     "member name",v->id);
1358                                 print_error(FALSE,s,v->line_no);
1359                                 g_free(s);
1360                         }
1361                 }
1362         }
1363 }
1364
1365
1366 static void
1367 check_duplicate_named(Class *c,Node *node,char *id, int line_no)
1368 {
1369         GList *l;
1370         for(l=c->nodes;l;l=g_list_next(l)) {
1371                 Node *n = l->data;
1372                 char *nid;
1373                 int nline_no;
1374                 char *s;
1375                 if(n->type == METHOD_NODE) {
1376                         Method *m = (Method *)n;
1377                         if(m->method == SIGNAL_LAST_METHOD ||
1378                            m->method == SIGNAL_FIRST_METHOD) {
1379                                 nid = m->id;
1380                                 nline_no = m->line_no;
1381                         } else
1382                                 continue;
1383                 } else if(n->type == ARGUMENT_NODE) {
1384                         Argument *a = (Argument *)n;
1385                         nid = a->name;
1386                         nline_no = a->line_no;
1387                 } else
1388                         continue;
1389                 if(n==node ||
1390                    line_no>=nline_no ||
1391                    strcmp(nid,id)!=0)
1392                         continue;
1393                 s = g_strdup_printf("named symbol (argument or signal) '%s' "
1394                                     "redefined, first defined on line %d",
1395                                     id,line_no);
1396                 print_error(FALSE,s,nline_no);
1397         }
1398 }
1399
1400 static void
1401 check_duplicate_signals_args(Class *c)
1402 {
1403         GList *l;
1404         for(l=c->nodes;l;l=g_list_next(l)) {
1405                 Node *n = l->data;
1406                 if(n->type == METHOD_NODE) {
1407                         Method *m = (Method *)n;
1408                         if(m->method == SIGNAL_LAST_METHOD ||
1409                            m->method == SIGNAL_FIRST_METHOD)
1410                                 check_duplicate_named(c,n,m->id,m->line_no);
1411                 } else if(n->type == ARGUMENT_NODE) {
1412                         Argument *a = (Argument *)n;
1413                         check_duplicate_named(c,n,a->name,a->line_no);
1414                 }
1415         }
1416 }
1417
1418 static void
1419 check_public_new(Class *c)
1420 {
1421         GList *l;
1422         for(l=c->nodes;l;l=g_list_next(l)) {
1423                 Node *n = l->data;
1424                 if(n->type == METHOD_NODE) {
1425                         Method *m = (Method *)n;
1426                         if((strcmp(m->id,"new")==0) &&
1427                            (m->method != REGULAR_METHOD ||
1428                             m->scope != PUBLIC_SCOPE))
1429                                 print_error(TRUE,
1430                                             "'new' should be a regular\n"
1431                                             "public method",
1432                                             m->line_no);
1433                 }
1434         }
1435 }
1436
1437 static void
1438 check_vararg(Class *c)
1439 {
1440         GList *l;
1441         for(l=c->nodes;l;l=g_list_next(l)) {
1442                 Node *n = l->data;
1443                 if(n->type == METHOD_NODE) {
1444                         Method *m = (Method *)n;
1445                         if(!m->vararg)
1446                                 continue;
1447                         if(m->method == OVERRIDE_METHOD ||
1448                            m->method == SIGNAL_LAST_METHOD ||
1449                            m->method == SIGNAL_FIRST_METHOD ||
1450                            m->method == VIRTUAL_METHOD) {
1451                                 print_error(FALSE,
1452                                             "signals, overrides and virtuals, "
1453                                             "can't have variable argument "
1454                                             "lists",
1455                                             m->line_no);
1456                         }
1457                 }
1458         }
1459 }
1460
1461 static void
1462 check_firstarg(Class *c)
1463 {
1464         GList *l;
1465         for(l=c->nodes;l;l=g_list_next(l)) {
1466                 Node *n = l->data;
1467                 if(n->type == METHOD_NODE) {
1468                         Method *m = (Method *)n;
1469                         if(m->args)
1470                                 continue;
1471                         if(m->method == OVERRIDE_METHOD ||
1472                            m->method == SIGNAL_LAST_METHOD ||
1473                            m->method == SIGNAL_FIRST_METHOD ||
1474                            m->method == VIRTUAL_METHOD) {
1475                                 print_error(FALSE,
1476                                             "signals, overrides and virtuals, "
1477                                             "can't have no arguments",
1478                                             m->line_no);
1479                         }
1480                 }
1481         }
1482 }
1483
1484 static void
1485 check_nonvoidempty(Class *c)
1486 {
1487         GList *l;
1488         for(l=c->nodes;l;l=g_list_next(l)) {
1489                 Node *n = l->data;
1490                 if(n->type == METHOD_NODE) {
1491                         Method *m = (Method *)n;
1492                         if(m->method != REGULAR_METHOD)
1493                                 continue;
1494                         if(!(strcmp(m->mtype->name,"void")==0 &&
1495                              m->mtype->stars == 0) &&
1496                            !m->cbuf) {
1497                                 print_error(TRUE,
1498                                             "non-void empty method found, "
1499                                             "regular non-void function should "
1500                                             "not be empty.",
1501                                             m->line_no);
1502                                 /* add a body here, so that the user will also
1503                                    get a warning from gcc, and so that it will
1504                                    at least point him to the prototype of the
1505                                    function in the .gob file */
1506                                 m->cbuf = g_strdup("/*empty*/");
1507                                 m->ccode_line = m->line_no;
1508                         }
1509                 }
1510         }
1511 }
1512
1513 static void
1514 check_signal_args(Class *c)
1515 {
1516         GList *l;
1517         for(l=c->nodes;l;l=g_list_next(l)) {
1518                 Node *n = l->data;
1519                 if(n->type == METHOD_NODE) {
1520                         Method *m = (Method *)n;
1521                         GList *l;
1522                         if(m->method != SIGNAL_LAST_METHOD &&
1523                            m->method != SIGNAL_FIRST_METHOD)
1524                                 continue;
1525
1526                         for(l=m->gtktypes;l;l=l->next) {
1527                                 char *s;
1528                                 if(get_cast(l->data))
1529                                         continue;
1530                                 s = g_strdup_printf("Unknown GTK+ type '%s' "
1531                                                     "among signal types",
1532                                                     (char *)l->data);
1533                                 print_error(FALSE, s, m->line_no);
1534                                 g_free(s);
1535                         }
1536                 }
1537         }
1538 }
1539
1540 static int
1541 count_signals(Class *c)
1542 {
1543         int num = 0;
1544         GList *l;
1545         for(l=c->nodes;l;l=g_list_next(l)) {
1546                 Node *n = l->data;
1547                 if(n->type == METHOD_NODE) {
1548                         Method *m = (Method *)n;
1549                         if(m->method == SIGNAL_LAST_METHOD ||
1550                            m->method == SIGNAL_FIRST_METHOD)
1551                                 num++;
1552                 }
1553         }
1554         return num;
1555 }
1556
1557 static int
1558 count_arguments(Class *c)
1559 {
1560         int num = 0;
1561         GList *li;
1562
1563         for(li=c->nodes;li;li=g_list_next(li)) {
1564                 Node *n = li->data;
1565                 if(n->type == ARGUMENT_NODE)
1566                         num ++;
1567         }
1568         return num;
1569 }
1570
1571 static int
1572 count_overrides(Class *c)
1573 {
1574         int num = 0;
1575         GList *l;
1576         for(l=c->nodes;l;l=g_list_next(l)) {
1577                 Node *n = l->data;
1578                 if(n->type == METHOD_NODE) {
1579                         Method *m = (Method *)n;
1580                         if(m->method == OVERRIDE_METHOD)
1581                                 num++;
1582                 }
1583         }
1584         return num;
1585 }
1586
1587 static int
1588 count_privates(Class *c)
1589 {
1590         int num = 0;
1591         GList *l;
1592         for(l=c->nodes;l;l=g_list_next(l)) {
1593                 Node *n = l->data;
1594                 if(n->type == VARIABLE_NODE) {
1595                         Variable *v = (Variable *)n;
1596                         if(v->scope == PRIVATE_SCOPE)
1597                                 num++;
1598                 }
1599         }
1600         return num;
1601 }
1602
1603 static int
1604 count_protecteds(Class *c)
1605 {
1606         int num = 0;
1607         GList *l;
1608         for(l=c->nodes;l;l=g_list_next(l)) {
1609                 Node *n = l->data;
1610                 if(n->type == METHOD_NODE) {
1611                         Method *m = (Method *)n;
1612                         if(m->scope == PROTECTED_SCOPE)
1613                                 num++;
1614                 }
1615         }
1616         return num;
1617 }
1618
1619
1620 static void
1621 open_files(void)
1622 {
1623         char *outfile,*outfileh,*outfileph;
1624
1625         if(!for_cpp)
1626                 outfile = g_strconcat(filebase,".c",NULL);
1627         else
1628                 outfile = g_strconcat(filebase,".cc",NULL);
1629         if(no_touch_headers)
1630                 outfileh = g_strconcat("#gob#",filebase,".h#gob#",NULL);
1631         else
1632                 outfileh = g_strconcat(filebase,".h",NULL);
1633
1634         if((privates>0 || protecteds>0 || always_private_header) &&
1635            !no_private_header)
1636                 outfileph = g_strconcat(filebase,"-private.h",NULL);
1637         else
1638                 outfileph = NULL;
1639
1640         
1641         out = fopen(outfile,"w");
1642         if(!out) {
1643                 g_error("Cannot open outfile: %s",outfile);
1644         }
1645         outh = fopen(outfileh,"w");
1646         if(!outh) {
1647                 g_error("Cannot open outfile: %s",outfileh);
1648         }
1649         if(outfileph) {
1650                 outph = fopen(outfileph,"w");
1651                 if(!outph) {
1652                         g_error("Cannot open outfile: %s",outfileh);
1653                 }
1654         }
1655 }
1656
1657 static void
1658 generate_outfiles(void)
1659 {
1660         char *p;
1661         GList *li;
1662         time_t curtime;
1663         gboolean found_header;
1664
1665         time(&curtime);
1666         out_printf(outh,"/* Generated by GOB (v%s)"
1667                "   (do not edit directly) */\n\n",VERSION);
1668         if(outph)
1669                 out_printf(outph,"/* Generated by GOB (v%s)"
1670                            "   (do not edit directly) */\n\n",VERSION);
1671         out_printf(out,"/* Generated by GOB (v%s) on %s"
1672                "   (do not edit directly) */\n\n",VERSION,ctime(&curtime));
1673         
1674         p = replace_sep(((Class *)class)->otype,'_');
1675         g_strup(p);
1676         out_printf(outh,"#ifndef __%s_H__\n#define __%s_H__\n\n"
1677                 "#include <gtk/gtk.h>\n\n",p,p);
1678         if(outph)
1679                 out_printf(outph,"#ifndef __%s_PRIVATE_H__\n"
1680                            "#define __%s_PRIVATE_H__\n\n"
1681                            "#include \"%s.h\"\n\n",p,p,filebase);
1682         g_free(p);
1683
1684         if(!for_cpp) {
1685                 out_printf(outh,"#ifdef __cplusplus\n"
1686                            "extern \"C\" {\n"
1687                            "#endif /* __cplusplus */\n\n");
1688                 if(outph)
1689                         out_printf(outph,"#ifdef __cplusplus\n"
1690                                    "extern \"C\" {\n"
1691                                    "#endif /* __cplusplus */\n\n");
1692         }
1693         
1694         p = g_strconcat(filebase,".h",NULL);
1695         found_header = TRUE;
1696         if(!g_list_find_custom(include_files,p,(GCompareFunc)strcmp)) {
1697                 out_printf(out,"#include \"%s.h\"\n\n",filebase);
1698                 found_header = FALSE;
1699         }
1700         g_free(p);
1701
1702         /* if we are creating a private header see if it was included */
1703         if(outph) {
1704                 p = g_strconcat(filebase,"-private.h",NULL);
1705                 if(!g_list_find_custom(include_files,p,(GCompareFunc)strcmp)) {
1706                         out_printf(out,"#include \"%s-private.h\"\n\n",
1707                                    filebase);
1708                         if(found_header)
1709                                 print_error(TRUE,
1710                                             "Implicit private header include "
1711                                             "added to top of\n"
1712                                             "\tsource file, while public "
1713                                             "header is at a custom location, "
1714                                             "you should\n"
1715                                             "\texplicitly include "
1716                                             "the private header below the "
1717                                             "public one.", 0);
1718                 }
1719                 g_free(p);
1720         }
1721
1722         for(li=nodes;li;li=g_list_next(li)) {
1723                 Node *node = li->data;
1724                 if(node->type == CCODE_NODE) {
1725                         CCode *cc = (CCode *)node;
1726                         FILE *fp;
1727                         if(cc->header) {
1728                                 fp = outh;
1729                                 out_printf(fp,"\n");
1730                         } else {
1731                                 fp = out;
1732                                 out_printf(fp,"\n");
1733                                 out_addline_infile(fp,cc->line_no);
1734                         }
1735                         out_printf(fp,"%s\n",cc->cbuf);
1736                         if(!cc->header)
1737                                 out_addline_outfile(fp);
1738                 } else if(node->type == CLASS_NODE) {
1739                         Class *c = (Class *)class;
1740                         GList *l;
1741
1742                         out_printf(out,"/* utility types we may need */\n");
1743                         out_printf(out,"typedef struct { "
1744                                    "gpointer a; gpointer b; "
1745                                    "} __twopointertype;\n");
1746                         out_printf(out,"typedef struct { "
1747                                    "gpointer a; gpointer b; "
1748                                    "gpointer c; "
1749                                    "} __threepointertype;\n");
1750
1751                         out_printf(outh,"\n#define %s\t"
1752                                 "(%s_get_type())\n",
1753                                 macrotype,funcbase);
1754                         out_printf(outh,"#define %s(obj)\t"
1755                                 "GTK_CHECK_CAST((obj),%s_get_type(),%s)\n",
1756                                 macrobase,funcbase,typebase);
1757                         out_printf(outh,"#define %s_CLASS(klass)\t"
1758                                 "GTK_CHECK_CLASS_CAST((klass),%s_get_type(),%sClass)\n",
1759                                 macrobase,funcbase,typebase);
1760                         out_printf(outh,"#define %s(obj)\t"
1761                                 "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
1762                                 macrois,funcbase);
1763
1764                         if(privates>0)
1765                                 out_printf(outh,"\ntypedef struct _%sPrivate %sPrivate;\n",typebase,typebase);
1766
1767                         out_printf(outh,"\ntypedef struct _%s %s;\n",typebase,typebase);
1768                         out_printf(outh,"struct _%s {\n\t%s __parent__;\n",
1769                                    typebase,ptypebase);
1770                         for(l=c->nodes;l;l=g_list_next(l)) {
1771                                 Node *n = l->data;
1772                                 Variable *v = (Variable *)n;
1773                                 if(n->type == VARIABLE_NODE &&
1774                                    v->scope == PUBLIC_SCOPE)
1775                                         put_variable((Variable *)n,outh);
1776                         }
1777                         /* put protecteds always AFTER publics */
1778                         for(l=c->nodes;l;l=g_list_next(l)) {
1779                                 Node *n = l->data;
1780                                 Variable *v = (Variable *)n;
1781                                 if(n->type == VARIABLE_NODE &&
1782                                    v->scope == PROTECTED_SCOPE)
1783                                         put_variable((Variable *)n,outh);
1784                         }
1785                         if(privates>0)
1786                                 out_printf(outh,"\t%sPrivate *_priv;\n",typebase);
1787                         out_printf(outh,"};\n");
1788
1789                         if(privates>0) {
1790                                 FILE *outfp;
1791
1792                                 /* if we are to stick this into the private
1793                                    header, if not stick it directly into the
1794                                    C file */
1795                                 if(outph) 
1796                                         outfp = outph;
1797                                 else
1798                                         outfp = out;
1799
1800                                 out_printf(outfp,"struct _%sPrivate {\n",
1801                                            typebase);
1802                                 for(l=c->nodes;l;l=l->next) {
1803                                         Node *n = l->data;
1804                                         Variable *v = (Variable *)n;
1805                                         if(n->type == VARIABLE_NODE &&
1806                                            v->scope == PRIVATE_SCOPE) {
1807                                                 out_addline_infile(outfp,v->line_no);
1808                                                 put_variable(v,outfp);
1809                                         }
1810                                 }
1811                                 out_addline_outfile(outfp);
1812                                 out_printf(outfp,"};\n");
1813                         }
1814
1815                         out_printf(outh,"\ntypedef struct _%sClass %sClass;\n",
1816                                 typebase,typebase);
1817                         out_printf(outh,
1818                                 "struct _%sClass {\n\t%sClass __parent__;\n",
1819                                 typebase,ptypebase);
1820                         for(l=c->nodes;l;l=g_list_next(l)) {
1821                                 Node *n = l->data;
1822                                 if(n->type == METHOD_NODE)
1823                                         put_vs_method((Method *)n);
1824                         }
1825                         out_printf(outh,"};\n\n");
1826
1827                         out_printf(outh,"guint\t%s_get_type\t(void);\n",funcbase);
1828                         
1829                         if(arguments>0) {
1830                                 out_printf(out,"static void __object_set_arg "
1831                                            "(GtkObject *object, GtkArg *arg, "
1832                                            "guint arg_id);\n"
1833                                            "static void __object_get_arg "
1834                                            "(GtkObject *object, GtkArg *arg, "
1835                                            "guint arg_id);\n");
1836                         }
1837
1838                         out_printf(out,"/* here are local prototypes */\n");
1839                         for(l=c->nodes;l;l=g_list_next(l)) {
1840                                 Node *n = l->data;
1841                                 if(n->type == METHOD_NODE) {
1842                                         put_pub_method((Method *)n);
1843                                         put_prot_method((Method *)n);
1844                                         put_priv_method_prot((Method *)n);
1845                                 }
1846                         }
1847
1848                         if(signals>0) {
1849                                 for(l=c->nodes;l;l=g_list_next(l)) {
1850                                         Node *n = l->data;
1851                                         if(n->type == METHOD_NODE)
1852                                                 add_signal_prots((Method *)n);
1853                                 }
1854                         }
1855                         
1856                         add_enums(c);
1857                         
1858                         add_get_type();
1859
1860                         make_method_pointers(c);
1861
1862                         out_printf(out,"#define GET_NEW (gtk_type_new(%s_get_type()))\n",
1863                                    funcbase);
1864
1865                         add_inits(c);
1866
1867                         if(arguments>0) {
1868                                 add_getset_arg(c, TRUE);
1869                                 add_getset_arg(c, FALSE);
1870                         }
1871
1872                         for(l=c->nodes;l;l=g_list_next(l)) {
1873                                 Node *n = l->data;
1874                                 if(n->type == METHOD_NODE) {
1875                                         put_method((Method *)n);
1876                                 }
1877                         }
1878
1879                         out_printf(out,"#undef GET_NEW\n");
1880
1881                         add_bad_hack_to_avoid_unused_warnings(c);
1882                 } else
1883                         g_assert_not_reached();
1884         }
1885
1886         if(!for_cpp)
1887                 out_printf(outh,"\n#ifdef __cplusplus\n"
1888                            "}\n"
1889                            "#endif /* __cplusplus */\n");
1890         out_printf(outh,"\n#endif");
1891         if(outph) {
1892                 if(!for_cpp)
1893                         out_printf(outph,"\n#ifdef __cplusplus\n"
1894                                    "}\n"
1895                                    "#endif /* __cplusplus */\n");
1896                 out_printf(outph,"\n#endif");
1897         }
1898 }
1899
1900 #if 0
1901 static void
1902 usage(poptContext optCon, int exitcode, char *error, char *addl)
1903 {
1904         poptPrintUsage(optCon, stderr, 0);
1905         if (error) fprintf(stderr, "%s: %s", error, addl);
1906         exit(exitcode);
1907 }
1908 #endif
1909
1910 static void
1911 print_help(void)
1912 {
1913         fprintf(stderr,"Gob version %s\n\n",VERSION);
1914         fprintf(stderr,"Options:\n"
1915                 "\t--help,-h,-?            Display this help\n"
1916                 "\t--version               Display version\n"
1917                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
1918                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
1919                 "\t--for-cpp               Create C++ files\n"
1920                 "\t--no-touch-headers      Don't touch headers unless they "
1921                                           "really changed\n"
1922                 "\t--always-private-header Always create a private header "
1923                                           "file,\n"
1924                 "\t                        even if it would be empty\n"
1925                 "\t--no-private-header     Don't create a private header, "
1926                                           "put private\n"
1927                 "\t                        structure and protected "
1928                                           "prototypes inside c file\n");
1929 }
1930
1931 static void
1932 parse_options(int argc, char *argv[])
1933 {
1934         int i;
1935         int got_file = FALSE;
1936         int no_opts = FALSE;
1937
1938         filename = NULL;
1939
1940         for(i=1;i<argc;i++) {
1941                 if(no_opts || argv[i][0]!='-') {
1942                         /*must be a file*/
1943                         if(got_file) {
1944                                 fprintf(stderr,"Specify only one file!\n");
1945                                 print_help();
1946                                 exit(1);
1947                         }
1948                         filename = argv[i];
1949                         got_file = TRUE;
1950                 } else if(strcmp(argv[i],"--help")==0) {
1951                         print_help();
1952                         exit(0);
1953                 } else if(strcmp(argv[i],"--version")==0) {
1954                         fprintf(stderr,"Gob version %s\n",VERSION);
1955                         exit(0);
1956                 } else if(strcmp(argv[i],"--exit-on-warn")==0) {
1957                         exit_on_warn = TRUE;
1958                 } else if(strcmp(argv[i],"--no-exit-on-warn")==0) {
1959                         exit_on_warn = FALSE;
1960                 } else if(strcmp(argv[i],"--for-cpp")==0) {
1961                         for_cpp = TRUE;
1962                 } else if(strcmp(argv[i],"--no-touch-headers")==0) {
1963                         no_touch_headers = TRUE;
1964                 } else if(strcmp(argv[i],"--always-private-header")==0) {
1965                         no_private_header = FALSE;
1966                         always_private_header = TRUE;
1967                 } else if(strcmp(argv[i],"--no-private-header")==0) {
1968                         always_private_header = FALSE;
1969                         no_private_header = TRUE;
1970                 } else if(strcmp(argv[i],"--")==0) {
1971                         /*further arguments are files*/
1972                         no_opts = TRUE;
1973                 } else if(strncmp(argv[i],"--",2)==0) {
1974                         /*unknown long option*/
1975                         fprintf(stderr,"Unknown option '%s'!\n",argv[i]);
1976                         print_help();
1977                         exit(1);
1978                 } else {
1979                         /*by now we know we have a string starting with
1980                           - which is a short option string*/
1981                         char *p = argv[i]+1;
1982                         for(p=argv[i]+1;*p;p++) {
1983                                 switch(*p) {
1984                                 case 'w':
1985                                         exit_on_warn=TRUE;
1986                                         break;
1987                                 case 'h':
1988                                 case '?':
1989                                         print_help();
1990                                         exit(0);
1991                                 default:
1992                                         fprintf(stderr,
1993                                                 "Unknown option '%c'!\n",*p);
1994                                         print_help();
1995                                         exit(1);
1996                                 }
1997                         }
1998                 }
1999         }
2000 }
2001
2002 /* this is a somewhat ugly hack, but it appears to work */
2003 static void
2004 compare_and_move_header(void)
2005 {
2006         char *hfnew = g_strconcat("#gob#",filebase,".h#gob#",NULL);
2007         char *hf = g_strconcat(filebase,".h",NULL);
2008         struct stat s;
2009         if(stat(hf,&s)==0) {
2010                 char *s;
2011                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null",hf,hfnew);
2012                 if(system(s)==0) {
2013                         if(unlink(hfnew)!=0)
2014                                 print_error(FALSE,"Can't remove new header file",0);
2015                         g_free(hfnew);
2016                         g_free(hf);
2017                         g_free(s);
2018                         return;
2019                 }
2020                 g_free(s);
2021                 if(unlink(hf)!=0)
2022                         print_error(FALSE,"Can't remove old header file",0);
2023         }
2024         if(rename(hfnew,hf)!=0)
2025                 print_error(FALSE,"Can't rename new header file",0);
2026         g_free(hfnew);
2027         g_free(hf);
2028 }
2029
2030 int
2031 main(int argc, char *argv[])
2032 {
2033 #if 0
2034         int c;
2035         poptContext optCon;
2036         
2037         struct poptOption optionsTable[] = {
2038                 { "exit-on-warn", 'w', 0, &exit_on_warn, 0,
2039                          "exit on warnings" },
2040                 POPT_AUTOHELP
2041                 { NULL, 0, 0, NULL, 0 }
2042         };
2043         
2044         optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
2045         poptSetOtherOptionHelp(optCon, "[OPTIONS]* [filename]");
2046         
2047         while ((c = poptGetNextOpt(optCon)) >= 0)
2048                 ;
2049         
2050         filename = poptGetArg(optCon);
2051         if(!(poptPeekArg(optCon) == NULL))
2052                 usage(optCon, 1, "Specify only one file",
2053                       ".e.g., filename.gob");
2054                         
2055         if (c < -1) {
2056                 /* an error occurred during option processing */
2057                 fprintf(stderr, "%s: %s\n",
2058                         poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
2059                         poptStrerror(c));
2060                 return 1;
2061         }
2062 #endif
2063
2064         parse_options(argc,argv);
2065         
2066         if(filename) {
2067                 yyin = fopen(filename,"r");
2068                 if(!yyin) {
2069                         fprintf(stderr,"Error: can't open file '%s'\n",
2070                                 filename);
2071                         exit(1);
2072                 }
2073         } else
2074                 filename = "stdin";
2075
2076         /*yydebug = 1;*/
2077         if(yyparse()!=0)
2078                 g_error("Parsing errors, quitting");
2079         if(!class)
2080                 print_error(FALSE," no class defined",0);
2081         
2082
2083         exit_on_error = FALSE;
2084
2085         signals = count_signals((Class *)class);
2086         arguments = count_arguments((Class *)class);
2087         overrides = count_overrides((Class *)class);
2088         privates = count_privates((Class *)class);
2089         protecteds = count_protecteds((Class *)class);
2090
2091         make_bases();
2092         make_inits((Class *)class);
2093         if(privates>0)
2094                 make_destroy((Class *)class);
2095         check_bad_symbols((Class *)class);
2096         check_duplicate_symbols((Class *)class);
2097         check_duplicate_signals_args((Class *)class);
2098         check_public_new((Class *)class);
2099         check_vararg((Class *)class);
2100         check_firstarg((Class *)class);
2101         check_nonvoidempty((Class *)class);
2102         check_signal_args((Class *)class);
2103
2104         exit_on_error = TRUE;
2105         
2106         if(got_error)
2107                 exit(1);
2108
2109         open_files();
2110         
2111         generate_outfiles();
2112
2113         fclose(out);
2114         fclose(outh);
2115
2116         if(no_touch_headers)
2117                 compare_and_move_header();
2118         
2119 #if 0
2120         poptFreeContext(optCon);
2121 #endif
2122         return 0;
2123 }