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