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