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