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