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