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