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