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