]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
a614e31be494ccac41fa1df78e16d6f19f31575c
[gob-dx.git] / src / main.c
1 /* GOB C Preprocessor
2  * Copyright (C) 1999,2000 the Free Software Foundation.
3  * Copyright (C) 2000 Eazel, Inc.
4  *
5  * Author: George Lebl
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the  Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20  * USA.
21  */
22
23 #include "config.h"
24 #include <glib.h>
25 #include <time.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31
32 #include "treefuncs.h"
33 #include "parse.h"
34 #include "out.h"
35 #include "util.h"
36 #include "checks.h"
37
38 #include "main.h"
39
40 char *filename = NULL;
41
42 int yyparse(void);
43
44 extern int yydebug;
45 extern FILE * yyin;
46 extern Node *class;
47 extern GList *nodes;
48
49 extern GList *include_files;
50
51 extern GHashTable *gtk_doc_hash;
52
53 char *filebase;
54 static char *funcbase;
55 static char *pfuncbase;
56 static char *macrobase;
57 static char *macrois;
58 static char *macrotype;
59 static char *typebase;
60 static char *ptypebase;
61
62 static int signals = 0; /* number of signals */
63 static int arguments = 0; /* number of named arguments */
64 static int overrides = 0; /* number of override methods */
65 static int privates = 0; /* number of private data members */
66 static int protecteds = 0; /* number of protected methods */
67 static int destructors = 0; /* number of variable destructors */
68 static int initializers = 0; /* number of variable initializers */
69
70 static gboolean made_aliases = FALSE;  /* if we made any shorthand aliases
71                                           and need the REALLY UGLY HACK to
72                                           avoid warnings */
73
74 /* the special variable types we need to define */
75 static gboolean special_array[SPECIAL_LAST] = {0};
76 static gboolean any_special = FALSE;
77
78 static gboolean need_destroy = FALSE;
79 static Method * destroy_handler = NULL;
80
81 static gboolean need_finalize = FALSE;
82 static Method * finalize_handler = NULL;
83
84 FILE *out = NULL;
85 FILE *outh = NULL;
86 FILE *outph = NULL;
87 FILE *devnull = NULL;
88
89 gboolean no_touch_headers = FALSE;
90 gboolean for_cpp = FALSE;
91 gboolean no_gnu = FALSE;
92 gboolean exit_on_warn = FALSE;
93 gboolean exit_on_error = TRUE;
94 gboolean got_error = FALSE;
95 gint private_header = PRIVATE_HEADER_ALWAYS;
96 gboolean no_extern_c = FALSE;
97 gboolean no_write = FALSE;
98 gboolean no_lines = FALSE;
99 gboolean no_self_alias = FALSE;
100 gboolean no_kill_underscores = FALSE;
101 gboolean always_private_struct = FALSE;
102
103 int method_unique_id = 1;
104
105 static void
106 make_bases(void)
107 {
108         filebase = replace_sep(((Class *)class)->otype, '-');
109         g_strdown(filebase);
110
111         funcbase = replace_sep(((Class *)class)->otype, '_');
112         g_strdown(funcbase);
113
114         pfuncbase = replace_sep(((Class *)class)->ptype, '_');
115         g_strdown(pfuncbase);
116
117         macrobase = replace_sep(((Class *)class)->otype, '_');
118         g_strup(macrobase);
119         
120         macrois = make_pre_macro(((Class *)class)->otype, "IS");
121         macrotype = make_pre_macro(((Class *)class)->otype, "TYPE");
122
123         typebase = remove_sep(((Class *)class)->otype);
124
125         ptypebase = remove_sep(((Class *)class)->ptype);
126 }
127
128 static char *
129 get_type(Type *t, gboolean postfix_to_stars)
130 {
131         char *s;
132         int i;
133         int extra;
134         GString *gs;
135
136         s = remove_sep(t->name);
137         gs = g_string_new(s);
138         g_free(s);
139
140         extra = 0;
141         if(postfix_to_stars) {
142                 char *p;
143                 /*XXX: this is ugly perhaps we can do this whole postfix thing
144                   in a nicer way, we just count the number of '[' s and from
145                   that we deduce the number of dimensions, so that we can print
146                   that many stars */
147                 for(p=t->postfix; p && *p; p++)
148                         if(*p == '[') extra++;
149         }
150         g_string_append_c(gs, ' ');
151
152         if(t->pointer) {
153                 g_string_append(gs, t->pointer);
154                 for(i=0; i < extra; i++)
155                         g_string_append_c(gs, '*');
156                 g_string_append_c(gs, ' ');
157         }
158         
159         s = gs->str;
160         g_string_free(gs, FALSE);
161         return s;
162 }
163
164 static char *
165 get_gtk_doc(char *id)
166 {
167         char *val, *s;
168
169         if(!gtk_doc_hash)
170                 return NULL;
171
172         val = g_hash_table_lookup(gtk_doc_hash, id);
173         if(val)
174                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
175                                        funcbase, get_real_id(id), val);
176         s = g_strconcat(funcbase, "_", get_real_id(id), NULL);
177         val = g_hash_table_lookup(gtk_doc_hash, s);
178         g_free(s);
179         if(val)
180                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
181                                        funcbase, get_real_id(id), val);
182         return NULL;
183 }
184
185 static void
186 print_type(FILE *fp, Type *t, gboolean postfix_to_stars)
187 {
188         char *s;
189
190         s = get_type(t, postfix_to_stars);
191         out_printf(fp, "%s", s); 
192         g_free(s);
193 }
194
195
196 static void
197 print_method(FILE *fp, char *typeprefix, char *nameprefix,
198              char *subnameprefix,
199              char *namepostfix, char *postfix, Method *m,
200              gboolean one_arg_per_line,
201              gboolean no_funcbase,
202              gboolean kill_underscore)
203 {
204         GList *li;
205         char *id;
206
207         out_printf(fp, "%s", typeprefix); 
208         print_type(fp, m->mtype, TRUE);
209
210         if(kill_underscore)
211                 id = get_real_id(m->id);
212         else
213                 id = m->id;
214
215         if(no_funcbase)
216                 out_printf(fp, "%s%s%s%s(",
217                            nameprefix, subnameprefix, id, namepostfix); 
218         else
219                 out_printf(fp, "%s%s_%s%s%s(",
220                            nameprefix, funcbase, subnameprefix, id,
221                            namepostfix); 
222         
223         if(m->args) {
224                 for(li=m->args; li; li=g_list_next(li)) {
225                         FuncArg *arg = li->data;
226                         print_type(fp, arg->atype, FALSE);
227                         if(li->next)
228                                 out_printf(fp, "%s%s,%s", arg->name,
229                                            arg->atype->postfix?
230                                            arg->atype->postfix:"",
231                                            one_arg_per_line?"\n\t\t\t\t\t":" ");
232                         else
233                                 out_printf(fp, "%s%s", arg->name,
234                                            arg->atype->postfix?
235                                            arg->atype->postfix:""); 
236                 }
237                 if(m->vararg)
238                         out_printf(fp, ",%s...",
239                                    one_arg_per_line?"\n\t\t\t\t\t":" "); 
240         } else {
241                 out_printf(fp, "void"); 
242         }
243         out_printf(fp, ")%s", postfix); 
244 }
245
246 static gboolean
247 any_method_to_alias(Class *c)
248 {
249         GList *li;
250         
251         for(li=c->nodes;li;li=g_list_next(li)) {
252                 Node *node = li->data;
253                 if(node->type == METHOD_NODE) {
254                         Method *m = (Method *)node;
255                         
256                         if(m->method == INIT_METHOD ||
257                            m->method == CLASS_INIT_METHOD ||
258                            m->method == OVERRIDE_METHOD)
259                                 continue;
260
261                         return TRUE;
262                 }
263         }
264         return FALSE;
265 }
266
267
268 static void
269 make_method_gnu_aliases(Class *c)
270 {
271         GList *li;
272         
273         for(li=c->nodes;li;li=g_list_next(li)) {
274                 Node *node = li->data;
275                 if(node->type == METHOD_NODE) {
276                         Method *m = (Method *)node;
277                         
278                         if(m->method == INIT_METHOD ||
279                            m->method == CLASS_INIT_METHOD ||
280                            m->method == OVERRIDE_METHOD)
281                                 continue;
282
283                         /* in C++ mode don't alias new */
284                         if(for_cpp && strcmp(m->id, "new")==0)
285                                 continue;
286
287                         out_printf(out, "static const typeof(&%s_%s) %s "
288                                    "__attribute__ ((__unused__)) "
289                                    "= %s_%s;\n", funcbase, get_real_id(m->id),
290                                    m->id, funcbase, get_real_id(m->id));
291                         out_printf(out, "#define %s(args...) "
292                                    "%s_%s(##args)\n", m->id,
293                                    funcbase, get_real_id(m->id));
294                 }
295         }
296 }
297
298 static void
299 make_method_nongnu_aliases(Class *c)
300 {
301         GList *li;
302         
303         for(li=c->nodes; li; li=g_list_next(li)) {
304                 Node *node = li->data;
305                 if(node->type == METHOD_NODE) {
306                         Method *m = (Method *)node;
307                         
308                         if(m->method == INIT_METHOD ||
309                            m->method == CLASS_INIT_METHOD ||
310                            m->method == OVERRIDE_METHOD)
311                                 continue;
312
313                         /* in C++ mode don't alias new */
314                         if(for_cpp && strcmp(m->id, "new")==0)
315                                 continue;
316
317                         print_method(out, "static ", "(* ", "", ") ", "",
318                                      m, FALSE, TRUE, FALSE);
319                         out_printf(out, " = %s_%s;\n", funcbase,
320                                    get_real_id(m->id));
321
322                         made_aliases = TRUE;
323                 }
324         }
325 }
326
327 static void
328 add_bad_hack_to_avoid_unused_warnings(Class *c)
329 {
330         GList *li;
331
332         /* if we haven't had any methods, just return */
333         if(!made_aliases)
334                 return;
335         
336         if(!no_gnu)
337                 out_printf(out, "\n\n#ifndef __GNUC__\n");
338         out_printf(out,
339                    "/*REALLY BAD HACK\n"
340                    "  This is to avoid unused warnings if you don't call\n"
341                    "  some method.  I need to find a better way to do\n"
342                    "  this, not needed in GCC since we use some gcc\n"
343                    "  extentions to make saner, faster code */\n"
344                    "static void\n"
345                    "___%s_really_bad_hack_to_avoid_warnings(void)\n"
346                    "{\n", funcbase);
347         for(li=c->nodes;li;li=g_list_next(li)) {
348                 Node *node = li->data;
349                 if(node->type == METHOD_NODE) {
350                         Method *m = (Method *)node;
351                         
352                         if(m->method == INIT_METHOD ||
353                            m->method == CLASS_INIT_METHOD ||
354                            m->method == OVERRIDE_METHOD)
355                                 continue;
356
357                         /* in C++ mode we don't alias new */
358                         if(for_cpp && strcmp(m->id, "new")==0)
359                                 continue;
360
361                         out_printf(out, "\t((void (*)(void))%s)();\n", m->id);
362                 }
363         }
364         out_printf(out, "\t___%s_really_bad_hack_to_avoid_warnings();\n",
365                    funcbase);
366         if(!no_gnu)
367                 out_printf(out, "}\n#endif /* __GNUC__ */\n\n");
368         else
369                 out_printf(out, "}\n\n");
370 }
371
372 static void
373 put_variable(Variable *v, FILE *fp)
374 {
375         out_printf(fp, "\t");
376         print_type(fp, v->vtype, FALSE);
377         out_printf(fp, "%s%s;", v->id,
378                    v->vtype->postfix?
379                    v->vtype->postfix:""); 
380         if(v->scope == PROTECTED_SCOPE)
381                 out_printf(fp, " /* protected */");
382         out_printf(fp, "\n");
383 }
384
385 static void
386 put_vs_method(Method *m)
387 {
388         if(m->method != SIGNAL_LAST_METHOD &&
389            m->method != SIGNAL_FIRST_METHOD &&
390            m->method != VIRTUAL_METHOD)
391                 return;
392
393         /* if a signal mark it as such */
394         if(m->method != VIRTUAL_METHOD)
395                 print_method(outh, "\t/*signal*/", "(* ", "", ") ", ";\n",
396                              m, FALSE, TRUE, TRUE);
397         else
398                 print_method(outh, "\t", "(* ", "", ") ", ";\n",
399                              m, FALSE, TRUE, TRUE);
400 }
401
402 static void
403 put_pub_method(Method *m)
404 {
405         if(m->scope != PUBLIC_SCOPE)
406                 return;
407
408         print_method(outh, "", "\t", "", "\t", ";\n", m, TRUE, FALSE, TRUE);
409 }
410
411 /* I'm starting not to like this idea */
412 #if 0
413 static void
414 put_signal_connect(Method *m)
415 {
416         if(m->method != SIGNAL_LAST_METHOD &&
417            m->method != SIGNAL_FIRST_METHOD)
418                 return;
419
420         out_printf(outh, "guint \t%s_%s__connect_full\t(%s *object,\n"
421                    "\t\t\t\t\tconst char *name,\n"
422                    "\t\t\t\t\tGtkSignalFunc func,\n"
423                    "\t\t\t\t\tGtkCallbackMarshal marshal,\n"
424                    "\t\t\t\t\tgpointer data,\n"
425                    "\t\t\t\t\tGtkDestroyNotify destroy_func,\n"
426                    "\t\t\t\t\tgboolean object_signal,\n"
427                    "\t\t\t\t\tgboolean after);\n",
428                    funcbase, m->id, typebase);
429
430         out_printf(outh, "#define %s_%s__connect(object,name,func,data) "
431                    "%s_%s__connect_full((object),(name),(func),NULL,"
432                    "(data),NULL,FALSE,FALSE)\n",
433                    funcbase, m->id, funcbase, m->id);
434         out_printf(outh, "#define %s_%s__connect_after(object,name,func,data) "
435                    "%s__connect_%s_full((object),(name),(func),NULL,"
436                    "(data),NULL,FALSE,TRUE)\n",
437                    funcbase, m->id, funcbase, m->id);
438
439         out_printf(outh, "guint \t%s_%s__connect_while_alive\t(%s *object,\n"
440                    "\t\t\t\t\tconst char *name,\n"
441                    "\t\t\t\t\tGtkSignalFunc func,\n"
442                    "\t\t\t\t\tgpointer data,\n"
443                    "\t\t\t\t\tGtkObject *alive_object);\n\n",
444                    funcbase, m->id, typebase);
445 }
446 #endif
447
448
449 static void
450 put_prot_method(Method *m)
451 {
452         if(m->scope != PROTECTED_SCOPE)
453                 return;
454
455         if(outph)
456                 print_method(outph, "", "\t", "", "\t", ";\n",
457                              m, FALSE, FALSE, TRUE);
458         else
459                 print_method(out, "", "\t", "", "\t", ";\n",
460                              m, FALSE, FALSE, TRUE);
461 }
462
463 static void
464 put_priv_method_prot(Method *m)
465 {
466         if(m->method == SIGNAL_LAST_METHOD ||
467            m->method == SIGNAL_FIRST_METHOD ||
468            m->method == VIRTUAL_METHOD) {
469                 if(m->cbuf)
470                         print_method(out,
471                                      "static ", "___real_", "", " ", ";\n",
472                                      m, FALSE, FALSE, TRUE);
473         }
474         /* no else, here, it might still have a private prototype, it's not
475          * exclusive */
476
477         if((m->method == OVERRIDE_METHOD &&
478             m->cbuf)) {
479                 /* add unique ID */
480                 char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
481                 print_method(out, "static ", s, "", " ",
482                              no_gnu?";\n":" G_GNUC_UNUSED;\n",
483                              m, FALSE, FALSE, FALSE);
484                 g_free(s);
485         } else if(m->scope == PRIVATE_SCOPE ||
486            m->method == INIT_METHOD ||
487            m->method == CLASS_INIT_METHOD)
488                 print_method(out, "static ", "", "", " ",
489                              no_gnu?";\n":" G_GNUC_UNUSED;\n",
490                              m, FALSE, FALSE, TRUE);
491 }
492
493 static GList *
494 make_func_arg(char *typename, int is_class, char *name)
495 {
496         Node *node;
497         Node *type;
498         char *tn;
499         
500         if(is_class)
501                 tn = g_strconcat(typename, ":Class", NULL);
502         else
503                 tn = g_strdup(typename);
504
505         type = new_type(tn, g_strdup("*"), NULL);
506         node = new_funcarg((Type *)type, name, NULL);
507         return g_list_prepend(NULL, node);
508 }
509
510 static void
511 make_inits(Class *cl)
512 {
513         int got_class_init = FALSE;
514         int got_init = FALSE;
515         GList *li;
516         Node *node;
517         for(li=cl->nodes;li;li=g_list_next(li)) {
518                 Node *n = li->data;
519                 if(n->type == METHOD_NODE) {
520                         Method *m = (Method *)n;
521                         if(m->method == INIT_METHOD) {
522                                 if(got_init)
523                                         print_error(FALSE, "init defined more then once", m->line_no);
524                                 got_init = TRUE;
525                         } else if(m->method == CLASS_INIT_METHOD) {
526                                 if(got_class_init)
527                                         print_error(FALSE, "class_init defined more then once", m->line_no);
528                                 got_class_init = TRUE;
529                         }
530                 }
531         }
532         if(!got_class_init) {
533                 node = new_method(NO_SCOPE, CLASS_INIT_METHOD,
534                                   (Type *)new_type(g_strdup("void"),
535                                                    NULL, NULL),
536                                   NULL, NULL, NULL, g_strdup("class_init"),
537                                   make_func_arg(cl->otype, TRUE, g_strdup("c")),
538                                   NULL, NULL, NULL, 0, 0, FALSE,
539                                   method_unique_id++);
540                 cl->nodes = g_list_prepend(cl->nodes, node);
541         }
542         if(!got_init) {
543                 node = new_method(NO_SCOPE, INIT_METHOD,
544                                   (Type *)new_type(g_strdup("void"),
545                                                    NULL, NULL),
546                                   NULL, NULL, NULL, g_strdup("init"),
547                                   make_func_arg(cl->otype, FALSE, g_strdup("o")),
548                                   NULL, NULL, NULL, 0, 0, FALSE,
549                                   method_unique_id++);
550                 cl->nodes = g_list_prepend(cl->nodes, node);
551         }
552 }
553
554 static void
555 find_destroy(Class *cl)
556 {
557         GList *li;
558
559         destroy_handler = NULL;
560         for(li=cl->nodes;li;li=g_list_next(li)) {
561                 Node *n = li->data;
562                 if(n->type == METHOD_NODE) {
563                         Method *m = (Method *)n;
564                         if(m->method == OVERRIDE_METHOD &&
565                            strcmp(m->id, "destroy")==0) {
566                                 if(strcmp(m->otype, "Gtk:Object") != 0) {
567                                         print_error(FALSE,
568                                                     "destroy method override "
569                                                     "of class other then "
570                                                     "Gtk:Object",
571                                                     m->line_no);
572                                 }
573                                 if(g_list_length(m->args) != 1) {
574                                         print_error(FALSE,
575                                                     "destroy method override "
576                                                     "with more then one "
577                                                     "parameter",
578                                                     m->line_no);
579                                 }
580                                 destroy_handler = m;
581                                 break;
582                         }
583                 }
584         }
585 }
586
587 static void
588 find_finalize(Class *cl)
589 {
590         GList *li;
591
592         finalize_handler = NULL;
593         for(li=cl->nodes;li;li=g_list_next(li)) {
594                 Node *n = li->data;
595                 if(n->type == METHOD_NODE) {
596                         Method *m = (Method *)n;
597                         if(m->method == OVERRIDE_METHOD &&
598                            strcmp(m->id, "finalize")==0) {
599                                 if(strcmp(m->otype, "Gtk:Object") != 0) {
600                                         print_error(FALSE,
601                                                     "finalize method override "
602                                                     "of class other then "
603                                                     "Gtk:Object",
604                                                     m->line_no);
605                                 }
606                                 if(g_list_length(m->args) != 1) {
607                                         print_error(FALSE,
608                                                     "finalize method override "
609                                                     "with more then one "
610                                                     "parameter",
611                                                     m->line_no);
612                                 }
613                                 finalize_handler = m;
614                                 break;
615                         }
616                 }
617         }
618 }
619
620
621 /* hash of method -> name of signal prototype */
622 static GHashTable *marsh = NULL;
623
624 /* list of methods with different signal prototypes,
625    we check this list if we can use a signal prototype of a
626    previous signal method, there are only uniques here */
627 static GList *eq_signal_methods = NULL;
628
629 /* compare a list of strings */
630 static gboolean
631 is_list_equal(GList *a, GList *b)
632 {
633         for(;a && b; a=a->next, b=b->next) {
634                 if(strcmp(a->data, b->data)!=0) {
635                         return FALSE;
636                 }
637         }
638         /* the the lists were different length */
639         if(a || b)
640                 return FALSE;
641         return TRUE;
642 }
643
644 static Method *
645 find_same_type_signal(Method *m)
646 {
647         GList *li;
648         for(li=eq_signal_methods;li;li=li->next) {
649                 Method *mm = li->data;
650                 if(is_list_equal(mm->gtktypes, m->gtktypes))
651                         return mm;
652         }
653         return NULL;
654 }
655
656 static void
657 print_signal_marsal_args(Method *m)
658 {
659         if(strcmp(m->gtktypes->next->data, "NONE")!=0) {
660                 GList *li;
661                 int i;
662                 for(i=0, li=m->gtktypes->next;li;
663                     i++, li=g_list_next(li)) {
664                         if(!for_cpp)
665                                 out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
666                                            (char *)li->data, i);
667                         else {
668                                 out_printf(out, ",\n\t\t(%s)"
669                                            "GTK_VALUE_%s(args[%d])",
670                                            get_cast(li->data, FALSE),
671                                            (char *)li->data, i);
672                         }
673                 }
674         }
675         out_printf(out, ",\n\t\tfunc_data);\n}\n\n");
676 }
677
678
679 static void
680 add_signal_prots(Method *m)
681 {
682         GList *li;
683         static int sig = 1;
684         char *s;
685         Method *mm;
686         
687         if(m->method != SIGNAL_LAST_METHOD &&
688            m->method != SIGNAL_FIRST_METHOD)
689                 return;
690
691         if(!marsh)
692                 marsh = g_hash_table_new(NULL, NULL);
693         
694         if(strcmp(m->gtktypes->data, "NONE")==0 &&
695            strcmp(m->gtktypes->next->data, "NONE")==0)
696                 return;
697
698         /* if we already did a signal prototype just use that */
699         mm = find_same_type_signal(m);
700         if(mm) {
701                 s = g_hash_table_lookup(marsh, mm);
702                 g_hash_table_insert(marsh, m, s);
703                 return;
704         }
705         
706         s = g_strdup_printf("Sig%d", sig++);
707         
708         g_hash_table_insert(marsh, m, s);
709         eq_signal_methods = g_list_prepend(eq_signal_methods, m);
710         
711         /* we know that we'll know all the gtktypes (so get_cast can't fail) */
712         out_printf(out, "\ntypedef %s (*___%s) (%s *, ",
713                    get_cast(m->gtktypes->data, FALSE), s, typebase);
714         
715         if(strcmp(m->gtktypes->next->data, "NONE")!=0) {
716                 for(li=m->gtktypes->next; li; li=g_list_next(li))
717                         out_printf(out, "%s, ", get_cast(li->data, FALSE));
718         }
719         out_printf(out, "gpointer);\n"); 
720         
721         out_printf(out, "\nstatic void\n"
722                 "___marshal_%s (GtkObject * object,\n"
723                 "\tGtkSignalFunc func,\n"
724                 "\tgpointer func_data,\n"
725                 "\tGtkArg * args)\n"
726                 "{\n", s);
727         
728         if(strcmp(m->gtktypes->data, "NONE")==0) {
729                 out_printf(out, "\t___%s rfunc;\n\n"
730                         "\trfunc = (___%s)func;\n\n"
731                         "\t(*rfunc)((%s *)object", s, s, typebase);
732         } else {
733                 const char *retcast = get_cast(m->gtktypes->data, FALSE);
734                 out_printf(out,
735                            "\t___%s rfunc;\n\t"
736                            "%s *retval;\n\n"
737                            "\trfunc = (___%s)func;\n\n"
738                            "\tretval = GTK_RETLOC_%s(args[%d]);\n\n"
739                            "\t*retval = (*rfunc)((%s *)object",
740                            s, retcast, s, (char *)m->gtktypes->data,
741                            g_list_length(m->gtktypes)-1, typebase);
742         }
743         print_signal_marsal_args(m);
744
745 }
746
747 static void
748 add_enums(Class *c)
749 {
750         GList *li;
751         out_printf(out, "\n");
752         if(signals>0) {
753                 out_printf(out, "enum {\n");
754                 for(li=c->nodes;li;li=g_list_next(li)) {
755                         Node *n = li->data;
756                         if(n->type == METHOD_NODE) {
757                                 Method *m = (Method *)n;
758                                 if(m->method == SIGNAL_LAST_METHOD ||
759                                    m->method == SIGNAL_FIRST_METHOD) {
760                                         char *s = g_strdup(get_real_id(m->id));
761                                         g_strup(s);
762                                         out_printf(out, "\t%s_SIGNAL,\n", s);
763                                         g_free(s);
764                                 }
765                         }
766                 }
767                 out_printf(out, "\tLAST_SIGNAL\n};\n\n");
768         }
769         if(arguments>0) {
770                 out_printf(out, "enum {\n\tARG_0");
771                 for(li=c->nodes;li;li=g_list_next(li)) {
772                         Node *n = li->data;
773                         if(n->type == ARGUMENT_NODE) {
774                                 Argument *a = (Argument *)n;
775                                 char *s = g_strdup(a->name);
776                                 g_strup(s);
777                                 out_printf(out, ",\n\tARG_%s", s);
778                                 g_free(s);
779                         }
780                 }
781                 out_printf(out, "\n};\n\n");
782         }
783
784         if(signals>0)
785                 out_printf(out,
786                            "static guint object_signals[LAST_SIGNAL] = {0};\n\n");
787
788         out_printf(out, "/* pointer to the class of our parent */\n");
789         out_printf(out, "static %sClass *parent_class = NULL;\n\n", ptypebase);
790 }
791
792 static void
793 add_get_type(void)
794 {
795         char *chunk_size = ((Class*)class)->chunk_size;
796         
797         out_printf(out, "guint\n"
798                 "%s_get_type (void)\n"
799                 "{\n"
800                 "\tstatic guint type = 0;\n\n"
801                 "\tif (!type) {\n"
802                 "\t\tstatic const GtkTypeInfo info = {\n"
803                 "\t\t\t\"%s\",\n"
804                 "\t\t\tsizeof (%s),\n"
805                 "\t\t\tsizeof (%sClass),\n"
806                 "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
807                 "\t\t\t(GtkObjectInitFunc) %s_init,\n"
808                 "\t\t\t/* reserved_1 */ NULL,\n"
809                 "\t\t\t/* reserved_2 */ NULL,\n"
810                 "\t\t\t(GtkClassInitFunc) NULL\n"
811                 "\t\t};\n\n"
812                 "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n",
813                 funcbase, typebase, typebase, typebase,
814                 funcbase, funcbase, pfuncbase);
815         if(chunk_size)  {
816                 out_printf(out, "#if %s > 0\n"
817                                 "\t\tgtk_type_set_chunk_alloc(type,%s);\n"
818                                 "#endif\n", 
819                                 chunk_size,  chunk_size);
820         }
821         out_printf(out,"\t}\n\n"
822                 "\treturn type;\n"
823                 "}\n\n");
824 }
825
826 static void
827 add_overrides(Class *c, char *oname, gboolean did_base_obj)
828 {
829         GList *li;
830         GHashTable *done;
831         char *s;
832         
833         done = g_hash_table_new(g_str_hash, g_str_equal);
834         if(did_base_obj) {
835                 s = g_strdup("GtkObject"); /* This was already done */
836                 g_hash_table_insert(done, s, s);
837                 s = g_strdup("GObject"); /* This was probably already done as well (if using Gtk/Glib 1.3/2.0) */
838                 g_hash_table_insert(done, s, s);
839         }
840         for(li=c->nodes; li; li=g_list_next(li)) {
841                 Node *n = li->data;
842                 char *f;
843                 Method *m = (Method *)n;
844                 if(n->type != METHOD_NODE ||
845                    m->method != OVERRIDE_METHOD)
846                         continue;
847
848                 s = remove_sep(m->otype);
849                 
850                 if(g_hash_table_lookup(done, s)) {
851                         g_free(s);
852                         continue;
853                 }
854                 g_hash_table_insert(done, s, s);
855
856                 f = replace_sep(m->otype, '_');
857                 g_strdown(f);
858
859                 out_printf(out, "\t%sClass *%s_class = (%sClass *)%s;\n",
860                            s, f, s, oname);
861                 
862                 g_free(f);
863         }
864         g_hash_table_foreach(done, (GHFunc)g_free, NULL);
865         g_hash_table_destroy(done);
866 }
867
868 static char *
869 make_run_signal_flags(Method *m, gboolean last)
870 {
871         GList *li;
872         GString *gs;
873         char *flags[] = {
874                 "FIRST",
875                 "LAST",
876                 "BOTH",
877                 "NO_RECURSE",
878                 "ACTION",
879                 "NO_HOOKS",
880                 NULL
881         };
882
883         gs = g_string_new(NULL);
884
885         if(last)
886                 g_string_assign(gs, "GTK_RUN_LAST");
887         else
888                 g_string_assign(gs, "GTK_RUN_FIRST");
889
890         if(m->scope == PUBLIC_SCOPE)
891                 g_string_append(gs, " | GTK_RUN_ACTION");
892
893         for(li = m->flags; li; li = li->next) {
894                 char *flag = li->data;
895                 int i;
896                 for(i=0;flags[i];i++) {
897                         if(strcmp(flags[i], flag)==0)
898                                 break;
899                 }
900                 /* if we haven't found it in our list */
901                 if(!flags[i]) {
902                         char *s;
903                         s = g_strdup_printf("Unknown flag '%s' used, "
904                                             "perhaps it was misspelled",
905                                             flag);
906                         print_error(TRUE, s, m->line_no);
907                         g_free(s);
908                 }
909                 g_string_sprintfa(gs, " | GTK_RUN_%s", flag);
910         }
911
912         {
913                 char *ret = gs->str;
914                 g_string_free(gs, FALSE);
915                 return ret;
916         }
917 }
918                 
919
920 static void
921 add_signals(Class *c)
922 {
923         GList *li;
924
925         out_printf(out, "\n");
926         for(li=c->nodes;li;li=g_list_next(li)) {
927                 Node *n = li->data;
928                 char *mar, *sig, *flags;
929                 gboolean is_none, last = FALSE;
930                 Method *m = (Method *)n;
931
932                 if(n->type != METHOD_NODE ||
933                    (m->method != SIGNAL_FIRST_METHOD &&
934                     m->method != SIGNAL_LAST_METHOD))
935                         continue;
936
937                 if(m->method == SIGNAL_FIRST_METHOD)
938                         last = FALSE;
939                 else
940                         last = TRUE;
941
942                 if(g_hash_table_lookup(marsh, m))
943                         mar = g_strconcat("___marshal_",
944                                           (char *)g_hash_table_lookup(marsh, m),
945                                           NULL);
946                 else
947                         mar = g_strdup("gtk_signal_default_marshaller");
948                 
949                 is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
950
951                 sig = g_strdup(get_real_id(m->id));
952                 g_strup(sig);
953                 flags = make_run_signal_flags(m, last);
954                 out_printf(out, "\tobject_signals[%s_SIGNAL] =\n"
955                         "\t\tgtk_signal_new (\"%s\",\n"
956                         "\t\t\t(GtkSignalRunType)(%s),\n"
957                         "\t\t\tGTK_CLASS_TYPE(gtk_object_class),\n"
958                         "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n"
959                         "\t\t\t%s,\n"
960                         "\t\t\tGTK_TYPE_%s, %d",
961                         sig, get_real_id(m->id),
962                         flags,
963                         typebase, get_real_id(m->id), mar,
964                         (char *)m->gtktypes->data,
965                         is_none?0:g_list_length(m->gtktypes->next));
966                 g_free(mar);
967                 g_free(sig);
968                 g_free(flags);
969                 
970                 if(!is_none) {
971                         GList *l;
972                         for(l=m->gtktypes->next;l;l=g_list_next(l))
973                                 out_printf(out, ",\n\t\t\tGTK_TYPE_%s",
974                                         (char *)l->data);
975                 }
976
977                 out_printf(out, ");\n");
978         }
979         out_printf(out, "\tgtk_object_class_add_signals (gtk_object_class,\n"
980                 "\t\tobject_signals, LAST_SIGNAL);\n\n");
981 }
982
983 static void
984 set_def_handlers(Class *c, char *oname)
985 {
986         GList *li;
987         gboolean set_line = FALSE;
988
989         out_printf(out, "\n");
990         for(li = c->nodes; li; li = g_list_next(li)) {
991                 Node *n = li->data;
992                 Method *m = (Method *)n;
993
994                 if(n->type != METHOD_NODE ||
995                    (m->method != SIGNAL_FIRST_METHOD &&
996                     m->method != SIGNAL_LAST_METHOD &&
997                     m->method != VIRTUAL_METHOD &&
998                     m->method != OVERRIDE_METHOD))
999                         continue;
1000
1001                 if(m->line_no > 0 && m->cbuf) {
1002                         out_addline_infile(out, m->line_no);
1003                         set_line = TRUE;
1004                 } else if(set_line) {
1005                         out_addline_outfile(out);
1006                         set_line = FALSE;
1007                 }
1008
1009
1010                 if(m->method == OVERRIDE_METHOD) {
1011                         char *s;
1012                         s = replace_sep(m->otype, '_');
1013                         g_strdown(s);
1014
1015                         if(need_destroy &&
1016                            destroy_handler &&
1017                            strcmp(m->id, "destroy") == 0)
1018                                 out_printf(out, "\tgtk_object_class->destroy "
1019                                            "= ___destroy;\n");
1020                         else if(need_finalize &&
1021                                 finalize_handler &&
1022                                 strcmp(m->id, "finalize") == 0)
1023                                 out_printf(out,
1024                                            "#ifdef G_OBJECT_CLASS\n"
1025                                            "\tg_object_class->finalize = ___finalize;\n"
1026                                            "#else /* !G_OBJECT_CLASS */\n"
1027                                            "\tgtk_object_class->finalize = ___finalize;\n"
1028                                            "#endif /* G_OBJECT_CLASS */\n");
1029                         else if(m->cbuf)
1030                                 out_printf(out,
1031                                            "\t%s_class->%s = ___%x_%s_%s;\n",
1032                                            s, m->id, (guint)m->unique_id,
1033                                            funcbase, m->id);
1034                         else
1035                                 out_printf(out, "\t%s_class->%s = NULL;\n",
1036                                            s, m->id);
1037                 } else {
1038                         if(m->cbuf)
1039                                 out_printf(out, "\t%s->%s = ___real_%s_%s;\n",
1040                                         oname, get_real_id(m->id),
1041                                         funcbase, get_real_id(m->id));
1042                         else
1043                                 out_printf(out, "\t%s->%s = NULL;\n",
1044                                         oname, get_real_id(m->id));
1045                 }
1046         }
1047         if(set_line)
1048                 out_addline_outfile(out);
1049 }
1050
1051 static void
1052 make_arguments(Class *c)
1053 {
1054         GList *li;
1055         char *argflags[] = {
1056                 "CONSTRUCT",
1057                 "CONSTRUCT_ONLY",
1058                 "CHILD_ARG",
1059                 "MASK",
1060                 NULL
1061         };
1062
1063         out_printf(out, "\n");
1064         for(li=c->nodes;li;li=g_list_next(li)) {
1065                 Node *n = li->data;
1066                 Argument *a;
1067                 GString *flags;
1068                 GList *l;
1069                 char *s;
1070                 if(n->type != ARGUMENT_NODE)
1071                         continue;
1072
1073                 a = (Argument *)n;
1074                 
1075                 if(a->get && a->set)
1076                         flags = g_string_new("GTK_ARG_READWRITE");
1077                 else if(a->get)
1078                         flags = g_string_new("GTK_ARG_READABLE");
1079                 else
1080                         flags = g_string_new("GTK_ARG_WRITABLE");
1081                 
1082                 for(l=a->flags;l;l=g_list_next(l)) {
1083                         char *flag = l->data;
1084                         int i;
1085                         if(strcmp(flag, "READWRITE")==0 ||
1086                            strcmp(flag, "READABLE")==0 ||
1087                            strcmp(flag, "WRITABLE")==0) {
1088                                 print_error(TRUE, "READWRITE, READABLE and "
1089                                             "WRITABLE argument flags are "
1090                                             "set automatically", a->line_no);
1091                                 continue;
1092                         }
1093                         for(i=0;argflags[i];i++) {
1094                                 if(strcmp(argflags[i], flag)==0)
1095                                         break;
1096                         }
1097                         /* if we haven't found it in our list */
1098                         if(!argflags[i]) {
1099                                 char *s;
1100                                 s = g_strdup_printf("Unknown flag '%s' used, "
1101                                                     "perhaps it was misspelled",
1102                                                     flag);
1103                                 print_error(TRUE, s, a->line_no);
1104                                 g_free(s);
1105                         }
1106                         g_string_sprintfa(flags, " | GTK_ARG_%s", flag);
1107                 }
1108
1109                 s = g_strdup(a->name);
1110                 g_strup(s);
1111                 out_printf(out, "\tgtk_object_add_arg_type(\"%s::%s\",\n"
1112                         "\t\tGTK_TYPE_%s,\n"
1113                         "\t\t%s,\n"
1114                         "\t\tARG_%s);\n",
1115                         typebase, a->name, a->gtktype, flags->str, s);
1116                 g_free(s);
1117                 g_string_free(flags, TRUE);
1118         }
1119         
1120         out_printf(out,
1121                    "\n\tgtk_object_class->set_arg = ___object_set_arg;\n"
1122                    "\tgtk_object_class->get_arg = ___object_get_arg;\n");
1123 }
1124
1125 static void
1126 print_initializer(Method *m, Variable *v)
1127 {
1128         char *root;
1129
1130         if(v->initializer == NULL)
1131                 return;
1132
1133         if(v->scope == PRIVATE_SCOPE)
1134                 root = g_strconcat(((FuncArg *)m->args->data)->name,
1135                                    "->_priv", NULL);
1136         else
1137                 root = g_strdup(((FuncArg *)m->args->data)->name);
1138
1139         if(v->initializer_line > 0)
1140                 out_addline_infile(out, v->initializer_line);
1141
1142         out_printf(out, "\t%s->%s = %s;\n",
1143                    root, v->id, v->initializer);
1144
1145         if(v->initializer_line > 0)
1146                 out_addline_outfile(out);
1147
1148         g_free(root);
1149 }
1150
1151 static void
1152 print_destructor(Variable *v)
1153 {
1154         char *root;
1155
1156         if(v->destructor == NULL)
1157                 return;
1158
1159         if(v->scope == PRIVATE_SCOPE)
1160                 root = "self->_priv";
1161         else
1162                 root = "self";
1163
1164         if(v->destructor_simple) {
1165                 if(v->destructor_line > 0)
1166                         out_addline_infile(out, v->destructor_line);
1167
1168                 out_printf(out, "\tif(%s->%s) { "
1169                            "((*(void (*)(void *))%s)) (%s->%s); "
1170                            "%s->%s = NULL; }\n",
1171                            root, v->id, v->destructor, root, v->id,
1172                            root, v->id);
1173
1174                 if(v->destructor_line > 0)
1175                         out_addline_outfile(out);
1176         } else {
1177                 out_printf(out, "#define VAR (%s->%s)\n", root, v->id);
1178                 out_printf(out, "\t{\n");
1179                 if(v->destructor_line > 0)
1180                         out_addline_infile(out, v->destructor_line);
1181
1182                 out_printf(out, "\t%s}\n", v->destructor);
1183
1184                 if(v->destructor_line > 0)
1185                         out_addline_outfile(out);
1186                 out_printf(out, "\tmemset(&VAR, 0, sizeof(VAR));\n");
1187                 out_printf(out, "#undef VAR\n");
1188         }
1189 }
1190
1191 static void
1192 add_destroy(Class *c)
1193 {
1194         out_printf(out, "\nstatic void\n"
1195                    "___destroy(GtkObject *obj_self)\n"
1196                    "{\n");
1197         out_printf(out,
1198                    "#define __GOB_FUNCTION__ \"%s::destroy\"\n",
1199                    c->otype);
1200
1201         if(destructors > 0) {
1202                 out_printf(out, "\t%s *self G_GNUC_UNUSED = %s (obj_self);\n",
1203                            typebase, macrobase);
1204         }
1205
1206         if(destroy_handler) {
1207                 /* so we get possible bad argument warning */
1208                 if(destroy_handler->line_no > 0)
1209                         out_addline_infile(out, destroy_handler->line_no);
1210                 out_printf(out, "\t___%x_%s_destroy(obj_self);\n",
1211                            (guint)destroy_handler->unique_id, funcbase);
1212                 if(destroy_handler->line_no > 0)
1213                         out_addline_outfile(out);
1214         } else {
1215                 out_printf(out,
1216                            "\tif(GTK_OBJECT_CLASS(parent_class)->destroy) \\\n"
1217                            "\t\t(* GTK_OBJECT_CLASS(parent_class)->destroy)(obj_self);\n");
1218         }
1219
1220         if(destructors > 0) {
1221                 GList *li;
1222                 for(li = ((Class *)class)->nodes;
1223                     li != NULL;
1224                     li = li->next) {
1225                         Node *n = li->data;
1226                         Variable *v = (Variable *)n;
1227                         if(n->type == VARIABLE_NODE &&
1228                            v->scope != CLASS_SCOPE)
1229                                 print_destructor(v);
1230                 }
1231         }
1232
1233         out_printf(out, "}\n"
1234                    "#undef __GOB_FUNCTION__\n\n");
1235 }
1236
1237 static void
1238 add_finalize(Class *c)
1239 {
1240         /* Sort of a hack to make it work with gtk+ 1.3/2.0 */
1241         out_printf(out,
1242                    "\n#ifdef G_OBJECT_CLASS\n"
1243                    "static void\n"
1244                    "___finalize(GObject *obj_self)\n"
1245                    "#else /* !G_OBJECT_CLASS */\n"
1246                    "static void\n"
1247                    "___finalize(GtkObject *obj_self)\n"
1248                    "#endif /* G_OBJECT_CLASS */\n"
1249                    "{\n");
1250         out_printf(out,
1251                    "#define __GOB_FUNCTION__ \"%s::finalize\"\n",
1252                    c->otype);
1253
1254         if(privates > 0) {
1255                 out_printf(out, "\t%s *self = %s (obj_self);\n",
1256                            typebase, macrobase);
1257         }
1258
1259         if(finalize_handler) {
1260                 /* so we get possible bad argument warning */
1261                 if(finalize_handler->line_no > 0)
1262                         out_addline_infile(out, finalize_handler->line_no);
1263                 out_printf(out, "\t___%x_%s_finalize(obj_self);\n",
1264                            (guint)finalize_handler->unique_id, funcbase);
1265                 if(finalize_handler->line_no > 0)
1266                         out_addline_outfile(out);
1267         } else {
1268                 /* Sort of a hack to make it work with gtk+ 1.3/2.0 */
1269                 out_printf(out,
1270                            "#ifdef G_OBJECT_CLASS\n"
1271                            "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
1272                            "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n"
1273                            "#else /* !G_OBJECT_CLASS */\n"
1274                            "\tif(GTK_OBJECT_CLASS(parent_class)->finalize) \\\n"
1275                            "\t\t(* GTK_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n"
1276                            "#endif /* G_OBJECT_CLASS */\n");
1277         }
1278
1279         if(privates > 0) {
1280                 out_printf(out, "\tg_free (self->_priv);\n"
1281                            "\tself->_priv = NULL;\n");
1282         }
1283
1284         out_printf(out, "}\n"
1285                    "#undef __GOB_FUNCTION__\n\n");
1286 }
1287
1288 static void
1289 add_inits(Class *c)
1290 {
1291         GList *li;
1292         for(li=c->nodes;li;li=g_list_next(li)) {
1293                 Node *n = li->data;
1294                 Method *m;
1295                 if(n->type != METHOD_NODE)
1296                         continue;
1297                 m = (Method *)n;
1298                 if(m->method == INIT_METHOD) {
1299                         if(m->line_no > 0)
1300                                 out_addline_infile(out, m->line_no);
1301                         print_method(out, "static ", "\n", "", " ", "\n",
1302                                      m, FALSE, FALSE, TRUE);
1303                         if(m->line_no > 0)
1304                                 out_addline_outfile(out);
1305                         out_printf(out, "{\n"
1306                                    "#define __GOB_FUNCTION__ \"%s::init\"\n",
1307                                    c->otype);
1308                         if(privates > 0) {
1309                                 out_printf(out, "\t%s->_priv = "
1310                                            "g_new0 (%sPrivate, 1);\n",
1311                                            ((FuncArg *)m->args->data)->name,
1312                                            typebase);
1313                         } else if(always_private_struct) {
1314                                 out_printf(out, "\t%s->_priv = NULL;\n",
1315                                            ((FuncArg *)m->args->data)->name);
1316                         }
1317                         if(initializers > 0) {
1318                                 GList *li;
1319                                 for(li = ((Class *)class)->nodes;
1320                                     li != NULL;
1321                                     li = li->next) {
1322                                         Node *n = li->data;
1323                                         Variable *v = (Variable *)n;
1324                                         if(n->type != VARIABLE_NODE ||
1325                                            v->scope == CLASS_SCOPE)
1326                                                 continue;
1327                                         print_initializer(m, v);
1328                                 }
1329                         }
1330                 } else if(m->method == CLASS_INIT_METHOD) {
1331                         gboolean did_base_obj = FALSE;
1332
1333                         if(m->line_no > 0)
1334                                 out_addline_infile(out, m->line_no);
1335                         print_method(out, "static ", "\n", "", " ", "\n",
1336                                      m, FALSE, FALSE, TRUE);
1337                         if(m->line_no > 0)
1338                                 out_addline_outfile(out);
1339                         out_printf(out, "{\n"
1340                                    "#define __GOB_FUNCTION__ \"%s::class_init\"\n",
1341                                    c->otype);
1342                         if(signals > 0 ||
1343                            arguments > 0 ||
1344                            need_destroy ||
1345                            need_finalize) {
1346                                 out_printf(out,
1347                                            "\tGtkObjectClass *"
1348                                            "gtk_object_class G_GNUC_UNUSED = "
1349                                            "(GtkObjectClass*) %s;\n",
1350                                            ((FuncArg *)m->args->data)->name);
1351                                 out_printf(out,
1352                                            "#ifdef G_OBJECT_CLASS\n"
1353                                            "\tGObjectClass *"
1354                                            "g_object_class G_GNUC_UNUSED = "
1355                                            "(GObjectClass*) %s;\n"
1356                                            "#endif /* G_OBJECT_CLASS */\n",
1357                                            ((FuncArg *)m->args->data)->name);
1358                                 did_base_obj = TRUE;
1359                         }
1360
1361                         if(overrides > 0)
1362                                 add_overrides(c,
1363                                               ((FuncArg *)m->args->data)->name,
1364                                               did_base_obj);
1365
1366                         if(initializers > 0) {
1367                                 GList *li;
1368                                 for(li = ((Class *)class)->nodes;
1369                                     li != NULL;
1370                                     li = li->next) {
1371                                         Node *n = li->data;
1372                                         Variable *v = (Variable *)n;
1373                                         if(n->type != VARIABLE_NODE ||
1374                                            v->scope != CLASS_SCOPE)
1375                                                 continue;
1376                                         print_initializer(m, v);
1377                                 }
1378                         }
1379                         
1380                         out_printf(out, "\n\tparent_class = ");
1381                         if(for_cpp)
1382                                 out_printf(out, "(%sClass *)", ptypebase);
1383                         out_printf(out, "gtk_type_class (%s_get_type ());\n",
1384                                    pfuncbase);
1385
1386                         if(signals > 0)
1387                                 add_signals(c);
1388
1389                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
1390
1391                         /* if there are no handlers for these things, we
1392                          * need to set them up here */
1393                         if(need_destroy && !destroy_handler)
1394                                 out_printf(out, "\tgtk_object_class->destroy "
1395                                            "= ___destroy;\n");
1396                         if(need_finalize && !finalize_handler)
1397                                 out_printf(out,
1398                                            "#ifdef G_OBJECT_CLASS\n"
1399                                            "\tg_object_class->finalize = ___finalize;\n"
1400                                            "#else /* !G_OBJECT_CLASS */\n"
1401                                            "\tgtk_object_class->finalize = ___finalize;\n"
1402                                            "#endif /* G_OBJECT_CLASS */\n");
1403                         
1404                         if(arguments > 0)
1405                                 make_arguments(c);
1406
1407                 } else
1408                         continue;
1409
1410                 if(m->cbuf) {
1411                         out_printf(out, " {\n");
1412                         out_addline_infile(out, m->ccode_line);
1413                         out_printf(out, "%s\n", m->cbuf);
1414                         out_addline_outfile(out);
1415                         out_printf(out, " }\n");
1416                 } else {
1417                         out_printf(out, "return;\n");
1418                 }
1419                 out_printf(out, "}\n"
1420                            "#undef __GOB_FUNCTION__\n");
1421         }
1422 }
1423
1424 static void
1425 add_getset_arg(Class *c, gboolean is_set)
1426 {
1427         GList *li;
1428         out_printf(out, "\nstatic void\n"
1429                    "___object_%s_arg (GtkObject *object,\n"
1430                    "\tGtkArg *arg,\n"
1431                    "\tguint arg_id)\n"
1432                    "#define __GOB_FUNCTION__ \"%s::%s_arg\"\n"
1433                    "{\n"
1434                    "\t%s *self;\n\n"
1435                    "\tself = %s (object);\n\n"
1436                    "\tswitch (arg_id) {\n",
1437                    is_set ? "set" : "get",
1438                    c->otype, is_set ? "set" : "get",
1439                    typebase, macrobase);
1440
1441         for(li=c->nodes;li;li=g_list_next(li)) {
1442                 Node *n = li->data;
1443                 Argument *a;
1444                 char *s;
1445                 char *cbuf;
1446                 int line_no;
1447                 if(n->type != ARGUMENT_NODE)
1448                         continue;
1449                 a = (Argument *)n;
1450                 if(is_set) {
1451                         cbuf = a->set;
1452                         line_no = a->set_line;
1453                 } else {
1454                         cbuf = a->get;
1455                         line_no = a->get_line;
1456                 }
1457                 if(!cbuf)
1458                         continue;
1459                 s = g_strdup(a->name);
1460                 g_strup(s);
1461                 out_printf(out, "\tcase ARG_%s:\n", s);
1462                 if(is_set && a->atype) {
1463                         char *cast = get_type(a->atype, TRUE);
1464                         if(no_gnu || for_cpp) {
1465                                 out_printf(out, "#define ARG "
1466                                            "((%s)GTK_VALUE_%s(*arg))\n",
1467                                            cast, a->gtktype);
1468                         } else {
1469                                 out_printf(out, "#ifdef __GNUC__\n");
1470                                 if(strcmp(a->gtktype, "OBJECT")==0) {
1471                                         out_printf(out, "#define ARG "
1472                                                    "({%s foo = "
1473                                                    "GTK_VALUE_POINTER(*arg); "
1474                                                    "foo; })\n",
1475                                                    cast);
1476                                 } else {
1477                                         out_printf(out, "#define ARG "
1478                                                    "({%s foo = "
1479                                                    "GTK_VALUE_%s(*arg); "
1480                                                    "foo; })\n",
1481                                                    cast, a->gtktype);
1482                                 }
1483                                 out_printf(out, "#else /* __GNUC__ */\n");
1484                                 out_printf(out, "#define ARG "
1485                                            "((%s)GTK_VALUE_%s(*arg))\n",
1486                                            cast, a->gtktype);
1487                                 out_printf(out, "#endif /* __GNUC__ */\n\n");
1488                         }
1489                         out_printf(out, "\t\t{\n");
1490                         g_free(cast);
1491                 } else if(!is_set && strcmp(a->gtktype, "OBJECT")==0) {
1492                         out_printf(out,
1493                                    "#define ARG (GTK_VALUE_POINTER(*arg))\n"
1494                                    "\t\t{\n");
1495                 } else {
1496                         out_printf(out,
1497                                    "#define ARG (GTK_VALUE_%s(*arg))\n"
1498                                    "\t\t{\n",
1499                                    a->gtktype);
1500                 }
1501                 g_free(s);
1502                 if(line_no > 0)
1503                         out_addline_infile(out, line_no);
1504                 out_printf(out, "%s\n", cbuf);
1505                 if(line_no > 0)
1506                         out_addline_outfile(out);
1507                 out_printf(out, "\t\t}\n\t\tbreak;\n"
1508                         "#undef ARG\n");
1509         }
1510         out_printf(out, "\tdefault:\n\t\tbreak;\n\t}\n}\n"
1511                    "#undef __GOB_FUNCTION__\n");
1512 }
1513
1514 static void
1515 print_checks(Method *m, FuncArg *fa)
1516 {
1517         GList *li;
1518         gboolean is_void;
1519         gboolean checked_null = FALSE;
1520         is_void = (strcmp(m->mtype->name, "void")==0 &&
1521                    m->mtype->pointer == NULL);
1522         
1523         for(li = fa->checks; li; li = g_list_next(li)) {
1524                 Check *ch = li->data;
1525                 char *s;
1526                 /* point to the method prot in .gob for failed checks */
1527                 if(m->line_no > 0)
1528                         out_addline_infile(out, m->line_no);
1529                 if(is_void)
1530                         out_printf(out, "\tg_return_if_fail (");
1531                 else
1532                         out_printf(out, "\tg_return_val_if_fail (");
1533                 switch(ch->chtype) {
1534                 case NULL_CHECK:
1535                         out_printf(out, "%s != NULL", fa->name);
1536                         checked_null = TRUE;
1537                         break;
1538                 case TYPE_CHECK:
1539                         s = make_pre_macro(fa->atype->name, "IS");
1540                         if(checked_null)
1541                                 out_printf(out, "%s (%s)", s, fa->name);
1542                         else
1543                                 /* if not check null, null may be valid */
1544                                 out_printf(out, "!(%s) || %s (%s)", fa->name,
1545                                            s, fa->name);
1546                         g_free(s);
1547                         break;
1548                 case LT_CHECK:
1549                         out_printf(out, "%s < %s", fa->name, ch->number);
1550                         break;
1551                 case GT_CHECK:
1552                         out_printf(out, "%s > %s", fa->name, ch->number);
1553                         break;
1554                 case LE_CHECK:
1555                         out_printf(out, "%s <= %s", fa->name, ch->number);
1556                         break;
1557                 case GE_CHECK:
1558                         out_printf(out, "%s >= %s", fa->name, ch->number);
1559                         break;
1560                 case EQ_CHECK:
1561                         out_printf(out, "%s == %s", fa->name, ch->number);
1562                         break;
1563                 case NE_CHECK:
1564                         out_printf(out, "%s != %s", fa->name, ch->number);
1565                         break;
1566                 }
1567                 if(is_void)
1568                         out_printf(out, ");\n");
1569                 else {
1570                         out_printf(out, ", (");
1571                         print_type(out, m->mtype, TRUE);
1572                         out_printf(out, ")%s);\n",
1573                                 m->onerror?m->onerror:"0");
1574                 }
1575         }
1576 }
1577
1578 static void
1579 print_preconditions(Method *m)
1580 {
1581         GList *li;
1582         
1583         for(li=m->args;li;li=g_list_next(li)) {
1584                 FuncArg *fa = li->data;
1585                 if(fa->checks)
1586                         print_checks(m, fa);
1587         }
1588         if(m->line_no>0)
1589                 out_addline_outfile(out);
1590 }
1591
1592 static void
1593 print_method_body(Method *m, int pre)
1594 {
1595         out_printf(out, "{\n"
1596                    "#define __GOB_FUNCTION__ \"%s::%s\"\n",
1597                    ((Class *)class)->otype,
1598                    get_real_id(m->id));
1599         if(pre)
1600                 print_preconditions(m);
1601
1602         /* Note: the trailing }'s are on one line, this is so
1603            that we get the no return warning correctly and point to
1604            the correct line in the .gob file, yes this is slightly
1605            ugly in the .c file, but that is not supposed to be
1606            human readable anyway. */
1607         if(m->cbuf) {
1608                 out_printf(out, "{\n");
1609                 if(m->ccode_line>0)
1610                         out_addline_infile(out, m->ccode_line);
1611                 out_printf(out, "\t%s}", m->cbuf);
1612         }
1613
1614         /* Note, there is no \n between the last } and this } so that
1615          * errors/warnings reported on the end of the body get pointed to the
1616          * right line in the .gob source */
1617         out_printf(out, "}\n");
1618
1619         if(m->cbuf)
1620                 out_addline_outfile(out);
1621         out_printf(out, "#undef __GOB_FUNCTION__\n");
1622 }
1623
1624 static void
1625 put_signal_args(Method *m)
1626 {
1627         GList *li;
1628         GList *ali;
1629         for(ali = m->gtktypes->next, li=m->args->next;
1630             li && ali;
1631             li=li->next, ali=ali->next) {
1632                 FuncArg *fa = li->data;
1633                 const char *cast = get_cast(ali->data, FALSE);
1634                 /* we should have already proved before that
1635                    the we know all the types */
1636                 g_assert(cast);
1637
1638                 out_printf(out, ",\n\t\t(%s)%s", cast,
1639                            fa->name);
1640         }
1641 }
1642
1643 static char *
1644 get_arg_names_for_macro(Method *m)
1645 {
1646         char *p;
1647         GList *li;
1648         GString *gs = g_string_new(NULL);
1649         p = "";
1650         for(li=m->args;li;li=g_list_next(li)) {
1651                 FuncArg *arg = li->data;
1652                 g_string_sprintfa(gs, "%s___%s", p, arg->name);
1653                 p = ",";
1654         }
1655         p = gs->str;
1656         g_string_free(gs, FALSE);
1657         return p;
1658 }
1659
1660 static void
1661 put_method(Method *m)
1662 {
1663         char *s, *args, *doc;
1664         gboolean is_void;
1665         is_void = (strcmp(m->mtype->name, "void")==0 &&
1666                    m->mtype->pointer == NULL);
1667         out_printf(out, "\n");
1668         if(m->method != OVERRIDE_METHOD) {
1669                 doc = get_gtk_doc(m->id);
1670                 if(doc) {
1671                         out_printf(out, "%s", doc);
1672                         g_free(doc);
1673                 }
1674         }
1675         switch(m->method) {
1676         case REGULAR_METHOD:
1677                 if(m->line_no > 0)
1678                         out_addline_infile(out, m->line_no);
1679                 if(m->scope == PRIVATE_SCOPE)
1680                         print_method(out, "static ", "\n", "", " ", "\n",
1681                                      m, FALSE, FALSE, TRUE);
1682                 else /* PUBLIC, PROTECTED */
1683                         print_method(out, "", "\n", "", " ", "\n",
1684                                      m, FALSE, FALSE, TRUE);
1685                 print_method_body(m, TRUE);
1686                 /* the outfile line was added above */
1687                 break;
1688         case SIGNAL_FIRST_METHOD:
1689         case SIGNAL_LAST_METHOD:
1690                 if(m->line_no > 0)
1691                         out_addline_infile(out, m->line_no);
1692                 if(m->scope == PRIVATE_SCOPE)
1693                         print_method(out, "static ", "\n", "", " ", "\n",
1694                                      m, FALSE, FALSE, TRUE);
1695                 else /* PUBLIC, PROTECTED */
1696                         print_method(out, "", "\n", "", " ", "\n",
1697                                      m, FALSE, FALSE, TRUE);
1698                 out_addline_outfile(out);
1699                 out_printf(out, "{\n");
1700                 s = g_strdup(get_real_id(m->id));
1701                 g_strup(s);
1702                 if(strcmp(m->mtype->name, "void") == 0 &&
1703                    m->mtype->pointer == NULL) {
1704                         print_preconditions(m);
1705                         if(((FuncArg *)m->args->data)->name)
1706                         out_printf(out, "\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1707                                 "\t\tobject_signals[%s_SIGNAL]",
1708                                 ((FuncArg *)m->args->data)->name, s);
1709                         put_signal_args(m);
1710                         out_printf(out, ");\n}\n");
1711                 } else {
1712                         out_printf(out, "\t");
1713                         print_type(out, m->mtype, TRUE);
1714                         out_printf(out, "return_val = (");
1715                         print_type(out, m->mtype, TRUE);
1716                         if(m->defreturn)
1717                                 out_printf(out, ")(%s);\n", m->defreturn);
1718                         else if(m->onerror)
1719                                 out_printf(out, ")(%s);\n", m->onerror);
1720                         else
1721                                 out_printf(out, ")(0);\n");
1722                         print_preconditions(m);
1723                         out_printf(out, "\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1724                                 "\t\tobject_signals[%s_SIGNAL]",
1725                                 ((FuncArg *)m->args->data)->name, s);
1726                         put_signal_args(m);
1727                         out_printf(out, ",\n\t\t&return_val);\n"
1728                                 "\treturn return_val;\n}\n");
1729                 }
1730
1731                 if(!m->cbuf)
1732                         break;
1733                 if(m->line_no > 0)
1734                         out_addline_infile(out, m->line_no);
1735                 print_method(out, "static ", "\n___real_", "", " ", "\n",
1736                              m, FALSE, FALSE, TRUE);
1737                 print_method_body(m, FALSE);
1738                 /* the outfile line was added above */
1739                 break;
1740         case VIRTUAL_METHOD:
1741                 if(m->line_no > 0)
1742                         out_addline_infile(out, m->line_no);
1743                 if(m->scope==PRIVATE_SCOPE)
1744                         print_method(out, "static ", "\n", "", " ", "\n",
1745                                      m, FALSE, FALSE, TRUE);
1746                 else /* PUBLIC, PROTECTED */
1747                         print_method(out, "", "\n", "", " ", "\n",
1748                                      m, FALSE, FALSE, TRUE);
1749                 out_addline_outfile(out);
1750                 out_printf(out, "{\n"
1751                         "\t%sClass *klass;\n", typebase);
1752                 print_preconditions(m);
1753                 out_printf(out, "\tklass = %s_GET_CLASS(%s);\n\n"
1754                         "\tif(klass->%s)\n",
1755                         macrobase, ((FuncArg *)m->args->data)->name,
1756                         get_real_id(m->id));
1757                 if(strcmp(m->mtype->name, "void") == 0 &&
1758                    m->mtype->pointer == NULL) {
1759                         GList *li;
1760                         out_printf(out, "\t\t(*klass->%s)(%s",
1761                                    get_real_id(m->id),
1762                                    ((FuncArg *)m->args->data)->name);
1763                         for(li=m->args->next;li;li=g_list_next(li)) {
1764                                 FuncArg *fa = li->data;
1765                                 out_printf(out, ",%s", fa->name);
1766                         }
1767                         out_printf(out, ");\n}\n");
1768                 } else {
1769                         GList *li;
1770                         out_printf(out, "\t\treturn (*klass->%s)(%s",
1771                                    get_real_id(m->id),
1772                                    ((FuncArg *)m->args->data)->name);
1773                         for(li=m->args->next;li;li=g_list_next(li)) {
1774                                 FuncArg *fa = li->data;
1775                                 out_printf(out, ",%s", fa->name);
1776                         }
1777                         out_printf(out, ");\n"
1778                                 "\telse\n"
1779                                 "\t\treturn (");
1780                         print_type(out, m->mtype, TRUE);
1781                         if(m->defreturn)
1782                                 out_printf(out, ")(%s);\n}\n", m->defreturn);
1783                         else if(m->onerror)
1784                                 out_printf(out, ")(%s);\n}\n", m->onerror);
1785                         else
1786                                 out_printf(out, ")(0);\n}\n");
1787                 }
1788
1789                 if(!m->cbuf)
1790                         break;
1791                 if(m->line_no > 0)
1792                         out_addline_infile(out, m->line_no);
1793                 print_method(out, "static ", "\n___real_", "", " ", "\n",
1794                              m, FALSE, FALSE, TRUE);
1795                 print_method_body(m, FALSE);
1796                 /* the outfile line was added above */
1797                 break;
1798         case OVERRIDE_METHOD:
1799                 if(!m->cbuf)
1800                         break;
1801                 if(m->line_no > 0)
1802                         out_addline_infile(out, m->line_no);
1803                 s = g_strdup_printf("\n___%x_", (guint)m->unique_id);
1804                 print_method(out, "static ", s, "", " ", "\n",
1805                              m, FALSE, FALSE, FALSE);
1806                 g_free(s);
1807                 out_addline_outfile(out);
1808                 s = replace_sep(m->otype, '_');
1809                 g_strup(s);
1810                 args = get_arg_names_for_macro(m);
1811                 if(is_void) {
1812                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
1813                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
1814                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n",
1815                                    args, s, m->id, s, m->id, args);
1816                 } else {
1817                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
1818                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
1819                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n"
1820                                    "\t\t(",
1821                                    args, s, m->id, s, m->id, args);
1822                         out_printf(out, "(");
1823                         print_type(out, m->mtype, TRUE);
1824                         out_printf(out, ")%s))\n",
1825                                    m->onerror?m->onerror:"0");
1826                 }
1827                 g_free(args);
1828                 g_free(s);
1829                 print_method_body(m, TRUE);
1830                 /* the outfile line was added above */
1831                 out_printf(out, "#undef PARENT_HANDLER\n");
1832                 break;
1833         default:
1834                 break;
1835         }
1836 }
1837
1838 static void
1839 open_files(void)
1840 {
1841         char *outfile, *outfileh, *outfileph;
1842
1843         if(!for_cpp)
1844                 outfile = g_strconcat(filebase, ".c", NULL);
1845         else
1846                 outfile = g_strconcat(filebase, ".cc", NULL);
1847         if(no_touch_headers)
1848                 outfileh = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
1849         else
1850                 outfileh = g_strconcat(filebase, ".h", NULL);
1851
1852         if((privates > 0 || protecteds > 0 ||
1853             private_header == PRIVATE_HEADER_ALWAYS) &&
1854            private_header != PRIVATE_HEADER_NEVER)
1855                 outfileph = g_strconcat(filebase, "-private.h", NULL);
1856         else
1857                 outfileph = NULL;
1858
1859         
1860         if(no_write) {
1861                 devnull = fopen("/dev/null", "w");
1862                 if(!devnull)
1863                         g_error("Cannot open null device");
1864                 out = devnull;
1865                 outh = devnull;
1866                 if(outfileph)
1867                         outph = devnull;
1868         } else {
1869                 out = fopen(outfile, "w");
1870                 if(!out) {
1871                         g_error("Cannot open outfile: %s", outfile);
1872                 }
1873                 outh = fopen(outfileh, "w");
1874                 if(!outh)
1875                         g_error("Cannot open outfile: %s", outfileh);
1876                 if(outfileph) {
1877                         outph = fopen(outfileph, "w");
1878                         if(!outph)
1879                                 g_error("Cannot open outfile: %s", outfileh);
1880                 }
1881         }
1882 }
1883
1884 static void
1885 put_argument_nongnu_wrappers(Class *c)
1886 {
1887         GList *li;
1888
1889         if(arguments<0)
1890                 return;
1891
1892         for(li=c->nodes;li;li=g_list_next(li)) {
1893                 Node *n = li->data;
1894                 Argument *a = (Argument *)n;
1895                 char *aname;
1896                 char *cast;
1897
1898                 if(n->type != ARGUMENT_NODE)
1899                         continue;
1900
1901                 aname = g_strdup(a->name);
1902                 g_strup(aname);
1903
1904                 if(a->atype)
1905                         cast = get_type(a->atype, TRUE);
1906                 else
1907                         cast = g_strdup(get_cast(a->gtktype, TRUE));
1908
1909                 if(cast) {
1910                         if(a->set)
1911                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1912                                            "\"%s\",(%s)(arg)\n",
1913                                            macrobase, aname, a->name, cast);
1914                         if(a->get)
1915                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1916                                            "\"%s\",(%s*)(arg)\n",
1917                                            macrobase, aname, a->name, cast);
1918                 } else {
1919                         if(a->set)
1920                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1921                                            "\"%s\",(arg)\n",
1922                                            macrobase, aname, a->name);
1923                         if(a->get)
1924                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1925                                            "\"%s\",(arg)\n",
1926                                            macrobase, aname, a->name);
1927                 }
1928                 g_free(cast);
1929                 g_free(aname);
1930         }
1931 }
1932
1933 static void
1934 put_argument_gnu_wrappers(Class *c)
1935 {
1936         GList *li;
1937
1938         if(arguments<0)
1939                 return;
1940
1941         for(li=c->nodes;li;li=g_list_next(li)) {
1942                 Node *n = li->data;
1943                 Argument *a = (Argument *)n;
1944                 char *s;
1945                 char *cast;
1946                 if(n->type != ARGUMENT_NODE)
1947                         continue;
1948                 s = g_strdup(a->name);
1949                 g_strup(s);
1950                 if(a->atype)
1951                         cast = get_type(a->atype, TRUE);
1952                 else
1953                         cast = g_strdup(get_cast(a->gtktype, TRUE));
1954                 if(cast) {
1955                         if(a->set)
1956                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1957                                            "\"%s\",({%sz = (arg); z;})\n",
1958                                            macrobase, s, a->name, cast);
1959                         if(a->get)
1960                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1961                                            "\"%s\",({%s*z = (arg); z;})\n",
1962                                            macrobase, s, a->name, cast);
1963                 } else {
1964                         if(a->set)
1965                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1966                                            "\"%s\",(arg)\n",
1967                                            macrobase, s, a->name);
1968                         if(a->get)
1969                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1970                                            "\"%s\",(arg)\n",
1971                                            macrobase, s, a->name);
1972                 }
1973                 g_free(cast);
1974                 g_free(s);
1975         }
1976 }
1977
1978 static void
1979 print_ccode_block(CCode *cc)
1980 {
1981         FILE *fp;
1982         switch(cc->cctype) {
1983         case HT_CCODE:
1984                 /* HT code is printed exactly like normal header
1985                    code but is printed before */
1986         case H_CCODE:
1987                 fp = outh;
1988                 out_printf(fp, "\n");
1989                 break;
1990         case AT_CCODE:
1991                 /* AT code is printed exactly like normal 'all'
1992                    code but is printed before */
1993         case A_CCODE:
1994                 if(outph) {
1995                         out_printf(outph, "\n");
1996                         out_printf(outph, "%s\n", cc->cbuf);
1997                         out_addline_infile(outph, cc->line_no);
1998                         out_addline_outfile(outph);
1999                 }
2000                 out_printf(outh, "\n");
2001                 out_printf(outh, "%s\n", cc->cbuf);
2002                 fp = out;
2003                 out_printf(fp, "\n");
2004                 out_addline_infile(fp, cc->line_no);
2005                 break;
2006         default:
2007         case C_CCODE:
2008                 fp = out;
2009                 out_printf(fp, "\n");
2010                 out_addline_infile(fp, cc->line_no);
2011                 break;
2012         case PH_CCODE:
2013                 if(outph)
2014                         fp = outph;
2015                 else
2016                         fp = out;
2017                 out_printf(fp, "\n");
2018                 out_addline_infile(fp, cc->line_no);
2019                 break;
2020         }
2021         out_printf(fp, "%s\n", cc->cbuf);
2022         if(cc->cctype == C_CCODE ||
2023            cc->cctype == A_CCODE ||
2024            cc->cctype == AT_CCODE ||
2025            cc->cctype == PH_CCODE)
2026                 out_addline_outfile(fp);
2027 }
2028
2029 static void
2030 print_class_block(Class *c)
2031 {
2032         GList *l;
2033         char *s;
2034         gboolean printed_private = FALSE;
2035
2036         if(any_special) {
2037                 out_printf(out, "/* utility types we may need */\n");
2038                 if(special_array[SPECIAL_2POINTER])
2039                         out_printf(out, "typedef struct { "
2040                                    "gpointer a; gpointer b; "
2041                                    "} ___twopointertype;\n");
2042                 if(special_array[SPECIAL_3POINTER])
2043                         out_printf(out, "typedef struct { "
2044                                    "gpointer a; gpointer b; "
2045                                    "gpointer c; "
2046                                    "} ___threepointertype;\n");
2047                 if(special_array[SPECIAL_INT_POINTER])
2048                         out_printf(out, "typedef struct { "
2049                                    "gint a; gpointer b; "
2050                                    "} ___intpointertype;\n");
2051                 out_printf(out, "\n");
2052         }
2053
2054         out_printf(outh, "\n/*\n"
2055                    " * Type checking and casting macros\n"
2056                    " */\n");
2057         out_printf(outh, "#define %s\t"
2058                    "(%s_get_type())\n",
2059                    macrotype, funcbase);
2060         out_printf(outh, "#define %s(obj)\t"
2061                    "GTK_CHECK_CAST((obj), %s_get_type(), %s)\n",
2062                    macrobase, funcbase, typebase);
2063         out_printf(outh, "#define %s_CONST(obj)\t"
2064                    "GTK_CHECK_CAST((obj), %s_get_type(), %s const)\n",
2065                    macrobase, funcbase, typebase); 
2066         out_printf(outh, "#define %s_CLASS(klass)\t"
2067                    "GTK_CHECK_CLASS_CAST((klass), %s_get_type(), %sClass)\n",
2068                    macrobase, funcbase, typebase);
2069         out_printf(outh, "#define %s(obj)\t"
2070                    "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
2071                    macrois, funcbase);
2072         out_printf(outh, "#ifdef GTK_CHECK_GET_CLASS\n"
2073                    "#define %s_GET_CLASS(obj)\t"
2074                    "GTK_CHECK_GET_CLASS((obj), %s_get_type(), %sClass)\n",
2075                    macrobase, funcbase, typebase);
2076         out_printf(outh, "#else /* !GTK_CHECK_GET_CLASS */\n"
2077                    "#define %s_GET_CLASS(obj)\t"
2078                    "((%sClass *)GTK_OBJECT(obj)->klass)\n"
2079                    "#endif /* GTK_CHECK_GET_CLASS */\n",
2080                    macrobase, typebase);
2081
2082         if( ! no_self_alias) {
2083                 out_printf(out, "/* self casting macros */\n");
2084                 out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
2085                 out_printf(out, "#define SELF_CONST(x) %s_CONST(x)\n", macrobase);
2086                 out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
2087                 out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n",
2088                            macrobase);
2089                 out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n",
2090                            macrobase);
2091
2092                 out_printf(out, "/* self typedefs */\n");
2093                 out_printf(out, "typedef %s Self;\n", typebase);
2094                 out_printf(out, "typedef %sClass SelfClass;\n\n", typebase);
2095         }
2096
2097         out_printf(out, "/* GTK_CLASS_TYPE for 1.2<->1.3/2.0 GTK+ compatibility */\n");
2098         out_printf(out,
2099                    "#ifndef GTK_CLASS_TYPE\n"
2100                    "#define GTK_CLASS_TYPE(x) (GTK_OBJECT_CLASS(x)->type)\n"
2101                    "#endif /* GTK_CLASS_TYPE */\n\n");
2102
2103         if(privates > 0 || always_private_struct) {
2104                 out_printf(outh, "\n/* Private structure type */\n");
2105                 out_printf(outh, "typedef struct _%sPrivate %sPrivate;\n",
2106                            typebase, typebase);
2107                 if(privates == 0)
2108                         out_printf(outh, "/* There are no privates, this "
2109                                    "structure is thus never defined */\n");
2110         }
2111
2112         out_printf(outh, "\n/*\n"
2113                    " * Main object structure\n"
2114                    " */\n");
2115         s = replace_sep(c->otype, '_');
2116         g_strup(s);
2117         out_printf(outh, "#ifndef __TYPEDEF_%s__\n"
2118                    "#define __TYPEDEF_%s__\n", s, s);
2119         g_free(s);
2120         out_printf(outh, "typedef struct _%s %s;\n"
2121                    "#endif\n", typebase, typebase);
2122         out_printf(outh, "struct _%s {\n\t%s __parent__;\n",
2123                    typebase, ptypebase);
2124         for(l=c->nodes; l; l=g_list_next(l)) {
2125                 static gboolean printed_public = FALSE;
2126                 Node *n = l->data;
2127                 Variable *v = (Variable *)n;
2128                 if(n->type == VARIABLE_NODE &&
2129                    v->scope == PUBLIC_SCOPE) {
2130                         if( ! printed_public) {
2131                                 out_printf(outh, "\t/*< public >*/\n");
2132                                 printed_public = TRUE;
2133                         }
2134                         put_variable((Variable *)n, outh);
2135                 }
2136         }
2137         /* put protecteds always AFTER publics */
2138         for(l=c->nodes; l; l=g_list_next(l)) {
2139                 Node *n = l->data;
2140                 Variable *v = (Variable *)n;
2141                 if(n->type == VARIABLE_NODE &&
2142                    v->scope == PROTECTED_SCOPE) {
2143                         if( ! printed_private) {
2144                                 out_printf(outh, "\t/*< private >*/\n");
2145                                 printed_private = TRUE;
2146                         }
2147                         put_variable((Variable *)n, outh);
2148                 }
2149         }
2150         if(privates > 0 || always_private_struct) {
2151                 if( ! printed_private)
2152                         out_printf(outh, "\t/*< private >*/\n");
2153                 out_printf(outh, "\t%sPrivate *_priv;\n", typebase);
2154         }
2155         out_printf(outh, "};\n");
2156
2157         if(privates > 0) {
2158                 FILE *outfp;
2159
2160                 /* if we are to stick this into the private
2161                    header, if not stick it directly into the
2162                    C file */
2163                 if(outph) 
2164                         outfp = outph;
2165                 else
2166                         outfp = out;
2167
2168                 out_printf(outfp, "struct _%sPrivate {\n",
2169                            typebase);
2170                 for(l=c->nodes; l; l=l->next) {
2171                         Node *n = l->data;
2172                         Variable *v = (Variable *)n;
2173                         if(n->type == VARIABLE_NODE &&
2174                            v->scope == PRIVATE_SCOPE) {
2175                                 out_addline_infile(outfp, v->line_no);
2176                                 put_variable(v, outfp);
2177                         }
2178                 }
2179                 out_addline_outfile(outfp);
2180                 out_printf(outfp, "};\n");
2181         }
2182
2183         out_printf(outh, "\n/*\n"
2184                    " * Class definition\n"
2185                    " */\n");
2186         out_printf(outh, "typedef struct _%sClass %sClass;\n",
2187                    typebase, typebase);
2188         out_printf(outh,
2189                    "struct _%sClass {\n\t%sClass __parent__;\n",
2190                    typebase, ptypebase);
2191         for(l = c->nodes; l != NULL; l = l->next) {
2192                 Node *n = l->data;
2193                 if(n->type == METHOD_NODE)
2194                         put_vs_method((Method *)n);
2195         }
2196         /* put class scope variables */
2197         for(l = c->nodes; l != NULL; l = l->next) {
2198                 Node *n = l->data;
2199                 Variable *v = (Variable *)n;
2200                 if(n->type == VARIABLE_NODE &&
2201                    v->scope == CLASS_SCOPE)
2202                         put_variable((Variable *)n, outh);
2203         }
2204         out_printf(outh, "};\n\n");
2205
2206         out_printf(out, "/* here are local prototypes */\n");
2207         if(arguments > 0) {
2208                 out_printf(out, "static void ___object_set_arg "
2209                            "(GtkObject *object, GtkArg *arg, "
2210                            "guint arg_id);\n"
2211                            "static void ___object_get_arg "
2212                            "(GtkObject *object, GtkArg *arg, "
2213                            "guint arg_id);\n");
2214         }
2215
2216         out_printf(outh, "\n/*\n"
2217                    " * Public methods\n"
2218                    " */\n");
2219
2220         out_printf(outh, "guint\t%s_get_type\t(void);\n", funcbase);
2221         for(l = c->nodes; l != NULL; l = l->next) {
2222                 Node *n = l->data;
2223                 if(n->type == METHOD_NODE) {
2224                         put_pub_method((Method *)n);
2225                         put_prot_method((Method *)n);
2226                         put_priv_method_prot((Method *)n);
2227                 }
2228         }
2229
2230 /* this idea is less and less apealing to me */
2231 #if 0
2232         if(!no_signal_connect) {
2233                 if(signals>0) {
2234                         out_printf(outh, "\n/*\n"
2235                                    " * Signal connection methods\n"
2236                                    " */\n");
2237                 }
2238
2239                 for(l=c->nodes;l;l=g_list_next(l)) {
2240                         Node *n = l->data;
2241                         if(n->type == METHOD_NODE)
2242                                 put_signal_connect((Method *)n);
2243                 }
2244         }
2245 #endif
2246
2247
2248         /* argument wrapping macros */
2249         if(arguments > 0 && ! no_gnu) {
2250                 out_printf(outh, "\n/*\n"
2251                            " * Argument wrapping macros\n"
2252                            " */\n");
2253                 out_printf(outh, "#ifdef __GNUC__\n");
2254                 put_argument_gnu_wrappers(c);
2255                 out_printf(outh, "#else /* __GNUC__ */\n");
2256                 put_argument_nongnu_wrappers(c);
2257                 out_printf(outh, "#endif /* __GNUC__ */\n\n");
2258         } else if(arguments > 0 && no_gnu) {
2259                 out_printf(outh, "\n/*\n"
2260                            " * Argument wrapping macros\n"
2261                            " */\n");
2262                 put_argument_nongnu_wrappers(c);
2263         }
2264
2265         if(signals > 0) {
2266                 for(l = c->nodes; l != NULL; l = l->next) {
2267                         Node *n = l->data;
2268                         if(n->type == METHOD_NODE)
2269                                 add_signal_prots((Method *)n);
2270                 }
2271         }
2272
2273         add_enums(c);
2274
2275         add_get_type();
2276
2277         if(any_method_to_alias(c)) {
2278                 if(no_gnu)
2279                         make_method_nongnu_aliases(c);
2280                 else {
2281                         out_printf(out, "\n#ifdef __GNUC__\n");
2282                         make_method_gnu_aliases(c);
2283                         out_printf(out, "#else /* __GNUC__ */\n");
2284                         make_method_nongnu_aliases(c);
2285                         out_printf(out, "#endif /* __GNUC__ */\n\n");
2286                 }
2287         }
2288
2289         out_printf(out, "/* a macro for creating a new object of our type */\n");
2290         out_printf(out,
2291                    "#define GET_NEW ((%s *)gtk_type_new(%s_get_type()))\n\n",
2292                    typebase, funcbase);
2293
2294         if(need_destroy)
2295                 add_destroy(c);
2296
2297         if(need_finalize)
2298                 add_finalize(c);
2299
2300         add_inits(c);
2301
2302         if(arguments > 0) {
2303                 add_getset_arg(c, TRUE);
2304                 add_getset_arg(c, FALSE);
2305         }
2306
2307         for(l = c->nodes; l != NULL; l = l->next) {
2308                 Node *n = l->data;
2309                 if(n->type == METHOD_NODE)
2310                         put_method((Method *)n);
2311         }
2312
2313         add_bad_hack_to_avoid_unused_warnings(c);
2314 }
2315
2316 static void
2317 print_version_macros(void)
2318 {
2319         int major=0, minor=0, pl=0;
2320         sscanf(VERSION, "%d.%d.%d", &major, &minor, &pl);
2321
2322         out_printf(out, "#define GOB_VERSION_MAJOR %d\n", major);
2323         out_printf(out, "#define GOB_VERSION_MINOR %d\n", minor);
2324         out_printf(out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
2325 }
2326
2327 static void
2328 print_file_comments(void)
2329 {
2330         time_t curtime;
2331         time(&curtime);
2332         out_printf(outh, "/* Generated by GOB (v%s)"
2333                    "   (do not edit directly) */\n\n", VERSION);
2334         if(outph)
2335                 out_printf(outph, "/* Generated by GOB (v%s)"
2336                            "   (do not edit directly) */\n\n", VERSION);
2337         out_printf(out, "/* Generated by GOB (v%s) on %s"
2338                    "   (do not edit directly) */\n\n",
2339                    VERSION, ctime(&curtime));
2340 }
2341
2342 static void
2343 print_includes(void)
2344 {
2345         gboolean found_header;
2346         char *p;
2347
2348         /* We may need string.h for memset */
2349         if(destructors > 0)
2350                 out_printf(out, "#include <string.h> /* memset() */\n\n");
2351
2352         p = g_strconcat(filebase, ".h", NULL);
2353         found_header = TRUE;
2354         if(!g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
2355                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
2356                 found_header = FALSE;
2357         }
2358         g_free(p);
2359
2360         /* if we are creating a private header see if it was included */
2361         if(outph) {
2362                 p = g_strconcat(filebase, "-private.h", NULL);
2363                 if(!g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
2364                         out_printf(out, "#include \"%s-private.h\"\n\n",
2365                                    filebase);
2366                         if(found_header)
2367                                 print_error(TRUE,
2368                                             "Implicit private header include "
2369                                             "added to top of\n"
2370                                             "\tsource file, while public "
2371                                             "header is at a custom location, "
2372                                             "you should\n"
2373                                             "\texplicitly include "
2374                                             "the private header below the "
2375                                             "public one.", 0);
2376                 }
2377                 g_free(p);
2378         }
2379 }
2380
2381 static void
2382 print_header_prefixes(void)
2383 {
2384         char *p;
2385
2386         p = replace_sep(((Class *)class)->otype, '_');
2387         g_strup(p);
2388         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
2389         if(outph)
2390                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
2391                            "#define __%s_PRIVATE_H__\n\n"
2392                            "#include \"%s.h\"\n\n", p, p, filebase);
2393         g_free(p);
2394
2395         if(!no_extern_c) {
2396                 out_printf(outh, "#ifdef __cplusplus\n"
2397                            "extern \"C\" {\n"
2398                            "#endif /* __cplusplus */\n\n");
2399                 if(outph)
2400                         out_printf(outph, "#ifdef __cplusplus\n"
2401                                    "extern \"C\" {\n"
2402                                    "#endif /* __cplusplus */\n\n");
2403         }
2404 }
2405
2406 static void
2407 print_header_postfixes(void)
2408 {
2409         if(!no_extern_c)
2410                 out_printf(outh, "\n#ifdef __cplusplus\n"
2411                            "}\n"
2412                            "#endif /* __cplusplus */\n");
2413         out_printf(outh, "\n#endif\n");
2414         if(outph) {
2415                 if(!no_extern_c)
2416                         out_printf(outph, "\n#ifdef __cplusplus\n"
2417                                    "}\n"
2418                                    "#endif /* __cplusplus */\n");
2419                 out_printf(outph, "\n#endif\n");
2420         }
2421 }
2422
2423 static void
2424 print_all_top(void)
2425 {
2426         GList *li;
2427
2428         /* print the AT_CCODE blocks */
2429         for(li=nodes;li;li=g_list_next(li)) {
2430                 Node *node = li->data;
2431                 if(node->type == CCODE_NODE) {
2432                         CCode *cc = (CCode *)node;
2433                         if(cc->cctype==AT_CCODE)
2434                                 print_ccode_block((CCode *)node);
2435                 }
2436         }
2437 }
2438
2439 static void
2440 print_header_top(void)
2441 {
2442         GList *li;
2443
2444         /* mandatory include */
2445         out_printf(outh, "#include <gtk/gtk.h>\n\n");
2446
2447         /* print the HT_CCODE blocks */
2448         for(li=nodes;li;li=g_list_next(li)) {
2449                 Node *node = li->data;
2450                 if(node->type == CCODE_NODE) {
2451                         CCode *cc = (CCode *)node;
2452                         if(cc->cctype==HT_CCODE)
2453                                 print_ccode_block((CCode *)node);
2454                 }
2455         }
2456 }
2457
2458 static void
2459 generate_outfiles(void)
2460 {
2461         GList *li;
2462
2463         print_file_comments();
2464
2465         print_all_top();
2466
2467         print_header_top();
2468
2469         print_header_prefixes();
2470
2471         print_version_macros();
2472
2473         print_includes();
2474
2475         for(li=nodes;li;li=g_list_next(li)) {
2476                 Node *node = li->data;
2477                 if(node->type == CCODE_NODE) {
2478                         CCode *cc = (CCode *)node;
2479                         if(cc->cctype!=HT_CCODE)
2480                                 print_ccode_block((CCode *)node);
2481                 } else if(node->type == CLASS_NODE) {
2482                         print_class_block((Class *)node);
2483                 } else
2484                         g_assert_not_reached();
2485         }
2486
2487         print_header_postfixes();
2488 }
2489
2490 static void
2491 print_help(void)
2492 {
2493         fprintf(stderr, "Gob version %s\n\n", VERSION);
2494         fprintf(stderr, "gob [options] file.gob\n\n");
2495         fprintf(stderr, "Options:\n"
2496                 "\t--help,-h,-?            Display this help\n"
2497                 "\t--version               Display version\n"
2498                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
2499                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
2500                 "\t--for-cpp               Create C++ files\n"
2501                 "\t--no-extern-c           Never print extern \"C\" into the "
2502                                           "header\n"
2503                 "\t--no-gnu                Never use GNU extentions\n"
2504                 "\t--no-touch-headers      Don't touch headers unless they "
2505                                           "really changed\n"
2506                 "\t--always-private-header Always create a private header "
2507                                           "file,\n"
2508                 "\t                        even if it would be empty "
2509                                           "[default]\n"
2510                 "\t--ondemand-private-header Create private header only when "
2511                                           "needed\n"
2512                 "\t--no-private-header     Don't create a private header, "
2513                                           "put private\n"
2514                 "\t                        structure and protected "
2515                                           "prototypes inside c file\n"
2516                 "\t--always-private-struct Always create a private pointer "
2517                                           "in\n"
2518                 "\t                        the object structure\n"
2519                 "\t--no-write,-n           Don't write output files, just "
2520                                           "check syntax\n"
2521                 "\t--no-lines              Don't print '#line' to output\n"
2522                 "\t--no-self-alias         Don't create self type and macro "
2523                                           "aliases\n"
2524                 "\t--no-kill-underscores   Don't remove the leading underscore "
2525                                           "from\n"
2526                 "\t                        short id names\n");
2527 }
2528
2529 static void
2530 parse_options(int argc, char *argv[])
2531 {
2532         int i;
2533         int got_file = FALSE;
2534         int no_opts = FALSE;
2535
2536         filename = NULL;
2537
2538         for(i=1;i<argc;i++) {
2539                 if(no_opts || argv[i][0]!='-') {
2540                         /*must be a file*/
2541                         if(got_file) {
2542                                 fprintf(stderr, "Specify only one file!\n");
2543                                 print_help();
2544                                 exit(1);
2545                         }
2546                         filename = argv[i];
2547                         got_file = TRUE;
2548                 } else if(strcmp(argv[i], "--help")==0) {
2549                         print_help();
2550                         exit(0);
2551                 } else if(strcmp(argv[i], "--version")==0) {
2552                         fprintf(stderr, "Gob version %s\n", VERSION);
2553                         exit(0);
2554                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
2555                         exit_on_warn = TRUE;
2556                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
2557                         exit_on_warn = FALSE;
2558                 } else if(strcmp(argv[i], "--for-cpp")==0) {
2559                         for_cpp = TRUE;
2560                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
2561                         no_touch_headers = TRUE;
2562                 } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
2563                         private_header = PRIVATE_HEADER_ONDEMAND;
2564                 } else if(strcmp(argv[i], "--always-private-header")==0) {
2565                         private_header = PRIVATE_HEADER_ALWAYS;
2566                 } else if(strcmp(argv[i], "--no-private-header")==0) {
2567                         private_header = PRIVATE_HEADER_NEVER;
2568                 } else if(strcmp(argv[i], "--no-gnu")==0) {
2569                         no_gnu = TRUE;
2570                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
2571                         no_extern_c = TRUE;
2572                 } else if(strcmp(argv[i], "--no-write")==0) {
2573                         no_write = TRUE;
2574                 } else if(strcmp(argv[i], "--no-lines")==0) {
2575                         no_lines = TRUE;
2576                 } else if(strcmp(argv[i], "--no-self-alias")==0) {
2577                         no_self_alias = TRUE;
2578                 } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
2579                         no_kill_underscores = TRUE;
2580                 } else if(strcmp(argv[i], "--always-private-struct")==0) {
2581                         always_private_struct = TRUE;
2582                 } else if(strcmp(argv[i], "--")==0) {
2583                         /*further arguments are files*/
2584                         no_opts = TRUE;
2585                 } else if(strncmp(argv[i], "--", 2)==0) {
2586                         /*unknown long option*/
2587                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
2588                         print_help();
2589                         exit(1);
2590                 } else {
2591                         /*by now we know we have a string starting with
2592                           - which is a short option string*/
2593                         char *p = argv[i]+1;
2594                         for(p=argv[i]+1; *p; p++) {
2595                                 switch(*p) {
2596                                 case 'w':
2597                                         exit_on_warn=TRUE;
2598                                         break;
2599                                 case 'n':
2600                                         no_write = TRUE;
2601                                         break;
2602                                 case 'h':
2603                                 case '?':
2604                                         print_help();
2605                                         exit(0);
2606                                 default:
2607                                         fprintf(stderr,
2608                                                 "Unknown option '%c'!\n", *p);
2609                                         print_help();
2610                                         exit(1);
2611                                 }
2612                         }
2613                 }
2614         }
2615 }
2616
2617 /* this is a somewhat ugly hack, but it appears to work */
2618 static void
2619 compare_and_move_header(void)
2620 {
2621         char *hfnew = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
2622         char *hf = g_strconcat(filebase, ".h", NULL);
2623         struct stat s;
2624         if(stat(hf, &s)==0) {
2625                 char *s;
2626                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
2627                 if(system(s)==0) {
2628                         if(unlink(hfnew)!=0)
2629                                 print_error(FALSE,
2630                                             "Can't remove new header file", 0);
2631                         g_free(hfnew);
2632                         g_free(hf);
2633                         g_free(s);
2634                         return;
2635                 }
2636                 g_free(s);
2637                 if(unlink(hf)!=0)
2638                         print_error(FALSE, "Can't remove old header file", 0);
2639         }
2640         if(rename(hfnew, hf)!=0)
2641                 print_error(FALSE, "Can't rename new header file", 0);
2642         g_free(hfnew);
2643         g_free(hf);
2644 }
2645
2646 int
2647 main(int argc, char *argv[])
2648 {
2649         parse_options(argc, argv);
2650         
2651         if(filename) {
2652                 yyin = fopen(filename, "r");
2653                 if(!yyin) {
2654                         fprintf(stderr, "Error: can't open file '%s'\n",
2655                                 filename);
2656                         exit(1);
2657                 }
2658         } else
2659                 filename = "stdin";
2660
2661         /*yydebug = 1;*/
2662         if(yyparse()!=0)
2663                 g_error("Parsing errors, quitting");
2664         if(!class)
2665                 print_error(FALSE, " no class defined", 0);
2666         
2667
2668         exit_on_error = FALSE;
2669
2670         signals = count_signals((Class *)class);
2671         arguments = count_arguments((Class *)class);
2672         overrides = count_overrides((Class *)class);
2673         privates = count_privates((Class *)class);
2674         protecteds = count_protecteds((Class *)class);
2675         destructors = count_destructors((Class *)class);
2676         initializers = count_initializers((Class *)class);
2677
2678         make_bases();
2679         make_inits((Class *)class);
2680         if(destructors > 0) {
2681                 need_destroy = TRUE;
2682                 find_destroy((Class *)class);
2683         }
2684         if(privates > 0) {
2685                 need_finalize = TRUE;
2686                 find_finalize((Class *)class);
2687         }
2688         check_bad_symbols((Class *)class);
2689         check_duplicate_symbols((Class *)class);
2690         check_duplicate_overrides((Class *)class);
2691         check_duplicate_signals_args((Class *)class);
2692         check_public_new((Class *)class);
2693         check_vararg((Class *)class);
2694         check_firstarg((Class *)class);
2695         check_nonvoidempty((Class *)class);
2696         check_signal_args((Class *)class);
2697         check_argument_types((Class *)class);
2698         check_func_arg_checks((Class *)class);
2699
2700         exit_on_error = TRUE;
2701         
2702         if(got_error)
2703                 exit(1);
2704
2705         any_special = setup_special_array((Class *)class, special_array);
2706
2707         open_files();
2708         
2709         generate_outfiles();
2710
2711         if(devnull)
2712                 fclose(devnull);
2713         else {
2714                 fclose(out);
2715                 fclose(outh);
2716                 if(outph)
2717                         fclose(outph);
2718         }
2719
2720         if(no_touch_headers && !no_write)
2721                 compare_and_move_header();
2722         
2723         return 0;
2724 }