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