]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
Release 1.0.8
[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                 gboolean is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
756                 out_printf(out,
757                            "\t___%s rfunc;\n\t"
758                            "%s *retval;\n\n"
759                            "\trfunc = (___%s)func;\n\n"
760                            "\tretval = GTK_RETLOC_%s(args[%d]);\n\n"
761                            "\t*retval = (*rfunc)((%s *)object",
762                            s, retcast, s,
763                            (char *)m->gtktypes->data,
764                            g_list_length(m->gtktypes) - (is_none ? 2 : 1),
765                            typebase);
766         }
767         print_signal_marsal_args(m);
768
769 }
770
771 static void
772 add_enums(Class *c)
773 {
774         GList *li;
775         out_printf(out, "\n");
776         if(signals>0) {
777                 out_printf(out, "enum {\n");
778                 for(li=c->nodes;li;li=g_list_next(li)) {
779                         Node *n = li->data;
780                         if(n->type == METHOD_NODE) {
781                                 Method *m = (Method *)n;
782                                 if(m->method == SIGNAL_LAST_METHOD ||
783                                    m->method == SIGNAL_FIRST_METHOD) {
784                                         char *s = g_strdup(get_real_id(m->id));
785                                         g_strup(s);
786                                         out_printf(out, "\t%s_SIGNAL,\n", s);
787                                         g_free(s);
788                                 }
789                         }
790                 }
791                 out_printf(out, "\tLAST_SIGNAL\n};\n\n");
792         }
793         if(set_arguments > 0 || get_arguments > 0) {
794                 out_printf(out, "enum {\n\tARG_0");
795                 for(li=c->nodes;li;li=g_list_next(li)) {
796                         Node *n = li->data;
797                         if(n->type == ARGUMENT_NODE) {
798                                 Argument *a = (Argument *)n;
799                                 char *s = g_strdup(a->name);
800                                 g_strup(s);
801                                 out_printf(out, ",\n\tARG_%s", s);
802                                 g_free(s);
803                         }
804                 }
805                 out_printf(out, "\n};\n\n");
806         }
807
808         if(signals>0)
809                 out_printf(out,
810                            "static guint object_signals[LAST_SIGNAL] = {0};\n\n");
811
812         out_printf(out, "/* pointer to the class of our parent */\n");
813         out_printf(out, "static %sClass *parent_class = NULL;\n\n", ptypebase);
814 }
815
816 static void
817 add_get_type(void)
818 {
819         char *chunk_size = ((Class*)class)->chunk_size;
820         
821         out_printf(out,
822                    "GtkType\n"
823                    "%s_get_type (void)\n"
824                    "{\n"
825                    "\tstatic GtkType type = 0;\n\n"
826                    "\tif (type == 0) {\n"
827                    "\t\tstatic const GtkTypeInfo info = {\n"
828                    "\t\t\t\"%s\",\n"
829                    "\t\t\tsizeof (%s),\n"
830                    "\t\t\tsizeof (%sClass),\n"
831                    "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
832                    "\t\t\t(GtkObjectInitFunc) %s_init,\n"
833                    "\t\t\t/* reserved_1 */ NULL,\n"
834                    "\t\t\t/* reserved_2 */ NULL,\n"
835                    "\t\t\t(GtkClassInitFunc) NULL\n"
836                    "\t\t};\n\n"
837                    "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n",
838                    funcbase, typebase, typebase, typebase,
839                    funcbase, funcbase, pfuncbase);
840         if(chunk_size)  {
841                 out_printf(out,
842                            "#if %s > 0\n"
843                            "\t\tgtk_type_set_chunk_alloc(type, %s);\n"
844                            "#endif\n", 
845                            chunk_size, chunk_size);
846         }
847         out_printf(out,
848                    "\t}\n\n"
849                    "\treturn type;\n"
850                    "}\n\n");
851 }
852
853 static void
854 add_overrides(Class *c, const char *oname, gboolean did_base_obj)
855 {
856         GList *li;
857         GHashTable *done;
858         char *s;
859         
860         done = g_hash_table_new(g_str_hash, g_str_equal);
861         if(did_base_obj) {
862                 s = g_strdup("GtkObject"); /* This was already done */
863                 g_hash_table_insert(done, s, s);
864                 s = g_strdup("GObject"); /* This was probably already done as well (if using Gtk/Glib 1.3/2.0) */
865                 g_hash_table_insert(done, s, s);
866         }
867         for(li=c->nodes; li; li=g_list_next(li)) {
868                 Node *n = li->data;
869                 char *f;
870                 Method *m = (Method *)n;
871                 if(n->type != METHOD_NODE ||
872                    m->method != OVERRIDE_METHOD)
873                         continue;
874
875                 s = remove_sep(m->otype);
876                 
877                 if(g_hash_table_lookup(done, s)) {
878                         g_free(s);
879                         continue;
880                 }
881                 g_hash_table_insert(done, s, s);
882
883                 f = replace_sep(m->otype, '_');
884                 g_strdown(f);
885
886                 out_printf(out, "\t%sClass *%s_class = (%sClass *)%s;\n",
887                            s, f, s, oname);
888                 
889                 g_free(f);
890         }
891         g_hash_table_foreach(done, (GHFunc)g_free, NULL);
892         g_hash_table_destroy(done);
893 }
894
895 static char *
896 make_run_signal_flags(Method *m, gboolean last)
897 {
898         GList *li;
899         GString *gs;
900         char *flags[] = {
901                 "FIRST",
902                 "LAST",
903                 "BOTH",
904                 "NO_RECURSE",
905                 "ACTION",
906                 "NO_HOOKS",
907                 NULL
908         };
909
910         gs = g_string_new(NULL);
911
912         if(last)
913                 g_string_assign(gs, "GTK_RUN_LAST");
914         else
915                 g_string_assign(gs, "GTK_RUN_FIRST");
916
917         if(m->scope == PUBLIC_SCOPE)
918                 g_string_append(gs, " | GTK_RUN_ACTION");
919
920         for(li = m->flags; li; li = li->next) {
921                 char *flag = li->data;
922                 int i;
923                 for(i=0;flags[i];i++) {
924                         if(strcmp(flags[i], flag)==0)
925                                 break;
926                 }
927                 /* if we haven't found it in our list */
928                 if( ! flags[i]) {
929                         error_printf(GOB_WARN, m->line_no,
930                                      "Unknown flag '%s' used, "
931                                      "perhaps it was misspelled",
932                                      flag);
933                 }
934                 g_string_sprintfa(gs, " | GTK_RUN_%s", flag);
935         }
936
937         {
938                 char *ret = gs->str;
939                 g_string_free(gs, FALSE);
940                 return ret;
941         }
942 }
943                 
944
945 static void
946 add_signals(Class *c)
947 {
948         GList *li;
949
950         out_printf(out, "\n");
951         for(li=c->nodes;li;li=g_list_next(li)) {
952                 Node *n = li->data;
953                 char *mar, *sig, *flags;
954                 gboolean is_none, last = FALSE;
955                 Method *m = (Method *)n;
956
957                 if(n->type != METHOD_NODE ||
958                    (m->method != SIGNAL_FIRST_METHOD &&
959                     m->method != SIGNAL_LAST_METHOD))
960                         continue;
961
962                 if(m->method == SIGNAL_FIRST_METHOD)
963                         last = FALSE;
964                 else
965                         last = TRUE;
966
967                 if(g_hash_table_lookup(marsh, m))
968                         mar = g_strconcat("___marshal_",
969                                           (char *)g_hash_table_lookup(marsh, m),
970                                           NULL);
971                 else
972                         mar = g_strdup("gtk_signal_default_marshaller");
973                 
974                 is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
975
976                 sig = g_strdup(get_real_id(m->id));
977                 g_strup(sig);
978                 flags = make_run_signal_flags(m, last);
979                 out_printf(out, "\tobject_signals[%s_SIGNAL] =\n"
980                         "\t\tgtk_signal_new (\"%s\",\n"
981                         "\t\t\t(GtkSignalRunType)(%s),\n"
982                         "\t\t\tGTK_CLASS_TYPE(gtk_object_class),\n"
983                         "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n"
984                         "\t\t\t%s,\n"
985                         "\t\t\tGTK_TYPE_%s, %d",
986                         sig, get_real_id(m->id),
987                         flags,
988                         typebase, get_real_id(m->id), mar,
989                         (char *)m->gtktypes->data,
990                         is_none ? 0 : g_list_length(m->gtktypes->next));
991                 g_free(mar);
992                 g_free(sig);
993                 g_free(flags);
994                 
995                 if( ! is_none) {
996                         GList *l;
997                         for(l = m->gtktypes->next; l != NULL; l = l->next)
998                                 out_printf(out, ",\n\t\t\tGTK_TYPE_%s",
999                                         (char *)l->data);
1000                 }
1001
1002                 out_printf(out, ");\n");
1003
1004                 if(strcmp(m->gtktypes->data, "NONE") != 0 ||
1005                    ! is_none) {
1006                         GList *gl, *al;
1007                         char *sep = "";
1008                         out_printf(out, "\tif(");
1009                         if(strcmp(m->gtktypes->data, "NONE") != 0) {
1010                                 out_printf(out, "%s sizeof(", sep);
1011                                 print_type(out, m->mtype, FALSE);
1012                                 out_printf(out, "%s",
1013                                            m->mtype->postfix ?
1014                                            m->mtype->postfix : ""); 
1015                                 out_printf(out, ") != sizeof(%s)",
1016                                            get_cast(m->gtktypes->data, FALSE));
1017
1018                                 sep = " || ";
1019                         }
1020
1021                         for(al = m->args->next, gl = m->gtktypes->next;
1022                             al != NULL && gl != NULL;
1023                             al = al->next, gl = gl->next) {
1024                                 FuncArg *arg = al->data;
1025                                 char *gtkarg = gl->data;
1026
1027                                 out_printf(out, "%ssizeof(", sep);
1028                                 print_type(out, arg->atype, FALSE);
1029                                 out_printf(out, "%s",
1030                                            arg->atype->postfix ?
1031                                            arg->atype->postfix : ""); 
1032                                 out_printf(out, ") != sizeof(%s)",
1033                                            get_cast(gtkarg, FALSE));
1034
1035                                 sep = " || ";
1036                         }
1037                         out_printf(out, ") {\n"
1038                                    "\t\tg_error(\"%s line %d: Type mismatch "
1039                                    "of \\\"%s\\\" signal signature\");\n"
1040                                    "\t}\n",
1041                                    filename, m->line_no, get_real_id(m->id));
1042
1043                 }
1044         }
1045         out_printf(out, "\tgtk_object_class_add_signals (gtk_object_class,\n"
1046                 "\t\tobject_signals, LAST_SIGNAL);\n\n");
1047 }
1048
1049 static void
1050 set_def_handlers(Class *c, const char *oname)
1051 {
1052         GList *li;
1053         gboolean set_line = FALSE;
1054
1055         out_printf(out, "\n");
1056         for(li = c->nodes; li; li = g_list_next(li)) {
1057                 Node *n = li->data;
1058                 Method *m = (Method *)n;
1059
1060                 if(n->type != METHOD_NODE ||
1061                    (m->method != SIGNAL_FIRST_METHOD &&
1062                     m->method != SIGNAL_LAST_METHOD &&
1063                     m->method != VIRTUAL_METHOD &&
1064                     m->method != OVERRIDE_METHOD))
1065                         continue;
1066
1067                 if(m->line_no > 0 && m->cbuf) {
1068                         out_addline_infile(out, m->line_no);
1069                         set_line = TRUE;
1070                 } else if(set_line) {
1071                         out_addline_outfile(out);
1072                         set_line = FALSE;
1073                 }
1074
1075
1076                 if(m->method == OVERRIDE_METHOD) {
1077                         char *s;
1078                         s = replace_sep(m->otype, '_');
1079                         g_strdown(s);
1080
1081                         if(need_destroy &&
1082                            destroy_handler &&
1083                            strcmp(get_real_id(m->id), "destroy") == 0)
1084                                 out_printf(out, "\tgtk_object_class->destroy "
1085                                            "= ___destroy;\n");
1086                         else if(need_finalize &&
1087                                 finalize_handler &&
1088                                 strcmp(get_real_id(m->id), "finalize") == 0)
1089                                 out_printf(out,
1090                                            "#ifdef G_OBJECT_CLASS\n"
1091                                            "\tg_object_class->finalize = ___finalize;\n"
1092                                            "#else /* !G_OBJECT_CLASS */\n"
1093                                            "\tgtk_object_class->finalize = ___finalize;\n"
1094                                            "#endif /* G_OBJECT_CLASS */\n");
1095                         else if(m->cbuf)
1096                                 out_printf(out,
1097                                            "\t%s_class->%s = ___%x_%s_%s;\n",
1098                                            s, get_real_id(m->id), (guint)m->unique_id,
1099                                            funcbase, get_real_id(m->id));
1100                         else
1101                                 out_printf(out, "\t%s_class->%s = NULL;\n",
1102                                            s, get_real_id(m->id));
1103                 } else {
1104                         if(m->cbuf)
1105                                 out_printf(out, "\t%s->%s = ___real_%s_%s;\n",
1106                                            oname, get_real_id(m->id),
1107                                            funcbase, get_real_id(m->id));
1108                         else
1109                                 out_printf(out, "\t%s->%s = NULL;\n",
1110                                            oname, get_real_id(m->id));
1111                 }
1112         }
1113         if(set_line)
1114                 out_addline_outfile(out);
1115 }
1116
1117 static void
1118 make_arguments(Class *c)
1119 {
1120         GList *li;
1121         char *argflags[] = {
1122                 "CONSTRUCT",
1123                 "CONSTRUCT_ONLY",
1124                 "CHILD_ARG",
1125                 "MASK",
1126                 NULL
1127         };
1128
1129         out_printf(out, "\n");
1130         for(li=c->nodes;li;li=g_list_next(li)) {
1131                 Node *n = li->data;
1132                 Argument *a;
1133                 GString *flags;
1134                 GList *l;
1135                 char *s;
1136                 if(n->type != ARGUMENT_NODE)
1137                         continue;
1138
1139                 a = (Argument *)n;
1140                 
1141                 if(a->get && a->set)
1142                         flags = g_string_new("GTK_ARG_READWRITE");
1143                 else if(a->get)
1144                         flags = g_string_new("GTK_ARG_READABLE");
1145                 else
1146                         flags = g_string_new("GTK_ARG_WRITABLE");
1147
1148                 g_assert(a->get || a->set);
1149                 
1150                 for(l=a->flags;l;l=g_list_next(l)) {
1151                         char *flag = l->data;
1152                         int i;
1153                         if(strcmp(flag, "READWRITE")==0 ||
1154                            strcmp(flag, "READABLE")==0 ||
1155                            strcmp(flag, "WRITABLE")==0) {
1156                                 error_print(GOB_WARN, a->line_no,
1157                                             "READWRITE, READABLE and "
1158                                             "WRITABLE argument flags are "
1159                                             "set automatically");
1160                                 continue;
1161                         }
1162                         for(i = 0; argflags[i]; i++) {
1163                                 if(strcmp(argflags[i], flag)==0)
1164                                         break;
1165                         }
1166                         /* if we haven't found it in our list */
1167                         if( ! argflags[i]) {
1168                                 error_printf(GOB_WARN, a->line_no,
1169                                              "Unknown flag '%s' used, "
1170                                              "perhaps it was misspelled", flag);
1171                         }
1172                         g_string_sprintfa(flags, " | GTK_ARG_%s", flag);
1173                 }
1174
1175                 s = g_strdup(a->name);
1176                 g_strup(s);
1177                 out_printf(out, "\tgtk_object_add_arg_type(\"%s::%s\",\n"
1178                         "\t\tGTK_TYPE_%s,\n"
1179                         "\t\t%s,\n"
1180                         "\t\tARG_%s);\n",
1181                         typebase, a->name, a->gtktype, flags->str, s);
1182                 g_free(s);
1183                 g_string_free(flags, TRUE);
1184         }
1185         
1186         out_printf(out, "\n");
1187         if(get_arguments > 0)
1188                 out_printf(out, "\tgtk_object_class->get_arg = ___object_get_arg;\n");
1189         if(set_arguments > 0)
1190                 out_printf(out, "\tgtk_object_class->set_arg = ___object_set_arg;\n");
1191 }
1192
1193 static void
1194 print_initializer(Method *m, Variable *v)
1195 {
1196         char *root;
1197
1198         if(v->initializer == NULL)
1199                 return;
1200
1201         if(v->scope == PRIVATE_SCOPE)
1202                 root = g_strconcat(((FuncArg *)m->args->data)->name,
1203                                    "->_priv", NULL);
1204         else
1205                 root = g_strdup(((FuncArg *)m->args->data)->name);
1206
1207         if(v->initializer_line > 0)
1208                 out_addline_infile(out, v->initializer_line);
1209
1210         out_printf(out, "\t%s->%s = %s;\n",
1211                    root, v->id, v->initializer);
1212
1213         if(v->initializer_line > 0)
1214                 out_addline_outfile(out);
1215
1216         g_free(root);
1217 }
1218
1219 static void
1220 print_destructor(Variable *v)
1221 {
1222         char *root;
1223
1224         if(v->destructor == NULL)
1225                 return;
1226
1227         if(v->scope == PRIVATE_SCOPE)
1228                 root = "self->_priv";
1229         else
1230                 root = "self";
1231
1232         if(v->destructor_simple) {
1233                 if(v->destructor_line > 0)
1234                         out_addline_infile(out, v->destructor_line);
1235
1236                 out_printf(out, "\tif(%s->%s) { "
1237                            "((*(void (*)(void *))%s)) (%s->%s); "
1238                            "%s->%s = NULL; }\n",
1239                            root, v->id, v->destructor, root, v->id,
1240                            root, v->id);
1241
1242                 if(v->destructor_line > 0)
1243                         out_addline_outfile(out);
1244         } else {
1245                 out_printf(out, "#define VAR (%s->%s)\n", root, v->id);
1246                 out_printf(out, "\t{\n");
1247                 if(v->destructor_line > 0)
1248                         out_addline_infile(out, v->destructor_line);
1249
1250                 out_printf(out, "\t%s}\n", v->destructor);
1251
1252                 if(v->destructor_line > 0)
1253                         out_addline_outfile(out);
1254                 out_printf(out, "\tmemset(&VAR, 0, sizeof(VAR));\n");
1255                 out_printf(out, "#undef VAR\n");
1256         }
1257 }
1258
1259 static void
1260 add_destroy(Class *c)
1261 {
1262         out_printf(out, "\nstatic void\n"
1263                    "___destroy(GtkObject *obj_self)\n"
1264                    "{\n");
1265         out_printf(out,
1266                    "#define __GOB_FUNCTION__ \"%s::destroy\"\n",
1267                    c->otype);
1268
1269         if(destructors > 0) {
1270                 out_printf(out, "\t%s *self = %s (obj_self);\n",
1271                            typebase, macrobase);
1272         }
1273
1274         if(destroy_handler) {
1275                 /* so we get possible bad argument warning */
1276                 if(destroy_handler->line_no > 0)
1277                         out_addline_infile(out, destroy_handler->line_no);
1278                 out_printf(out, "\t___%x_%s_destroy(obj_self);\n",
1279                            (guint)destroy_handler->unique_id, funcbase);
1280                 if(destroy_handler->line_no > 0)
1281                         out_addline_outfile(out);
1282         } else {
1283                 out_printf(out,
1284                            "\tif(GTK_OBJECT_CLASS(parent_class)->destroy) \\\n"
1285                            "\t\t(* GTK_OBJECT_CLASS(parent_class)->destroy)(obj_self);\n");
1286         }
1287
1288         if(destructors > 0) {
1289                 GList *li;
1290                 for(li = ((Class *)class)->nodes;
1291                     li != NULL;
1292                     li = li->next) {
1293                         Node *n = li->data;
1294                         Variable *v = (Variable *)n;
1295                         if(n->type == VARIABLE_NODE &&
1296                            v->scope != CLASS_SCOPE)
1297                                 print_destructor(v);
1298                 }
1299         }
1300
1301         out_printf(out, "\treturn;\n");
1302         if(destructors > 0)
1303                 out_printf(out, "\tself = NULL;\n");
1304         out_printf(out, "}\n"
1305                    "#undef __GOB_FUNCTION__\n\n");
1306 }
1307
1308 static void
1309 add_finalize(Class *c)
1310 {
1311         /* Sort of a hack to make it work with gtk+ 1.3/2.0 */
1312         out_printf(out,
1313                    "\n#ifdef G_OBJECT_CLASS\n"
1314                    "static void\n"
1315                    "___finalize(GObject *obj_self)\n"
1316                    "#else /* !G_OBJECT_CLASS */\n"
1317                    "static void\n"
1318                    "___finalize(GtkObject *obj_self)\n"
1319                    "#endif /* G_OBJECT_CLASS */\n"
1320                    "{\n");
1321         out_printf(out,
1322                    "#define __GOB_FUNCTION__ \"%s::finalize\"\n",
1323                    c->otype);
1324
1325         if(privates > 0) {
1326                 out_printf(out, "\t%s *self = %s (obj_self);\n",
1327                            typebase, macrobase);
1328                 out_printf(out, "\tgpointer priv = self->_priv;\n");
1329         }
1330
1331         if(finalize_handler) {
1332                 /* so we get possible bad argument warning */
1333                 if(finalize_handler->line_no > 0)
1334                         out_addline_infile(out, finalize_handler->line_no);
1335                 out_printf(out, "\t___%x_%s_finalize(obj_self);\n",
1336                            (guint)finalize_handler->unique_id, funcbase);
1337                 if(finalize_handler->line_no > 0)
1338                         out_addline_outfile(out);
1339         } else {
1340                 /* Sort of a hack to make it work with gtk+ 1.3/2.0 */
1341                 out_printf(out,
1342                            "#ifdef G_OBJECT_CLASS\n"
1343                            "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
1344                            "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n"
1345                            "#else /* !G_OBJECT_CLASS */\n"
1346                            "\tif(GTK_OBJECT_CLASS(parent_class)->finalize) \\\n"
1347                            "\t\t(* GTK_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n"
1348                            "#endif /* G_OBJECT_CLASS */\n");
1349         }
1350
1351         if(privates > 0) {
1352                 out_printf(out, "\tg_free(priv);\n");
1353         }
1354
1355         out_printf(out, "}\n"
1356                    "#undef __GOB_FUNCTION__\n\n");
1357 }
1358
1359 static void
1360 add_inits(Class *c)
1361 {
1362         GList *li;
1363         for(li=c->nodes;li;li=g_list_next(li)) {
1364                 Node *n = li->data;
1365                 Method *m;
1366
1367                 gboolean add_unused_class = FALSE;
1368
1369                 if(n->type != METHOD_NODE)
1370                         continue;
1371                 m = (Method *)n;
1372                 if(m->method == INIT_METHOD) {
1373                         if(m->line_no > 0)
1374                                 out_addline_infile(out, m->line_no);
1375                         print_method(out, "static ", "\n", "", " ", "", "\n",
1376                                      m, FALSE, FALSE, TRUE);
1377                         if(m->line_no > 0)
1378                                 out_addline_outfile(out);
1379                         out_printf(out, "{\n"
1380                                    "#define __GOB_FUNCTION__ \"%s::init\"\n",
1381                                    c->otype);
1382                         if(privates > 0) {
1383                                 out_printf(out, "\t%s->_priv = "
1384                                            "g_new0 (%sPrivate, 1);\n",
1385                                            ((FuncArg *)m->args->data)->name,
1386                                            typebase);
1387                         } else if(always_private_struct) {
1388                                 out_printf(out, "\t%s->_priv = NULL;\n",
1389                                            ((FuncArg *)m->args->data)->name);
1390                         }
1391                         if(initializers > 0) {
1392                                 GList *li;
1393                                 for(li = ((Class *)class)->nodes;
1394                                     li != NULL;
1395                                     li = li->next) {
1396                                         Node *n = li->data;
1397                                         Variable *v = (Variable *)n;
1398                                         if(n->type != VARIABLE_NODE ||
1399                                            v->scope == CLASS_SCOPE)
1400                                                 continue;
1401                                         print_initializer(m, v);
1402                                 }
1403                         }
1404                 } else if(m->method == CLASS_INIT_METHOD) {
1405                         gboolean did_base_obj = FALSE;
1406
1407                         if(m->line_no > 0)
1408                                 out_addline_infile(out, m->line_no);
1409                         print_method(out, "static ", "\n", "", " ", "", "\n",
1410                                      m, FALSE, FALSE, TRUE);
1411                         if(m->line_no > 0)
1412                                 out_addline_outfile(out);
1413                         out_printf(out, "{\n"
1414                                    "#define __GOB_FUNCTION__ \"%s::class_init\"\n",
1415                                    c->otype);
1416                         if(signals > 0 ||
1417                            set_arguments > 0 ||
1418                            get_arguments > 0 ||
1419                            need_destroy ||
1420                            need_finalize) {
1421                                 add_unused_class = TRUE;
1422                                 out_printf(out,
1423                                            "\tGtkObjectClass *"
1424                                            "gtk_object_class = "
1425                                            "(GtkObjectClass*) %s;\n",
1426                                            ((FuncArg *)m->args->data)->name);
1427                                 out_printf(out,
1428                                            "#ifdef G_OBJECT_CLASS\n"
1429                                            "\tGObjectClass *"
1430                                            "g_object_class = "
1431                                            "(GObjectClass*) %s;\n"
1432                                            "#endif /* G_OBJECT_CLASS */\n",
1433                                            ((FuncArg *)m->args->data)->name);
1434                                 did_base_obj = TRUE;
1435                         }
1436
1437                         if(overrides > 0)
1438                                 add_overrides(c,
1439                                               ((FuncArg *)m->args->data)->name,
1440                                               did_base_obj);
1441
1442                         if(initializers > 0) {
1443                                 GList *li;
1444                                 for(li = ((Class *)class)->nodes;
1445                                     li != NULL;
1446                                     li = li->next) {
1447                                         Node *n = li->data;
1448                                         Variable *v = (Variable *)n;
1449                                         if(n->type == VARIABLE_NODE &&
1450                                            v->scope == CLASS_SCOPE)
1451                                                 print_initializer(m, v);
1452                                 }
1453                         }
1454                         
1455                         out_printf(out, "\n\tparent_class = ");
1456                         if(for_cpp)
1457                                 out_printf(out, "(%sClass *)", ptypebase);
1458                         out_printf(out, "gtk_type_class (%s_get_type ());\n",
1459                                    pfuncbase);
1460
1461                         if(signals > 0)
1462                                 add_signals(c);
1463
1464                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
1465
1466                         /* if there are no handlers for these things, we
1467                          * need to set them up here */
1468                         if(need_destroy && !destroy_handler)
1469                                 out_printf(out, "\tgtk_object_class->destroy "
1470                                            "= ___destroy;\n");
1471                         if(need_finalize && !finalize_handler)
1472                                 out_printf(out,
1473                                            "#ifdef G_OBJECT_CLASS\n"
1474                                            "\tg_object_class->finalize = ___finalize;\n"
1475                                            "#else /* !G_OBJECT_CLASS */\n"
1476                                            "\tgtk_object_class->finalize = ___finalize;\n"
1477                                            "#endif /* G_OBJECT_CLASS */\n");
1478                         
1479                         if(get_arguments > 0 || set_arguments > 0)
1480                                 make_arguments(c);
1481
1482                 } else
1483                         continue;
1484
1485                 if(m->cbuf) {
1486                         out_printf(out, " {\n");
1487                         out_addline_infile(out, m->ccode_line);
1488                         out_printf(out, "%s\n", m->cbuf);
1489                         out_addline_outfile(out);
1490                         out_printf(out, " }\n");
1491                 }
1492                 out_printf(out, "\treturn;\n");
1493                 out_printf(out,
1494                            "\t%s = NULL;\n",
1495                            ((FuncArg *)m->args->data)->name);
1496                 if(add_unused_class) {
1497                         out_printf(out,
1498                                    "\tgtk_object_class = NULL;\n"
1499                                    "#ifdef G_OBJECT_CLASS\n"
1500                                    "\tg_object_class = NULL;\n"
1501                                    "#endif /* G_OBJECT_CLASS */\n");
1502                 }
1503                 out_printf(out, "}\n"
1504                            "#undef __GOB_FUNCTION__\n");
1505         }
1506 }
1507
1508 static void
1509 add_getset_arg(Class *c, gboolean is_set)
1510 {
1511         GList *li;
1512         out_printf(out, "\nstatic void\n"
1513                    "___object_%s_arg (GtkObject *object,\n"
1514                    "\tGtkArg *arg,\n"
1515                    "\tguint arg_id)\n"
1516                    "#define __GOB_FUNCTION__ \"%s::%s_arg\"\n"
1517                    "{\n"
1518                    "\t%s *self;\n\n"
1519                    "\tself = %s (object);\n\n"
1520                    "\tswitch (arg_id) {\n",
1521                    is_set ? "set" : "get",
1522                    c->otype, is_set ? "set" : "get",
1523                    typebase, macrobase);
1524
1525         for(li=c->nodes;li;li=g_list_next(li)) {
1526                 Node *n = li->data;
1527                 Argument *a;
1528                 char *s;
1529                 char *cbuf;
1530                 int line_no;
1531                 if(n->type != ARGUMENT_NODE)
1532                         continue;
1533                 a = (Argument *)n;
1534                 if(is_set) {
1535                         cbuf = a->set;
1536                         line_no = a->set_line;
1537                 } else {
1538                         cbuf = a->get;
1539                         line_no = a->get_line;
1540                 }
1541                 if(!cbuf)
1542                         continue;
1543                 s = g_strdup(a->name);
1544                 g_strup(s);
1545                 out_printf(out, "\tcase ARG_%s:\n", s);
1546                 if(is_set && a->atype) {
1547                         char *cast = get_type(a->atype, TRUE);
1548                         if(no_gnu || for_cpp) {
1549                                 out_printf(out, "#define ARG "
1550                                            "((%s)GTK_VALUE_%s(*arg))\n",
1551                                            cast, a->gtktype);
1552                         } else {
1553                                 out_printf(out, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
1554                                 if(strcmp(a->gtktype, "OBJECT")==0) {
1555                                         out_printf(out, "#define ARG "
1556                                                    "({%s foo = "
1557                                                    "GTK_VALUE_POINTER(*arg); "
1558                                                    "foo; })\n",
1559                                                    cast);
1560                                 } else {
1561                                         out_printf(out, "#define ARG "
1562                                                    "({%s foo = "
1563                                                    "GTK_VALUE_%s(*arg); "
1564                                                    "foo; })\n",
1565                                                    cast, a->gtktype);
1566                                 }
1567                                 out_printf(out, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
1568                                 out_printf(out, "#define ARG "
1569                                            "((%s)GTK_VALUE_%s(*arg))\n",
1570                                            cast, a->gtktype);
1571                                 out_printf(out, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
1572                         }
1573                         out_printf(out, "\t\t{\n");
1574                         g_free(cast);
1575                 } else if(!is_set && strcmp(a->gtktype, "OBJECT")==0) {
1576                         out_printf(out,
1577                                    "#define ARG (GTK_VALUE_POINTER(*arg))\n"
1578                                    "\t\t{\n");
1579                 } else {
1580                         out_printf(out,
1581                                    "#define ARG (GTK_VALUE_%s(*arg))\n"
1582                                    "\t\t{\n",
1583                                    a->gtktype);
1584                 }
1585                 g_free(s);
1586                 if(line_no > 0)
1587                         out_addline_infile(out, line_no);
1588                 out_printf(out, "%s\n", cbuf);
1589                 if(line_no > 0)
1590                         out_addline_outfile(out);
1591                 out_printf(out, "\t\t}\n\t\tbreak;\n"
1592                         "#undef ARG\n");
1593         }
1594         out_printf(out, "\tdefault:\n\t\tbreak;\n\t}\n"
1595                    "\treturn;\n\tself = NULL;\n\targ = NULL;\n}\n"
1596                    "#undef __GOB_FUNCTION__\n");
1597 }
1598
1599 static void
1600 print_checks(Method *m, FuncArg *fa)
1601 {
1602         GList *li;
1603         gboolean is_void;
1604         gboolean checked_null = FALSE;
1605         is_void = (strcmp(m->mtype->name, "void")==0 &&
1606                    m->mtype->pointer == NULL);
1607         
1608         for(li = fa->checks; li; li = g_list_next(li)) {
1609                 Check *ch = li->data;
1610                 char *s;
1611                 /* point to the method prot in .gob for failed checks */
1612                 if(m->line_no > 0)
1613                         out_addline_infile(out, m->line_no);
1614                 if(is_void)
1615                         out_printf(out, "\tg_return_if_fail (");
1616                 else
1617                         out_printf(out, "\tg_return_val_if_fail (");
1618                 switch(ch->chtype) {
1619                 case NULL_CHECK:
1620                         out_printf(out, "%s != NULL", fa->name);
1621                         checked_null = TRUE;
1622                         break;
1623                 case TYPE_CHECK:
1624                         s = make_pre_macro(fa->atype->name, "IS");
1625                         if(checked_null)
1626                                 out_printf(out, "%s (%s)", s, fa->name);
1627                         else
1628                                 /* if not check null, null may be valid */
1629                                 out_printf(out, "!(%s) || %s (%s)", fa->name,
1630                                            s, fa->name);
1631                         g_free(s);
1632                         break;
1633                 case LT_CHECK:
1634                         out_printf(out, "%s < %s", fa->name, ch->number);
1635                         break;
1636                 case GT_CHECK:
1637                         out_printf(out, "%s > %s", fa->name, ch->number);
1638                         break;
1639                 case LE_CHECK:
1640                         out_printf(out, "%s <= %s", fa->name, ch->number);
1641                         break;
1642                 case GE_CHECK:
1643                         out_printf(out, "%s >= %s", fa->name, ch->number);
1644                         break;
1645                 case EQ_CHECK:
1646                         out_printf(out, "%s == %s", fa->name, ch->number);
1647                         break;
1648                 case NE_CHECK:
1649                         out_printf(out, "%s != %s", fa->name, ch->number);
1650                         break;
1651                 }
1652                 if(is_void)
1653                         out_printf(out, ");\n");
1654                 else {
1655                         out_printf(out, ", (");
1656                         print_type(out, m->mtype, TRUE);
1657                         out_printf(out, ")%s);\n",
1658                                 m->onerror?m->onerror:"0");
1659                 }
1660         }
1661 }
1662
1663 static void
1664 print_preconditions(Method *m)
1665 {
1666         GList *li;
1667         
1668         for(li=m->args;li;li=g_list_next(li)) {
1669                 FuncArg *fa = li->data;
1670                 if(fa->checks)
1671                         print_checks(m, fa);
1672         }
1673         if(m->line_no>0)
1674                 out_addline_outfile(out);
1675 }
1676
1677 static void
1678 print_method_body(Method *m, int pre)
1679 {
1680         out_printf(out, "{\n"
1681                    "#define __GOB_FUNCTION__ \"%s::%s\"\n",
1682                    ((Class *)class)->otype,
1683                    get_real_id(m->id));
1684         if(pre)
1685                 print_preconditions(m);
1686
1687         /* Note: the trailing }'s are on one line, this is so
1688            that we get the no return warning correctly and point to
1689            the correct line in the .gob file, yes this is slightly
1690            ugly in the .c file, but that is not supposed to be
1691            human readable anyway. */
1692         if(m->cbuf) {
1693                 out_printf(out, "{\n");
1694                 if(m->ccode_line>0)
1695                         out_addline_infile(out, m->ccode_line);
1696                 out_printf(out, "\t%s}", m->cbuf);
1697         }
1698
1699         /* Note, there is no \n between the last } and this } so that
1700          * errors/warnings reported on the end of the body get pointed to the
1701          * right line in the .gob source */
1702         out_printf(out, "}\n");
1703
1704         if(m->cbuf)
1705                 out_addline_outfile(out);
1706         out_printf(out, "#undef __GOB_FUNCTION__\n");
1707 }
1708
1709 static void
1710 put_signal_args(Method *m)
1711 {
1712         GList *li;
1713         GList *ali;
1714         for(ali = m->gtktypes->next, li=m->args->next;
1715             li && ali;
1716             li=li->next, ali=ali->next) {
1717                 FuncArg *fa = li->data;
1718                 const char *cast = get_cast(ali->data, FALSE);
1719                 /* we should have already proved before that
1720                    the we know all the types */
1721                 g_assert(cast);
1722
1723                 out_printf(out, ",\n\t\t(%s)%s", cast,
1724                            fa->name);
1725         }
1726 }
1727
1728 static char *
1729 get_arg_names_for_macro(Method *m)
1730 {
1731         char *p;
1732         GList *li;
1733         GString *gs = g_string_new(NULL);
1734         p = "";
1735         for(li=m->args;li;li=g_list_next(li)) {
1736                 FuncArg *arg = li->data;
1737                 g_string_sprintfa(gs, "%s___%s", p, arg->name);
1738                 p = ",";
1739         }
1740         p = gs->str;
1741         g_string_free(gs, FALSE);
1742         return p;
1743 }
1744
1745 static void
1746 put_method(Method *m)
1747 {
1748         char *s, *args, *doc;
1749         gboolean is_void;
1750         is_void = (strcmp(m->mtype->name, "void")==0 &&
1751                    m->mtype->pointer == NULL);
1752         out_printf(out, "\n");
1753         if(m->method != OVERRIDE_METHOD) {
1754                 doc = get_gtk_doc(m->id);
1755                 if(doc) {
1756                         out_printf(out, "%s", doc);
1757                         g_free(doc);
1758                 }
1759         }
1760         switch(m->method) {
1761         case REGULAR_METHOD:
1762                 if(m->line_no > 0)
1763                         out_addline_infile(out, m->line_no);
1764                 if(m->scope == PRIVATE_SCOPE)
1765                         print_method(out, "static ", "\n", "", " ", "", "\n",
1766                                      m, FALSE, FALSE, TRUE);
1767                 else /* PUBLIC, PROTECTED */
1768                         print_method(out, "", "\n", "", " ", "", "\n",
1769                                      m, FALSE, FALSE, TRUE);
1770                 print_method_body(m, TRUE);
1771                 /* the outfile line was added above */
1772                 break;
1773         case SIGNAL_FIRST_METHOD:
1774         case SIGNAL_LAST_METHOD:
1775                 if(m->line_no > 0)
1776                         out_addline_infile(out, m->line_no);
1777                 if(m->scope == PRIVATE_SCOPE)
1778                         print_method(out, "static ", "\n", "", " ", "", "\n",
1779                                      m, FALSE, FALSE, TRUE);
1780                 else /* PUBLIC, PROTECTED */
1781                         print_method(out, "", "\n", "", " ", "", "\n",
1782                                      m, FALSE, FALSE, TRUE);
1783                 out_addline_outfile(out);
1784                 out_printf(out, "{\n");
1785                 s = g_strdup(get_real_id(m->id));
1786                 g_strup(s);
1787                 if(strcmp(m->mtype->name, "void") == 0 &&
1788                    m->mtype->pointer == NULL) {
1789                         print_preconditions(m);
1790                         if(((FuncArg *)m->args->data)->name)
1791                         out_printf(out, "\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1792                                 "\t\tobject_signals[%s_SIGNAL]",
1793                                 ((FuncArg *)m->args->data)->name, s);
1794                         put_signal_args(m);
1795                         out_printf(out, ");\n}\n");
1796                 } else {
1797                         out_printf(out, "\t");
1798                         print_type(out, m->mtype, TRUE);
1799                         out_printf(out, "return_val = (");
1800                         print_type(out, m->mtype, TRUE);
1801                         if(m->defreturn)
1802                                 out_printf(out, ")(%s);\n", m->defreturn);
1803                         else if(m->onerror)
1804                                 out_printf(out, ")(%s);\n", m->onerror);
1805                         else
1806                                 out_printf(out, ")(0);\n");
1807                         print_preconditions(m);
1808                         out_printf(out, "\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1809                                 "\t\tobject_signals[%s_SIGNAL]",
1810                                 ((FuncArg *)m->args->data)->name, s);
1811                         put_signal_args(m);
1812                         out_printf(out, ",\n\t\t&return_val);\n"
1813                                 "\treturn return_val;\n}\n");
1814                 }
1815
1816                 if(!m->cbuf)
1817                         break;
1818                 if(m->line_no > 0)
1819                         out_addline_infile(out, m->line_no);
1820                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
1821                              m, FALSE, FALSE, TRUE);
1822                 print_method_body(m, FALSE);
1823                 /* the outfile line was added above */
1824                 break;
1825         case VIRTUAL_METHOD:
1826                 if(m->line_no > 0)
1827                         out_addline_infile(out, m->line_no);
1828                 if(m->scope==PRIVATE_SCOPE)
1829                         print_method(out, "static ", "\n", "", " ", "", "\n",
1830                                      m, FALSE, FALSE, TRUE);
1831                 else /* PUBLIC, PROTECTED */
1832                         print_method(out, "", "\n", "", " ", "", "\n",
1833                                      m, FALSE, FALSE, TRUE);
1834                 out_addline_outfile(out);
1835                 out_printf(out, "{\n"
1836                         "\t%sClass *klass;\n", typebase);
1837                 print_preconditions(m);
1838                 out_printf(out, "\tklass = %s_GET_CLASS(%s);\n\n"
1839                         "\tif(klass->%s)\n",
1840                         macrobase, ((FuncArg *)m->args->data)->name,
1841                         get_real_id(m->id));
1842                 if(strcmp(m->mtype->name, "void") == 0 &&
1843                    m->mtype->pointer == NULL) {
1844                         GList *li;
1845                         out_printf(out, "\t\t(*klass->%s)(%s",
1846                                    get_real_id(m->id),
1847                                    ((FuncArg *)m->args->data)->name);
1848                         for(li=m->args->next;li;li=g_list_next(li)) {
1849                                 FuncArg *fa = li->data;
1850                                 out_printf(out, ",%s", fa->name);
1851                         }
1852                         out_printf(out, ");\n}\n");
1853                 } else {
1854                         GList *li;
1855                         out_printf(out, "\t\treturn (*klass->%s)(%s",
1856                                    get_real_id(m->id),
1857                                    ((FuncArg *)m->args->data)->name);
1858                         for(li=m->args->next;li;li=g_list_next(li)) {
1859                                 FuncArg *fa = li->data;
1860                                 out_printf(out, ",%s", fa->name);
1861                         }
1862                         out_printf(out, ");\n"
1863                                 "\telse\n"
1864                                 "\t\treturn (");
1865                         print_type(out, m->mtype, TRUE);
1866                         if(m->defreturn)
1867                                 out_printf(out, ")(%s);\n}\n", m->defreturn);
1868                         else if(m->onerror)
1869                                 out_printf(out, ")(%s);\n}\n", m->onerror);
1870                         else
1871                                 out_printf(out, ")(0);\n}\n");
1872                 }
1873
1874                 if(!m->cbuf)
1875                         break;
1876                 if(m->line_no > 0)
1877                         out_addline_infile(out, m->line_no);
1878                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
1879                              m, FALSE, FALSE, TRUE);
1880                 print_method_body(m, FALSE);
1881                 /* the outfile line was added above */
1882                 break;
1883         case OVERRIDE_METHOD:
1884                 if(!m->cbuf)
1885                         break;
1886                 if(m->line_no > 0)
1887                         out_addline_infile(out, m->line_no);
1888                 s = g_strdup_printf("\n___%x_", (guint)m->unique_id);
1889                 print_method(out, "static ", s, "", " ", "", "\n",
1890                              m, FALSE, FALSE, FALSE);
1891                 g_free(s);
1892                 out_addline_outfile(out);
1893                 s = replace_sep(m->otype, '_');
1894                 g_strup(s);
1895                 args = get_arg_names_for_macro(m);
1896                 if(is_void) {
1897                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
1898                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
1899                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n",
1900                                    args, s, get_real_id(m->id), s, get_real_id(m->id), args);
1901                 } else {
1902                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
1903                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
1904                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n"
1905                                    "\t\t(",
1906                                    args, s, get_real_id(m->id), s, get_real_id(m->id), args);
1907                         out_printf(out, "(");
1908                         print_type(out, m->mtype, TRUE);
1909                         out_printf(out, ")%s))\n",
1910                                    m->onerror?m->onerror:"0");
1911                 }
1912                 g_free(args);
1913                 g_free(s);
1914                 print_method_body(m, TRUE);
1915                 /* the outfile line was added above */
1916                 out_printf(out, "#undef PARENT_HANDLER\n");
1917                 break;
1918         default:
1919                 break;
1920         }
1921 }
1922
1923 static void
1924 open_files(void)
1925 {
1926         char *outfile, *outfileh, *outfileph;
1927
1928         if(!for_cpp)
1929                 outfile = g_strconcat(filebase, ".c", NULL);
1930         else
1931                 outfile = g_strconcat(filebase, ".cc", NULL);
1932         if(no_touch_headers)
1933                 outfileh = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
1934         else
1935                 outfileh = g_strconcat(filebase, ".h", NULL);
1936
1937         if((privates > 0 || protecteds > 0 ||
1938             private_header == PRIVATE_HEADER_ALWAYS) &&
1939            private_header != PRIVATE_HEADER_NEVER)
1940                 outfileph = g_strconcat(filebase, "-private.h", NULL);
1941         else
1942                 outfileph = NULL;
1943
1944         
1945         if(no_write) {
1946                 devnull = fopen("/dev/null", "w");
1947                 if(!devnull)
1948                         g_error("Cannot open null device");
1949                 out = devnull;
1950                 outh = devnull;
1951                 if(outfileph)
1952                         outph = devnull;
1953         } else {
1954                 out = fopen(outfile, "w");
1955                 if(!out) {
1956                         g_error("Cannot open outfile: %s", outfile);
1957                 }
1958                 outh = fopen(outfileh, "w");
1959                 if(!outh)
1960                         g_error("Cannot open outfile: %s", outfileh);
1961                 if(outfileph) {
1962                         outph = fopen(outfileph, "w");
1963                         if(!outph)
1964                                 g_error("Cannot open outfile: %s", outfileh);
1965                 }
1966         }
1967 }
1968
1969 static void
1970 put_argument_nongnu_wrappers(Class *c)
1971 {
1972         GList *li;
1973
1974         if(get_arguments < 0 && set_arguments < 0)
1975                 return;
1976
1977         for(li=c->nodes;li;li=g_list_next(li)) {
1978                 Node *n = li->data;
1979                 Argument *a = (Argument *)n;
1980                 char *aname;
1981                 char *cast;
1982
1983                 if(n->type != ARGUMENT_NODE)
1984                         continue;
1985
1986                 aname = g_strdup(a->name);
1987                 g_strup(aname);
1988
1989                 if(a->atype)
1990                         cast = get_type(a->atype, TRUE);
1991                 else
1992                         cast = g_strdup(get_cast(a->gtktype, TRUE));
1993
1994                 if(cast) {
1995                         if(a->set)
1996                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1997                                            "\"%s\",(%s)(arg)\n",
1998                                            macrobase, aname, a->name, cast);
1999                         if(a->get)
2000                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2001                                            "\"%s\",(%s*)(arg)\n",
2002                                            macrobase, aname, a->name, cast);
2003                 } else {
2004                         if(a->set)
2005                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2006                                            "\"%s\",(arg)\n",
2007                                            macrobase, aname, a->name);
2008                         if(a->get)
2009                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2010                                            "\"%s\",(arg)\n",
2011                                            macrobase, aname, a->name);
2012                 }
2013                 g_free(cast);
2014                 g_free(aname);
2015         }
2016 }
2017
2018 static void
2019 put_argument_gnu_wrappers(Class *c)
2020 {
2021         GList *li;
2022
2023         if(get_arguments < 0 && set_arguments < 0)
2024                 return;
2025
2026         for(li=c->nodes;li;li=g_list_next(li)) {
2027                 Node *n = li->data;
2028                 Argument *a = (Argument *)n;
2029                 char *s;
2030                 char *cast;
2031                 if(n->type != ARGUMENT_NODE)
2032                         continue;
2033                 s = g_strdup(a->name);
2034                 g_strup(s);
2035                 if(a->atype)
2036                         cast = get_type(a->atype, TRUE);
2037                 else
2038                         cast = g_strdup(get_cast(a->gtktype, TRUE));
2039                 if(cast) {
2040                         if(a->set)
2041                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2042                                            "\"%s\",({%sz = (arg); z;})\n",
2043                                            macrobase, s, a->name, cast);
2044                         if(a->get)
2045                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2046                                            "\"%s\",({%s*z = (arg); z;})\n",
2047                                            macrobase, s, a->name, cast);
2048                 } else {
2049                         if(a->set)
2050                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2051                                            "\"%s\",(arg)\n",
2052                                            macrobase, s, a->name);
2053                         if(a->get)
2054                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2055                                            "\"%s\",(arg)\n",
2056                                            macrobase, s, a->name);
2057                 }
2058                 g_free(cast);
2059                 g_free(s);
2060         }
2061 }
2062
2063 static void
2064 print_ccode_block(CCode *cc)
2065 {
2066         FILE *fp;
2067         switch(cc->cctype) {
2068         case HT_CCODE:
2069                 /* HT code is printed exactly like normal header
2070                    code but is printed before */
2071         case H_CCODE:
2072                 fp = outh;
2073                 out_printf(fp, "\n");
2074                 break;
2075         case AT_CCODE:
2076                 /* AT code is printed exactly like normal 'all'
2077                    code but is printed before */
2078         case A_CCODE:
2079                 if(outph) {
2080                         out_printf(outph, "\n");
2081                         out_printf(outph, "%s\n", cc->cbuf);
2082                         out_addline_infile(outph, cc->line_no);
2083                         out_addline_outfile(outph);
2084                 }
2085                 out_printf(outh, "\n");
2086                 out_printf(outh, "%s\n", cc->cbuf);
2087                 fp = out;
2088                 out_printf(fp, "\n");
2089                 out_addline_infile(fp, cc->line_no);
2090                 break;
2091         default:
2092         case C_CCODE:
2093                 fp = out;
2094                 out_printf(fp, "\n");
2095                 out_addline_infile(fp, cc->line_no);
2096                 break;
2097         case PH_CCODE:
2098                 if(outph)
2099                         fp = outph;
2100                 else
2101                         fp = out;
2102                 out_printf(fp, "\n");
2103                 out_addline_infile(fp, cc->line_no);
2104                 break;
2105         }
2106         out_printf(fp, "%s\n", cc->cbuf);
2107         if(cc->cctype == C_CCODE ||
2108            cc->cctype == A_CCODE ||
2109            cc->cctype == AT_CCODE ||
2110            cc->cctype == PH_CCODE)
2111                 out_addline_outfile(fp);
2112 }
2113
2114 static void
2115 print_class_block(Class *c)
2116 {
2117         GList *l;
2118         char *s;
2119         gboolean printed_private = FALSE;
2120
2121         if(any_special) {
2122                 out_printf(out, "/* utility types we may need */\n");
2123                 if(special_array[SPECIAL_2POINTER])
2124                         out_printf(out, "typedef struct { "
2125                                    "gpointer a; gpointer b; "
2126                                    "} ___twopointertype;\n");
2127                 if(special_array[SPECIAL_3POINTER])
2128                         out_printf(out, "typedef struct { "
2129                                    "gpointer a; gpointer b; "
2130                                    "gpointer c; "
2131                                    "} ___threepointertype;\n");
2132                 if(special_array[SPECIAL_INT_POINTER])
2133                         out_printf(out, "typedef struct { "
2134                                    "gint a; gpointer b; "
2135                                    "} ___intpointertype;\n");
2136                 out_printf(out, "\n");
2137         }
2138
2139         out_printf(outh, "\n/*\n"
2140                    " * Type checking and casting macros\n"
2141                    " */\n");
2142         out_printf(outh, "#define %s\t"
2143                    "(%s_get_type())\n",
2144                    macrotype, funcbase);
2145         out_printf(outh, "#define %s(obj)\t"
2146                    "GTK_CHECK_CAST((obj), %s_get_type(), %s)\n",
2147                    macrobase, funcbase, typebase);
2148         out_printf(outh, "#define %s_CONST(obj)\t"
2149                    "GTK_CHECK_CAST((obj), %s_get_type(), %s const)\n",
2150                    macrobase, funcbase, typebase); 
2151         out_printf(outh, "#define %s_CLASS(klass)\t"
2152                    "GTK_CHECK_CLASS_CAST((klass), %s_get_type(), %sClass)\n",
2153                    macrobase, funcbase, typebase);
2154         out_printf(outh, "#define %s(obj)\t"
2155                    "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
2156                    macrois, funcbase);
2157         out_printf(outh, "#ifdef GTK_CHECK_GET_CLASS\n"
2158                    "#define %s_GET_CLASS(obj)\t"
2159                    "GTK_CHECK_GET_CLASS((obj), %s_get_type(), %sClass)\n",
2160                    macrobase, funcbase, typebase);
2161         out_printf(outh, "#else /* !GTK_CHECK_GET_CLASS */\n"
2162                    "#define %s_GET_CLASS(obj)\t"
2163                    "((%sClass *)GTK_OBJECT(obj)->klass)\n"
2164                    "#endif /* GTK_CHECK_GET_CLASS */\n",
2165                    macrobase, typebase);
2166
2167         if( ! no_self_alias) {
2168                 out_printf(out, "/* self casting macros */\n");
2169                 out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
2170                 out_printf(out, "#define SELF_CONST(x) %s_CONST(x)\n", macrobase);
2171                 out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
2172                 out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n",
2173                            macrobase);
2174                 out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n",
2175                            macrobase);
2176
2177                 out_printf(out, "/* self typedefs */\n");
2178                 out_printf(out, "typedef %s Self;\n", typebase);
2179                 out_printf(out, "typedef %sClass SelfClass;\n\n", typebase);
2180         }
2181
2182         out_printf(out, "/* GTK_CLASS_TYPE for 1.2<->1.3/2.0 GTK+ compatibility */\n");
2183         out_printf(out,
2184                    "#ifndef GTK_CLASS_TYPE\n"
2185                    "#define GTK_CLASS_TYPE(x) (GTK_OBJECT_CLASS(x)->type)\n"
2186                    "#endif /* GTK_CLASS_TYPE */\n\n");
2187
2188         if(privates > 0 || always_private_struct) {
2189                 out_printf(outh, "\n/* Private structure type */\n");
2190                 out_printf(outh, "typedef struct _%sPrivate %sPrivate;\n",
2191                            typebase, typebase);
2192                 if(privates == 0)
2193                         out_printf(outh, "/* There are no privates, this "
2194                                    "structure is thus never defined */\n");
2195         }
2196
2197         out_printf(outh, "\n/*\n"
2198                    " * Main object structure\n"
2199                    " */\n");
2200         s = replace_sep(c->otype, '_');
2201         g_strup(s);
2202         out_printf(outh, "#ifndef __TYPEDEF_%s__\n"
2203                    "#define __TYPEDEF_%s__\n", s, s);
2204         g_free(s);
2205         out_printf(outh, "typedef struct _%s %s;\n"
2206                    "#endif\n", typebase, typebase);
2207         out_printf(outh, "struct _%s {\n\t%s __parent__;\n",
2208                    typebase, ptypebase);
2209         for(l=c->nodes; l; l=g_list_next(l)) {
2210                 static gboolean printed_public = FALSE;
2211                 Node *n = l->data;
2212                 Variable *v = (Variable *)n;
2213                 if(n->type == VARIABLE_NODE &&
2214                    v->scope == PUBLIC_SCOPE) {
2215                         if( ! printed_public) {
2216                                 out_printf(outh, "\t/*< public >*/\n");
2217                                 printed_public = TRUE;
2218                         }
2219                         put_variable((Variable *)n, outh);
2220                 }
2221         }
2222         /* put protecteds always AFTER publics */
2223         for(l=c->nodes; l; l=g_list_next(l)) {
2224                 Node *n = l->data;
2225                 Variable *v = (Variable *)n;
2226                 if(n->type == VARIABLE_NODE &&
2227                    v->scope == PROTECTED_SCOPE) {
2228                         if( ! printed_private) {
2229                                 out_printf(outh, "\t/*< private >*/\n");
2230                                 printed_private = TRUE;
2231                         }
2232                         put_variable((Variable *)n, outh);
2233                 }
2234         }
2235         if(privates > 0 || always_private_struct) {
2236                 if( ! printed_private)
2237                         out_printf(outh, "\t/*< private >*/\n");
2238                 out_printf(outh, "\t%sPrivate *_priv;\n", typebase);
2239         }
2240         out_printf(outh, "};\n");
2241
2242         if(privates > 0) {
2243                 FILE *outfp;
2244
2245                 /* if we are to stick this into the private
2246                    header, if not stick it directly into the
2247                    C file */
2248                 if(outph) 
2249                         outfp = outph;
2250                 else
2251                         outfp = out;
2252
2253                 out_printf(outfp, "struct _%sPrivate {\n",
2254                            typebase);
2255                 for(l=c->nodes; l; l=l->next) {
2256                         Node *n = l->data;
2257                         Variable *v = (Variable *)n;
2258                         if(n->type == VARIABLE_NODE &&
2259                            v->scope == PRIVATE_SCOPE) {
2260                                 out_addline_infile(outfp, v->line_no);
2261                                 put_variable(v, outfp);
2262                         }
2263                 }
2264                 out_addline_outfile(outfp);
2265                 out_printf(outfp, "};\n");
2266         }
2267
2268         out_printf(outh, "\n/*\n"
2269                    " * Class definition\n"
2270                    " */\n");
2271         out_printf(outh, "typedef struct _%sClass %sClass;\n",
2272                    typebase, typebase);
2273         out_printf(outh,
2274                    "struct _%sClass {\n\t%sClass __parent__;\n",
2275                    typebase, ptypebase);
2276         for(l = c->nodes; l != NULL; l = l->next) {
2277                 Node *n = l->data;
2278                 if(n->type == METHOD_NODE)
2279                         put_vs_method((Method *)n);
2280         }
2281         /* put class scope variables */
2282         for(l = c->nodes; l != NULL; l = l->next) {
2283                 Node *n = l->data;
2284                 Variable *v = (Variable *)n;
2285                 if(n->type == VARIABLE_NODE &&
2286                    v->scope == CLASS_SCOPE)
2287                         put_variable((Variable *)n, outh);
2288         }
2289         out_printf(outh, "};\n\n");
2290
2291         out_printf(out, "/* here are local prototypes */\n");
2292         if(set_arguments > 0) {
2293                 out_printf(out, "static void ___object_set_arg "
2294                            "(GtkObject *object, GtkArg *arg, "
2295                            "guint arg_id);\n");
2296         }
2297         if(get_arguments > 0) {
2298                 out_printf(out, "static void ___object_get_arg "
2299                            "(GtkObject *object, GtkArg *arg, "
2300                            "guint arg_id);\n");
2301         }
2302
2303         out_printf(outh, "\n/*\n"
2304                    " * Public methods\n"
2305                    " */\n");
2306
2307         out_printf(outh, "GtkType\t%s_get_type\t(void)", funcbase);
2308         if ( ! no_gnu) {
2309                 out_printf(outh, " G_GNUC_CONST;\n");
2310         } else {
2311                 out_printf(outh, ";\n");
2312         }
2313
2314         for(l = c->nodes; l != NULL; l = l->next) {
2315                 Node *n = l->data;
2316                 if(n->type == METHOD_NODE) {
2317                         put_pub_method((Method *)n);
2318                         put_prot_method((Method *)n);
2319                         put_priv_method_prot((Method *)n);
2320                 }
2321         }
2322
2323         /* this idea is less and less apealing to me */
2324         if (signals > 0) {
2325                 out_printf (outh, "\n/*\n"
2326                             " * Signal connection wrapper macros\n"
2327                             " */\n");
2328                 if( ! no_gnu) {
2329                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2330                         put_signal_macros (c, TRUE);
2331                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
2332                         put_signal_macros (c, FALSE);
2333                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
2334                 } else {
2335                         put_signal_macros (c, FALSE);
2336                 }
2337         }
2338
2339         /* argument wrapping macros */
2340         if(get_arguments > 0 || set_arguments > 0) {
2341                 out_printf(outh, "\n/*\n"
2342                            " * Argument wrapping macros\n"
2343                            " */\n");
2344                 if( ! no_gnu) {
2345                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2346                         put_argument_gnu_wrappers(c);
2347                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
2348                         put_argument_nongnu_wrappers(c);
2349                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
2350                 } else {
2351                         put_argument_nongnu_wrappers(c);
2352                 }
2353         }
2354
2355         if(signals > 0) {
2356                 for(l = c->nodes; l != NULL; l = l->next) {
2357                         Node *n = l->data;
2358                         if(n->type == METHOD_NODE)
2359                                 add_signal_prots((Method *)n);
2360                 }
2361         }
2362
2363         add_enums(c);
2364
2365         if ( ! overrode_get_type)
2366                 add_get_type();
2367
2368         if(any_method_to_alias(c)) {
2369                 if( ! no_gnu) {
2370                         out_printf(out, "/* Short form macros */\n");
2371                         out_printf(out, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2372                         make_method_gnu_aliases(c);
2373                         out_printf(out, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n");
2374                 }
2375                 make_method_nongnu_aliases(c);
2376         }
2377
2378         out_printf(out, "/* a macro for creating a new object of our type */\n");
2379         out_printf(out,
2380                    "#define GET_NEW ((%s *)gtk_type_new(%s_get_type()))\n\n",
2381                    typebase, funcbase);
2382
2383         if(need_destroy)
2384                 add_destroy(c);
2385
2386         if(need_finalize)
2387                 add_finalize(c);
2388
2389         add_inits(c);
2390
2391         if(set_arguments > 0) {
2392                 add_getset_arg(c, TRUE);
2393         }
2394
2395         if(get_arguments > 0) {
2396                 add_getset_arg(c, FALSE);
2397         }
2398
2399         for(l = c->nodes; l != NULL; l = l->next) {
2400                 Node *n = l->data;
2401                 if(n->type == METHOD_NODE)
2402                         put_method((Method *)n);
2403         }
2404
2405         add_bad_hack_to_avoid_unused_warnings(c);
2406 }
2407
2408 static void
2409 print_version_macros(void)
2410 {
2411         int major=0, minor=0, pl=0;
2412         sscanf(VERSION, "%d.%d.%d", &major, &minor, &pl);
2413
2414         out_printf(out, "#define GOB_VERSION_MAJOR %d\n", major);
2415         out_printf(out, "#define GOB_VERSION_MINOR %d\n", minor);
2416         out_printf(out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
2417 }
2418
2419 static void
2420 print_file_comments(void)
2421 {
2422         time_t curtime;
2423         time(&curtime);
2424         out_printf(outh, "/* Generated by GOB (v%s)"
2425                    "   (do not edit directly) */\n\n", VERSION);
2426         if(outph)
2427                 out_printf(outph, "/* Generated by GOB (v%s)"
2428                            "   (do not edit directly) */\n\n", VERSION);
2429         out_printf(out, "/* Generated by GOB (v%s) on %s"
2430                    "   (do not edit directly) */\n\n",
2431                    VERSION, ctime(&curtime));
2432
2433         out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
2434 }
2435
2436 static void
2437 print_includes(void)
2438 {
2439         gboolean found_header;
2440         char *p;
2441
2442         /* We may need string.h for memset */
2443         if(destructors > 0 &&
2444            ! g_list_find_custom(include_files, "string.h", (GCompareFunc)strcmp)) {
2445                 out_printf(out, "#include <string.h> /* memset() */\n\n");
2446         }
2447
2448         p = g_strconcat(filebase, ".h", NULL);
2449         found_header = TRUE;
2450         if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
2451                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
2452                 found_header = FALSE;
2453         }
2454         g_free(p);
2455
2456         /* if we are creating a private header see if it was included */
2457         if(outph) {
2458                 p = g_strconcat(filebase, "-private.h", NULL);
2459                 if( ! g_list_find_custom(include_files, p,
2460                                          (GCompareFunc)strcmp)) {
2461                         out_printf(out, "#include \"%s-private.h\"\n\n",
2462                                    filebase);
2463                         if(found_header)
2464                                 error_printf(GOB_WARN, 0,
2465                                             "Implicit private header include "
2466                                             "added to top of\n"
2467                                             "\tsource file, while public "
2468                                             "header is at a custom location, "
2469                                             "you should\n"
2470                                             "\texplicitly include "
2471                                             "the private header below the "
2472                                             "public one.");
2473                 }
2474                 g_free(p);
2475         }
2476 }
2477
2478 static void
2479 print_header_prefixes(void)
2480 {
2481         char *p;
2482
2483         p = replace_sep(((Class *)class)->otype, '_');
2484         g_strup(p);
2485         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
2486         if(outph)
2487                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
2488                            "#define __%s_PRIVATE_H__\n\n"
2489                            "#include \"%s.h\"\n\n", p, p, filebase);
2490         g_free(p);
2491
2492         if( ! no_extern_c) {
2493                 out_printf(outh, "#ifdef __cplusplus\n"
2494                            "extern \"C\" {\n"
2495                            "#endif /* __cplusplus */\n\n");
2496                 if(outph)
2497                         out_printf(outph, "#ifdef __cplusplus\n"
2498                                    "extern \"C\" {\n"
2499                                    "#endif /* __cplusplus */\n\n");
2500         }
2501 }
2502
2503 static void
2504 print_header_postfixes(void)
2505 {
2506         if( ! no_extern_c)
2507                 out_printf(outh, "\n#ifdef __cplusplus\n"
2508                            "}\n"
2509                            "#endif /* __cplusplus */\n");
2510         out_printf(outh, "\n#endif\n");
2511         if(outph) {
2512                 if( ! no_extern_c)
2513                         out_printf(outph, "\n#ifdef __cplusplus\n"
2514                                    "}\n"
2515                                    "#endif /* __cplusplus */\n");
2516                 out_printf(outph, "\n#endif\n");
2517         }
2518 }
2519
2520 static void
2521 print_all_top(void)
2522 {
2523         GList *li;
2524
2525         /* print the AT_CCODE blocks */
2526         for(li = nodes; li != NULL; li = li->next) {
2527                 Node *node = li->data;
2528                 if(node->type == CCODE_NODE) {
2529                         CCode *cc = (CCode *)node;
2530                         if(cc->cctype == AT_CCODE)
2531                                 print_ccode_block((CCode *)node);
2532                 }
2533         }
2534 }
2535
2536 static void
2537 print_header_top(void)
2538 {
2539         GList *li;
2540
2541         /* mandatory include */
2542         out_printf(outh, "#include <gtk/gtk.h>\n\n");
2543
2544         /* print the HT_CCODE blocks */
2545         for(li=nodes;li;li=g_list_next(li)) {
2546                 Node *node = li->data;
2547                 if(node->type == CCODE_NODE) {
2548                         CCode *cc = (CCode *)node;
2549                         if(cc->cctype == HT_CCODE)
2550                                 print_ccode_block((CCode *)node);
2551                 }
2552         }
2553 }
2554
2555 static void
2556 generate_outfiles(void)
2557 {
2558         GList *li;
2559
2560         print_file_comments();
2561
2562         print_all_top();
2563
2564         print_header_top();
2565
2566         print_header_prefixes();
2567
2568         print_version_macros();
2569
2570         print_includes();
2571
2572         for(li=nodes;li;li=g_list_next(li)) {
2573                 Node *node = li->data;
2574                 if(node->type == CCODE_NODE) {
2575                         CCode *cc = (CCode *)node;
2576                         if(cc->cctype != HT_CCODE &&
2577                            cc->cctype != AT_CCODE)
2578                                 print_ccode_block((CCode *)node);
2579                 } else if(node->type == CLASS_NODE) {
2580                         print_class_block((Class *)node);
2581                 } else
2582                         g_assert_not_reached();
2583         }
2584
2585         print_header_postfixes();
2586 }
2587
2588 static void
2589 print_help(void)
2590 {
2591         fprintf(stderr, "Gob version %s\n\n", VERSION);
2592         fprintf(stderr, "gob [options] file.gob\n\n");
2593         fprintf(stderr, "Options:\n"
2594                 "\t--help,-h,-?            Display this help\n"
2595                 "\t--version               Display version\n"
2596                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
2597                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
2598                 "\t--for-cpp               Create C++ files\n"
2599                 "\t--no-extern-c           Never print extern \"C\" into the "
2600                                           "header\n"
2601                 "\t--no-gnu                Never use GNU extentions\n"
2602                 "\t--no-touch-headers      Don't touch headers unless they "
2603                                           "really changed\n"
2604                 "\t--always-private-header Always create a private header "
2605                                           "file,\n"
2606                 "\t                        even if it would be empty "
2607                                           "[default]\n"
2608                 "\t--ondemand-private-header Create private header only when "
2609                                           "needed\n"
2610                 "\t--no-private-header     Don't create a private header, "
2611                                           "put private\n"
2612                 "\t                        structure and protected "
2613                                           "prototypes inside c file\n"
2614                 "\t--always-private-struct Always create a private pointer "
2615                                           "in\n"
2616                 "\t                        the object structure\n"
2617                 "\t--no-write,-n           Don't write output files, just "
2618                                           "check syntax\n"
2619                 "\t--no-lines              Don't print '#line' to output\n"
2620                 "\t--no-self-alias         Don't create self type and macro "
2621                                           "aliases\n"
2622                 "\t--no-kill-underscores   Don't remove the leading underscore "
2623                                           "from\n"
2624                 "\t                        short id names\n");
2625 }
2626
2627 static void
2628 parse_options(int argc, char *argv[])
2629 {
2630         int i;
2631         int got_file = FALSE;
2632         int no_opts = FALSE;
2633
2634         filename = NULL;
2635
2636         for(i = 1 ; i < argc; i++) {
2637                 if(no_opts ||
2638                    argv[i][0] != '-') {
2639                         /*must be a file*/
2640                         if(got_file) {
2641                                 fprintf(stderr, "Specify only one file!\n");
2642                                 print_help();
2643                                 exit(1);
2644                         }
2645                         filename = argv[i];
2646                         got_file = TRUE;
2647                 } else if(strcmp(argv[i], "--help")==0) {
2648                         print_help();
2649                         exit(0);
2650                 } else if(strcmp(argv[i], "--version")==0) {
2651                         fprintf(stderr, "Gob version %s\n", VERSION);
2652                         exit(0);
2653                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
2654                         exit_on_warn = TRUE;
2655                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
2656                         exit_on_warn = FALSE;
2657                 } else if(strcmp(argv[i], "--for-cpp")==0) {
2658                         for_cpp = TRUE;
2659                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
2660                         no_touch_headers = TRUE;
2661                 } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
2662                         private_header = PRIVATE_HEADER_ONDEMAND;
2663                 } else if(strcmp(argv[i], "--always-private-header")==0) {
2664                         private_header = PRIVATE_HEADER_ALWAYS;
2665                 } else if(strcmp(argv[i], "--no-private-header")==0) {
2666                         private_header = PRIVATE_HEADER_NEVER;
2667                 } else if(strcmp(argv[i], "--no-gnu")==0) {
2668                         no_gnu = TRUE;
2669                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
2670                         no_extern_c = TRUE;
2671                 } else if(strcmp(argv[i], "--no-write")==0) {
2672                         no_write = TRUE;
2673                 } else if(strcmp(argv[i], "--no-lines")==0) {
2674                         no_lines = TRUE;
2675                 } else if(strcmp(argv[i], "--no-self-alias")==0) {
2676                         no_self_alias = TRUE;
2677                 } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
2678                         no_kill_underscores = TRUE;
2679                 } else if(strcmp(argv[i], "--always-private-struct")==0) {
2680                         always_private_struct = TRUE;
2681                 } else if(strcmp(argv[i], "--")==0) {
2682                         /*further arguments are files*/
2683                         no_opts = TRUE;
2684                 } else if(strncmp(argv[i], "--", 2)==0) {
2685                         /*unknown long option*/
2686                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
2687                         print_help();
2688                         exit(1);
2689                 } else {
2690                         /*by now we know we have a string starting with
2691                           - which is a short option string*/
2692                         char *p;
2693                         for(p = argv[i] + 1; *p; p++) {
2694                                 switch(*p) {
2695                                 case 'w':
2696                                         exit_on_warn=TRUE;
2697                                         break;
2698                                 case 'n':
2699                                         no_write = TRUE;
2700                                         break;
2701                                 case 'h':
2702                                 case '?':
2703                                         print_help();
2704                                         exit(0);
2705                                 default:
2706                                         fprintf(stderr,
2707                                                 "Unknown option '%c'!\n", *p);
2708                                         print_help();
2709                                         exit(1);
2710                                 }
2711                         }
2712                 }
2713         }
2714 }
2715
2716 /* this is a somewhat ugly hack, but it appears to work */
2717 static void
2718 compare_and_move_header(void)
2719 {
2720         char *hfnew = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
2721         char *hf = g_strconcat(filebase, ".h", NULL);
2722         struct stat s;
2723         if(stat(hf, &s) == 0) {
2724                 char *s;
2725                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
2726                 if(system(s) == 0) {
2727                         if(unlink(hfnew) != 0)
2728                                 error_printf(GOB_ERROR, 0,
2729                                              "Can't remove new header file");
2730                         g_free(hfnew);
2731                         g_free(hf);
2732                         g_free(s);
2733                         return;
2734                 }
2735                 g_free(s);
2736                 if(unlink(hf) != 0)
2737                         error_printf(GOB_ERROR, 0,
2738                                      "Can't remove old header file");
2739         }
2740         if(rename(hfnew, hf) != 0)
2741                 error_printf(GOB_ERROR, 0,
2742                              "Can't rename new header file");
2743         g_free(hfnew);
2744         g_free(hf);
2745 }
2746
2747 int
2748 main(int argc, char *argv[])
2749 {
2750         parse_options(argc, argv);
2751         
2752         if(filename) {
2753                 yyin = fopen(filename, "r");
2754                 if(!yyin) {
2755                         fprintf(stderr, "Error: can't open file '%s'\n",
2756                                 filename);
2757                         exit(1);
2758                 }
2759         } else
2760                 filename = "stdin";
2761
2762         /* This is where parsing is done */
2763         /*yydebug = 1;*/
2764         if(yyparse() != 0)
2765                 g_error("Parsing errors, quitting");
2766
2767         if( ! class)
2768                 error_print(GOB_ERROR, 0, " no class defined");
2769         
2770
2771         exit_on_error = FALSE;
2772
2773         signals = count_signals((Class *)class);
2774         set_arguments = count_set_arguments((Class *)class);
2775         get_arguments = count_get_arguments((Class *)class);
2776         overrides = count_overrides((Class *)class);
2777         privates = count_privates((Class *)class);
2778         protecteds = count_protecteds((Class *)class);
2779         destructors = count_destructors((Class *)class);
2780         initializers = count_initializers((Class *)class);
2781         overrode_get_type = find_get_type((Class *)class);
2782
2783         make_bases();
2784         make_inits((Class *)class);
2785         if(destructors > 0) {
2786                 need_destroy = TRUE;
2787                 find_destroy((Class *)class);
2788         }
2789         if(privates > 0) {
2790                 need_finalize = TRUE;
2791                 find_finalize((Class *)class);
2792         }
2793         check_bad_symbols((Class *)class);
2794         check_duplicate_symbols((Class *)class);
2795         check_duplicate_overrides((Class *)class);
2796         check_duplicate_signals_args((Class *)class);
2797         check_public_new((Class *)class);
2798         check_vararg((Class *)class);
2799         check_firstarg((Class *)class);
2800         check_nonvoidempty((Class *)class);
2801         check_signal_args((Class *)class);
2802         check_argument_types((Class *)class);
2803         check_func_arg_checks((Class *)class);
2804
2805         exit_on_error = TRUE;
2806         
2807         if(got_error)
2808                 exit(1);
2809
2810         any_special = setup_special_array((Class *)class, special_array);
2811
2812         open_files();
2813         
2814         generate_outfiles();
2815
2816         if(devnull)
2817                 fclose(devnull);
2818         else {
2819                 fclose(out);
2820                 fclose(outh);
2821                 if(outph)
2822                         fclose(outph);
2823         }
2824
2825         if(no_touch_headers &&
2826            ! no_write)
2827                 compare_and_move_header();
2828         
2829         return 0;
2830 }