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