]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
Release 1.0.10
[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_ONDEMAND;
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 TYPE_SELF %s\n", macrotype);
2253                 out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n",
2254                            macrobase);
2255                 out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n",
2256                            macrobase);
2257
2258                 out_printf(out, "/* self typedefs */\n");
2259                 out_printf(out, "typedef %s Self;\n", typebase);
2260                 out_printf(out, "typedef %sClass SelfClass;\n\n", typebase);
2261         }
2262
2263         out_printf(out, "/* GTK_CLASS_TYPE for 1.2<->1.3/2.0 GTK+ compatibility */\n");
2264         out_printf(out,
2265                    "#ifndef GTK_CLASS_TYPE\n"
2266                    "#define GTK_CLASS_TYPE(x) (GTK_OBJECT_CLASS(x)->type)\n"
2267                    "#endif /* GTK_CLASS_TYPE */\n\n");
2268
2269         if(privates > 0 || always_private_struct) {
2270                 out_printf(outh, "\n/* Private structure type */\n");
2271                 out_printf(outh, "typedef struct _%sPrivate %sPrivate;\n",
2272                            typebase, typebase);
2273                 if(privates == 0)
2274                         out_printf(outh, "/* There are no privates, this "
2275                                    "structure is thus never defined */\n");
2276         }
2277
2278         out_printf(outh, "\n/*\n"
2279                    " * Main object structure\n"
2280                    " */\n");
2281         s = replace_sep(c->otype, '_');
2282         g_strup(s);
2283         out_printf(outh, "#ifndef __TYPEDEF_%s__\n"
2284                    "#define __TYPEDEF_%s__\n", s, s);
2285         g_free(s);
2286         out_printf(outh, "typedef struct _%s %s;\n"
2287                    "#endif\n", typebase, typebase);
2288         out_printf(outh, "struct _%s {\n\t%s __parent__;\n",
2289                    typebase, ptypebase);
2290         for(l=c->nodes; l; l=g_list_next(l)) {
2291                 static gboolean printed_public = FALSE;
2292                 Node *n = l->data;
2293                 Variable *v = (Variable *)n;
2294                 if(n->type == VARIABLE_NODE &&
2295                    v->scope == PUBLIC_SCOPE) {
2296                         if( ! printed_public) {
2297                                 out_printf(outh, "\t/*< public >*/\n");
2298                                 printed_public = TRUE;
2299                         }
2300                         put_variable((Variable *)n, outh);
2301                 }
2302         }
2303         /* put protecteds always AFTER publics */
2304         for(l=c->nodes; l; l=g_list_next(l)) {
2305                 Node *n = l->data;
2306                 Variable *v = (Variable *)n;
2307                 if(n->type == VARIABLE_NODE &&
2308                    v->scope == PROTECTED_SCOPE) {
2309                         if( ! printed_private) {
2310                                 out_printf(outh, "\t/*< private >*/\n");
2311                                 printed_private = TRUE;
2312                         }
2313                         put_variable((Variable *)n, outh);
2314                 }
2315         }
2316         if(privates > 0 || always_private_struct) {
2317                 if( ! printed_private)
2318                         out_printf(outh, "\t/*< private >*/\n");
2319                 out_printf(outh, "\t%sPrivate *_priv;\n", typebase);
2320         }
2321         out_printf(outh, "};\n");
2322
2323         if(privates > 0) {
2324                 FILE *outfp;
2325
2326                 /* if we are to stick this into the private
2327                    header, if not stick it directly into the
2328                    C file */
2329                 if(outph) 
2330                         outfp = outph;
2331                 else
2332                         outfp = out;
2333
2334                 out_printf(outfp, "struct _%sPrivate {\n",
2335                            typebase);
2336                 for(l=c->nodes; l; l=l->next) {
2337                         Node *n = l->data;
2338                         Variable *v = (Variable *)n;
2339                         if(n->type == VARIABLE_NODE &&
2340                            v->scope == PRIVATE_SCOPE) {
2341                                 out_addline_infile(outfp, v->line_no);
2342                                 put_variable(v, outfp);
2343                         }
2344                 }
2345                 out_addline_outfile(outfp);
2346                 out_printf(outfp, "};\n");
2347         }
2348
2349         out_printf(outh, "\n/*\n"
2350                    " * Class definition\n"
2351                    " */\n");
2352         out_printf(outh, "typedef struct _%sClass %sClass;\n",
2353                    typebase, typebase);
2354         out_printf(outh,
2355                    "struct _%sClass {\n\t%sClass __parent__;\n",
2356                    typebase, ptypebase);
2357         for(l = c->nodes; l != NULL; l = l->next) {
2358                 Node *n = l->data;
2359                 if(n->type == METHOD_NODE)
2360                         put_vs_method((Method *)n);
2361         }
2362         /* If BonoboX type class put down the epv */
2363         if (c->bonobo_x_class != NULL) {
2364                 out_printf (outh,
2365                             "\t/* Bonobo object epv */\n"
2366                             "\tPOA_%s__epv _epv;\n",
2367                             c->bonobo_x_class);
2368         }
2369         /* put class scope variables */
2370         for(l = c->nodes; l != NULL; l = l->next) {
2371                 Node *n = l->data;
2372                 Variable *v = (Variable *)n;
2373                 if(n->type == VARIABLE_NODE &&
2374                    v->scope == CLASS_SCOPE)
2375                         put_variable((Variable *)n, outh);
2376         }
2377         out_printf(outh, "};\n\n");
2378
2379         out_printf(out, "/* here are local prototypes */\n");
2380         if(set_arguments > 0) {
2381                 out_printf(out, "static void ___object_set_arg "
2382                            "(GtkObject *object, GtkArg *arg, "
2383                            "guint arg_id);\n");
2384         }
2385         if(get_arguments > 0) {
2386                 out_printf(out, "static void ___object_get_arg "
2387                            "(GtkObject *object, GtkArg *arg, "
2388                            "guint arg_id);\n");
2389         }
2390
2391         out_printf(outh, "\n/*\n"
2392                    " * Public methods\n"
2393                    " */\n");
2394
2395         if ( ! overrode_get_type) {
2396                 out_printf(outh, "GtkType\t%s_get_type\t(void)", funcbase);
2397                 if ( ! no_gnu) {
2398                         out_printf(outh, " G_GNUC_CONST;\n");
2399                 } else {
2400                         out_printf(outh, ";\n");
2401                 }
2402         }
2403
2404         for(l = c->nodes; l != NULL; l = l->next) {
2405                 Node *n = l->data;
2406                 if(n->type == METHOD_NODE) {
2407                         put_pub_method((Method *)n);
2408                         put_prot_method((Method *)n);
2409                         put_priv_method_prot((Method *)n);
2410                 }
2411         }
2412
2413         /* this idea is less and less apealing to me */
2414         if (signals > 0) {
2415                 out_printf (outh, "\n/*\n"
2416                             " * Signal connection wrapper macros\n"
2417                             " */\n");
2418                 if( ! no_gnu) {
2419                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2420                         put_signal_macros (c, TRUE);
2421                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
2422                         put_signal_macros (c, FALSE);
2423                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
2424                 } else {
2425                         put_signal_macros (c, FALSE);
2426                 }
2427         }
2428
2429         /* argument wrapping macros */
2430         if(get_arguments > 0 || set_arguments > 0) {
2431                 out_printf(outh, "\n/*\n"
2432                            " * Argument wrapping macros\n"
2433                            " */\n");
2434                 if( ! no_gnu) {
2435                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2436                         put_argument_gnu_wrappers(c);
2437                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
2438                         put_argument_nongnu_wrappers(c);
2439                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
2440                 } else {
2441                         put_argument_nongnu_wrappers(c);
2442                 }
2443         }
2444
2445         if(signals > 0) {
2446                 for(l = c->nodes; l != NULL; l = l->next) {
2447                         Node *n = l->data;
2448                         if(n->type == METHOD_NODE)
2449                                 add_signal_prots((Method *)n);
2450                 }
2451         }
2452
2453         add_enums(c);
2454
2455         if ( ! overrode_get_type) {
2456                 if (c->bonobo_x_class != NULL)
2457                         add_bonobo_x_get_type ();
2458                 else
2459                         add_get_type ();
2460         }
2461
2462         if(any_method_to_alias(c)) {
2463                 if( ! no_gnu) {
2464                         out_printf(out, "/* Short form macros */\n");
2465                         out_printf(out, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2466                         make_method_gnu_aliases(c);
2467                         out_printf(out, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n");
2468                 }
2469                 make_method_nongnu_aliases(c);
2470         }
2471
2472         out_printf(out, "/* a macro for creating a new object of our type */\n");
2473         out_printf(out,
2474                    "#define GET_NEW ((%s *)gtk_type_new(%s_get_type()))\n\n",
2475                    typebase, funcbase);
2476
2477         if(need_destroy)
2478                 add_destroy(c);
2479
2480         if(need_finalize)
2481                 add_finalize(c);
2482
2483         add_inits(c);
2484
2485         if(set_arguments > 0) {
2486                 add_getset_arg(c, TRUE);
2487         }
2488
2489         if(get_arguments > 0) {
2490                 add_getset_arg(c, FALSE);
2491         }
2492
2493         for(l = c->nodes; l != NULL; l = l->next) {
2494                 Node *n = l->data;
2495                 if(n->type == METHOD_NODE)
2496                         put_method((Method *)n);
2497         }
2498
2499         add_bad_hack_to_avoid_unused_warnings(c);
2500 }
2501
2502 static void
2503 print_version_macros(void)
2504 {
2505         int major=0, minor=0, pl=0;
2506         sscanf(VERSION, "%d.%d.%d", &major, &minor, &pl);
2507
2508         out_printf(out, "#define GOB_VERSION_MAJOR %d\n", major);
2509         out_printf(out, "#define GOB_VERSION_MINOR %d\n", minor);
2510         out_printf(out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
2511 }
2512
2513 static void
2514 print_file_comments(void)
2515 {
2516         time_t curtime;
2517         time(&curtime);
2518         out_printf(outh, "/* Generated by GOB (v%s)"
2519                    "   (do not edit directly) */\n\n", VERSION);
2520         if(outph)
2521                 out_printf(outph, "/* Generated by GOB (v%s)"
2522                            "   (do not edit directly) */\n\n", VERSION);
2523         out_printf(out, "/* Generated by GOB (v%s) on %s"
2524                    "   (do not edit directly) */\n\n",
2525                    VERSION, ctime(&curtime));
2526
2527         out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
2528 }
2529
2530 static void
2531 print_includes(void)
2532 {
2533         gboolean found_header;
2534         char *p;
2535
2536         /* We may need string.h for memset */
2537         if(destructors > 0 &&
2538            ! g_list_find_custom(include_files, "string.h", (GCompareFunc)strcmp)) {
2539                 out_printf(out, "#include <string.h> /* memset() */\n\n");
2540         }
2541
2542         p = g_strconcat(filebase, ".h", NULL);
2543         found_header = TRUE;
2544         if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
2545                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
2546                 found_header = FALSE;
2547         }
2548         g_free(p);
2549
2550         /* if we are creating a private header see if it was included */
2551         if(outph) {
2552                 p = g_strconcat(filebase, "-private.h", NULL);
2553                 if( ! g_list_find_custom(include_files, p,
2554                                          (GCompareFunc)strcmp)) {
2555                         out_printf(out, "#include \"%s-private.h\"\n\n",
2556                                    filebase);
2557                         if(found_header)
2558                                 error_printf(GOB_WARN, 0,
2559                                             "Implicit private header include "
2560                                             "added to top of\n"
2561                                             "\tsource file, while public "
2562                                             "header is at a custom location, "
2563                                             "you should\n"
2564                                             "\texplicitly include "
2565                                             "the private header below the "
2566                                             "public one.");
2567                 }
2568                 g_free(p);
2569         }
2570 }
2571
2572 static void
2573 print_header_prefixes(void)
2574 {
2575         char *p;
2576
2577         p = replace_sep(((Class *)class)->otype, '_');
2578         g_strup(p);
2579         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
2580         if(outph)
2581                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
2582                            "#define __%s_PRIVATE_H__\n\n"
2583                            "#include \"%s.h\"\n\n", p, p, filebase);
2584         g_free(p);
2585
2586         if( ! no_extern_c) {
2587                 out_printf(outh, "#ifdef __cplusplus\n"
2588                            "extern \"C\" {\n"
2589                            "#endif /* __cplusplus */\n\n");
2590                 if(outph)
2591                         out_printf(outph, "#ifdef __cplusplus\n"
2592                                    "extern \"C\" {\n"
2593                                    "#endif /* __cplusplus */\n\n");
2594         }
2595 }
2596
2597 static void
2598 print_header_postfixes(void)
2599 {
2600         if( ! no_extern_c)
2601                 out_printf(outh, "\n#ifdef __cplusplus\n"
2602                            "}\n"
2603                            "#endif /* __cplusplus */\n");
2604         out_printf(outh, "\n#endif\n");
2605         if(outph) {
2606                 if( ! no_extern_c)
2607                         out_printf(outph, "\n#ifdef __cplusplus\n"
2608                                    "}\n"
2609                                    "#endif /* __cplusplus */\n");
2610                 out_printf(outph, "\n#endif\n");
2611         }
2612 }
2613
2614 static void
2615 print_all_top(void)
2616 {
2617         GList *li;
2618
2619         /* print the AT_CCODE blocks */
2620         for(li = nodes; li != NULL; li = li->next) {
2621                 Node *node = li->data;
2622                 if(node->type == CCODE_NODE) {
2623                         CCode *cc = (CCode *)node;
2624                         if(cc->cctype == AT_CCODE)
2625                                 print_ccode_block((CCode *)node);
2626                 }
2627         }
2628 }
2629
2630 static void
2631 print_header_top(void)
2632 {
2633         GList *li;
2634
2635         /* mandatory include */
2636         out_printf(outh, "#include <gtk/gtk.h>\n\n");
2637
2638         /* print the HT_CCODE blocks */
2639         for(li=nodes;li;li=g_list_next(li)) {
2640                 Node *node = li->data;
2641                 if(node->type == CCODE_NODE) {
2642                         CCode *cc = (CCode *)node;
2643                         if(cc->cctype == HT_CCODE)
2644                                 print_ccode_block((CCode *)node);
2645                 }
2646         }
2647 }
2648
2649 static void
2650 generate_outfiles(void)
2651 {
2652         GList *li;
2653
2654         print_file_comments();
2655
2656         print_all_top();
2657
2658         print_header_top();
2659
2660         print_header_prefixes();
2661
2662         print_version_macros();
2663
2664         print_includes();
2665
2666         for(li=nodes;li;li=g_list_next(li)) {
2667                 Node *node = li->data;
2668                 if(node->type == CCODE_NODE) {
2669                         CCode *cc = (CCode *)node;
2670                         if(cc->cctype != HT_CCODE &&
2671                            cc->cctype != AT_CCODE)
2672                                 print_ccode_block((CCode *)node);
2673                 } else if(node->type == CLASS_NODE) {
2674                         print_class_block((Class *)node);
2675                 } else
2676                         g_assert_not_reached();
2677         }
2678
2679         print_header_postfixes();
2680 }
2681
2682 static void
2683 print_help(void)
2684 {
2685         fprintf(stderr, "Gob version %s\n\n", VERSION);
2686         fprintf(stderr, "gob [options] file.gob\n\n");
2687         fprintf(stderr, "Options:\n"
2688                 "\t--help,-h,-?            Display this help\n"
2689                 "\t--version               Display version\n"
2690                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
2691                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
2692                 "\t--for-cpp               Create C++ files\n"
2693                 "\t--no-extern-c           Never print extern \"C\" into the "
2694                                           "header\n"
2695                 "\t--no-gnu                Never use GNU extentions\n"
2696                 "\t--no-touch-headers      Don't touch headers unless they "
2697                                           "really changed\n"
2698                 "\t--always-private-header Always create a private header "
2699                                           "file,\n"
2700                 "\t                        even if it would be empty "
2701                                           "[default]\n"
2702                 "\t--ondemand-private-header Create private header only when "
2703                                           "needed\n"
2704                 "\t--no-private-header     Don't create a private header, "
2705                                           "put private\n"
2706                 "\t                        structure and protected "
2707                                           "prototypes inside c file\n"
2708                 "\t--always-private-struct Always create a private pointer "
2709                                           "in\n"
2710                 "\t                        the object structure\n"
2711                 "\t--no-write,-n           Don't write output files, just "
2712                                           "check syntax\n"
2713                 "\t--no-lines              Don't print '#line' to output\n"
2714                 "\t--no-self-alias         Don't create self type and macro "
2715                                           "aliases\n"
2716                 "\t--no-kill-underscores   Don't remove the leading underscore "
2717                                           "from\n"
2718                 "\t                        short id names\n");
2719 }
2720
2721 static void
2722 parse_options(int argc, char *argv[])
2723 {
2724         int i;
2725         int got_file = FALSE;
2726         int no_opts = FALSE;
2727
2728         filename = NULL;
2729
2730         for(i = 1 ; i < argc; i++) {
2731                 if(no_opts ||
2732                    argv[i][0] != '-') {
2733                         /*must be a file*/
2734                         if(got_file) {
2735                                 fprintf(stderr, "Specify only one file!\n");
2736                                 print_help();
2737                                 exit(1);
2738                         }
2739                         filename = argv[i];
2740                         got_file = TRUE;
2741                 } else if(strcmp(argv[i], "--help")==0) {
2742                         print_help();
2743                         exit(0);
2744                 } else if(strcmp(argv[i], "--version")==0) {
2745                         fprintf(stderr, "Gob version %s\n", VERSION);
2746                         exit(0);
2747                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
2748                         exit_on_warn = TRUE;
2749                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
2750                         exit_on_warn = FALSE;
2751                 } else if(strcmp(argv[i], "--for-cpp")==0) {
2752                         for_cpp = TRUE;
2753                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
2754                         no_touch_headers = TRUE;
2755                 } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
2756                         private_header = PRIVATE_HEADER_ONDEMAND;
2757                 } else if(strcmp(argv[i], "--always-private-header")==0) {
2758                         private_header = PRIVATE_HEADER_ALWAYS;
2759                 } else if(strcmp(argv[i], "--no-private-header")==0) {
2760                         private_header = PRIVATE_HEADER_NEVER;
2761                 } else if(strcmp(argv[i], "--no-gnu")==0) {
2762                         no_gnu = TRUE;
2763                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
2764                         no_extern_c = TRUE;
2765                 } else if(strcmp(argv[i], "--no-write")==0) {
2766                         no_write = TRUE;
2767                 } else if(strcmp(argv[i], "--no-lines")==0) {
2768                         no_lines = TRUE;
2769                 } else if(strcmp(argv[i], "--no-self-alias")==0) {
2770                         no_self_alias = TRUE;
2771                 } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
2772                         no_kill_underscores = TRUE;
2773                 } else if(strcmp(argv[i], "--always-private-struct")==0) {
2774                         always_private_struct = TRUE;
2775                 } else if(strcmp(argv[i], "--")==0) {
2776                         /*further arguments are files*/
2777                         no_opts = TRUE;
2778                 } else if(strncmp(argv[i], "--", 2)==0) {
2779                         /*unknown long option*/
2780                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
2781                         print_help();
2782                         exit(1);
2783                 } else {
2784                         /*by now we know we have a string starting with
2785                           - which is a short option string*/
2786                         char *p;
2787                         for(p = argv[i] + 1; *p; p++) {
2788                                 switch(*p) {
2789                                 case 'w':
2790                                         exit_on_warn=TRUE;
2791                                         break;
2792                                 case 'n':
2793                                         no_write = TRUE;
2794                                         break;
2795                                 case 'h':
2796                                 case '?':
2797                                         print_help();
2798                                         exit(0);
2799                                 default:
2800                                         fprintf(stderr,
2801                                                 "Unknown option '%c'!\n", *p);
2802                                         print_help();
2803                                         exit(1);
2804                                 }
2805                         }
2806                 }
2807         }
2808 }
2809
2810 /* this is a somewhat ugly hack, but it appears to work */
2811 static void
2812 compare_and_move_header(void)
2813 {
2814         char *hfnew = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
2815         char *hf = g_strconcat(filebase, ".h", NULL);
2816         struct stat s;
2817         if(stat(hf, &s) == 0) {
2818                 char *s;
2819                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
2820                 if(system(s) == 0) {
2821                         if(unlink(hfnew) != 0)
2822                                 error_printf(GOB_ERROR, 0,
2823                                              "Can't remove new header file");
2824                         g_free(hfnew);
2825                         g_free(hf);
2826                         g_free(s);
2827                         return;
2828                 }
2829                 g_free(s);
2830                 if(unlink(hf) != 0)
2831                         error_printf(GOB_ERROR, 0,
2832                                      "Can't remove old header file");
2833         }
2834         if(rename(hfnew, hf) != 0)
2835                 error_printf(GOB_ERROR, 0,
2836                              "Can't rename new header file");
2837         g_free(hfnew);
2838         g_free(hf);
2839 }
2840
2841 int
2842 main(int argc, char *argv[])
2843 {
2844         parse_options(argc, argv);
2845         
2846         if(filename) {
2847                 yyin = fopen(filename, "r");
2848                 if(!yyin) {
2849                         fprintf(stderr, "Error: can't open file '%s'\n",
2850                                 filename);
2851                         exit(1);
2852                 }
2853         } else
2854                 filename = "stdin";
2855
2856         /* This is where parsing is done */
2857         /*yydebug = 1;*/
2858         if(yyparse() != 0)
2859                 g_error("Parsing errors, quitting");
2860
2861         if( ! class)
2862                 error_print(GOB_ERROR, 0, " no class defined");
2863         
2864
2865         exit_on_error = FALSE;
2866
2867         signals = count_signals((Class *)class);
2868         set_arguments = count_set_arguments((Class *)class);
2869         get_arguments = count_get_arguments((Class *)class);
2870         overrides = count_overrides((Class *)class);
2871         privates = count_privates((Class *)class);
2872         protecteds = count_protecteds((Class *)class);
2873         destructors = count_destructors((Class *)class);
2874         initializers = count_initializers((Class *)class);
2875         overrode_get_type = find_get_type((Class *)class);
2876
2877         make_bases();
2878         make_inits((Class *)class);
2879         if(destructors > 0) {
2880                 need_destroy = TRUE;
2881                 find_destroy((Class *)class);
2882         }
2883         if(privates > 0) {
2884                 need_finalize = TRUE;
2885                 find_finalize((Class *)class);
2886         }
2887         check_bad_symbols((Class *)class);
2888         check_duplicate_symbols((Class *)class);
2889         check_duplicate_overrides((Class *)class);
2890         check_duplicate_signals_args((Class *)class);
2891         check_public_new((Class *)class);
2892         check_vararg((Class *)class);
2893         check_firstarg((Class *)class);
2894         check_nonvoidempty((Class *)class);
2895         check_signal_args((Class *)class);
2896         check_argument_types((Class *)class);
2897         check_func_arg_checks((Class *)class);
2898
2899         exit_on_error = TRUE;
2900         
2901         if(got_error)
2902                 exit(1);
2903
2904         any_special = setup_special_array((Class *)class, special_array);
2905
2906         open_files();
2907         
2908         generate_outfiles();
2909
2910         if(devnull)
2911                 fclose(devnull);
2912         else {
2913                 fclose(out);
2914                 fclose(outh);
2915                 if(outph)
2916                         fclose(outph);
2917         }
2918
2919         if(no_touch_headers &&
2920            ! no_write)
2921                 compare_and_move_header();
2922         
2923         return 0;
2924 }