]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
e55600609017600f1a98430a99c2a89638611fc3
[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 char *filebase;
48 static char *funcbase;
49 static char *pfuncbase;
50 static char *macrobase;
51 static char *macrois;
52 static char *macrotype;
53 static char *typebase;
54 static char *ptypebase;
55
56 static int signals = 0;
57 static int arguments = 0;
58 static int overrides = 0;
59
60 FILE *out;
61 FILE *outh;
62
63 gboolean no_touch_headers = FALSE;
64 gboolean for_cpp = FALSE;
65 gboolean exit_on_warn = FALSE;
66 gboolean exit_on_error = TRUE;
67 gboolean got_error = FALSE;
68
69 void
70 print_error(int is_warn, char *error,int line)
71 {
72         char *w;
73         if(is_warn)
74                 w = "Warning:";
75         else {
76                 w = "Error:";
77                 got_error = TRUE;
78         }
79         if(line>0)
80                 fprintf(stderr,"%s:%d: %s %s\n",filename,line,w,error);
81         else
82                 fprintf(stderr,"%s: %s %s\n",filename,w,error);
83         if((!is_warn || exit_on_warn) && exit_on_error)
84                 exit(1);
85 }
86
87 static char *
88 remove_sep(char *base)
89 {
90         char *p;
91         char *s = g_strdup(base);
92         while((p=strchr(s,':')))
93                 strcpy(p,p+1);
94         return s;
95 }
96
97 static char *
98 replace_sep(char *base, char r)
99 {
100         char *p;
101         char *s = g_strdup(base);
102         while((p=strchr(s,':')))
103                 *p = r;
104         if(*s == r) {
105                 p = g_strdup(s+1);
106                 g_free(s);
107                 return p;
108         }
109         return s;
110 }
111
112 /*separate the namespace part and then replace rest of
113   separators with r*/
114 static void
115 separns_replace_sep(char *base, char **ns, char **name, char r)
116 {
117         char *p;
118         char *s = g_strdup(base);
119         *ns = NULL;
120         if((p=strchr(s,':')) && p!=s) {
121                 *p = '\0';
122                 *ns = g_strdup(s);
123                 p = g_strdup(p+1);
124                 g_free(s);
125                 s = p;
126         }
127         while((p=strchr(s,':')))
128                 *p = r;
129         if(*s == r) {
130                 *name = g_strdup(s+1);
131                 g_free(s);
132         } else
133                 *name = s;
134 }
135
136 /* make a macro with some prefix before the name but after
137    namespace */
138 static char *
139 make_pre_macro(char *base, char *pre)
140 {
141         char *s1,*s2;
142         char *s;
143
144         separns_replace_sep(base,&s1,&s2,'_');
145         if(s1)
146                 s = g_strconcat(s1,"_",pre,"_",s2,NULL);
147         else
148                 s = g_strconcat(pre,"_",s2,NULL);
149
150         g_strup(s);
151         
152         g_free(s1);
153         g_free(s2);
154
155         return s;
156 }
157
158 static void
159 make_bases(void)
160 {
161         filebase = replace_sep(((Class *)class)->otype,'-');
162         g_strdown(filebase);
163
164         funcbase = replace_sep(((Class *)class)->otype,'_');
165         g_strdown(funcbase);
166
167         pfuncbase = replace_sep(((Class *)class)->ptype,'_');
168         g_strdown(pfuncbase);
169
170         macrobase = replace_sep(((Class *)class)->otype,'_');
171         g_strup(macrobase);
172         
173         macrois = make_pre_macro(((Class *)class)->otype,"IS");
174         macrotype = make_pre_macro(((Class *)class)->otype,"TYPE");
175
176         typebase = remove_sep(((Class *)class)->otype);
177
178         ptypebase = remove_sep(((Class *)class)->ptype);
179 }
180
181 static void
182 print_type(FILE *fp, Type *t)
183 {
184         char *s;
185         int i;
186         s = remove_sep(t->name);
187         out_printf(fp,"%s ",s); 
188         g_free(s);
189         
190         for(i=0;i<t->stars;i++)
191                 out_printf(fp,"*"); 
192 }
193
194 static void
195 print_method(FILE *fp, char *typeprefix, char *nameprefix,
196              char *namepostfix,char *postfix, Method *m,
197              gboolean no_funcbase)
198 {
199         GList *li;
200
201         out_printf(fp,"%s",typeprefix); 
202         print_type(fp,m->mtype);
203         if(no_funcbase)
204                 out_printf(fp,"%s%s%s(",
205                            nameprefix,m->id,namepostfix); 
206         else
207                 out_printf(fp,"%s%s_%s%s(",
208                            nameprefix,funcbase,m->id,namepostfix); 
209         
210         if(m->args) {
211                 for(li=m->args;li;li=g_list_next(li)) {
212                         FuncArg *arg = li->data;
213                         print_type(fp,arg->atype);
214                         if(li->next)
215                                 out_printf(fp,"%s, ",arg->name); 
216                         else
217                                 out_printf(fp,"%s",arg->name); 
218
219                 }
220                 if(m->vararg)
221                         out_printf(fp,", ..."); 
222         } else {
223                 out_printf(fp,"void"); 
224         }
225         out_printf(fp,")%s",postfix); 
226 }
227
228
229 static void
230 make_method_pointers(Class *c)
231 {
232         GList *li;
233         
234         out_printf(out,"\n");
235         for(li=c->nodes;li;li=g_list_next(li)) {
236                 Node *node = li->data;
237                 if(node->type == METHOD_NODE) {
238                         Method *m = (Method *)node;
239                         
240                         if(m->scope == INIT_METHOD ||
241                            m->scope == CLASS_INIT_METHOD ||
242                            m->scope == OVERRIDE_METHOD)
243                                 continue;
244
245                         /* in C++ mode don't alias new */
246                         if(for_cpp && strcmp(m->id,"new")==0)
247                                 continue;
248
249                         print_method(out,"static ","(* ",") ","",m,TRUE);
250                         out_printf(out," = %s_%s;\n",funcbase,m->id);
251                 }
252         }
253         out_printf(out,"\n");
254 }
255
256 static void
257 add_bad_hack_to_avoid_unused_warnings(Class *c)
258 {
259         GList *li;
260         
261         out_printf(out,"\n\n/*REALLY BAD HACK\n"
262                    "  This is to avoid unused warnings if you don't call\n"
263                    "  some method, it pollutes the namespace but the call\n"
264                    "  is weird enough.  I need to find a better way to do\n"
265                    "  this */\n");
266         out_printf(out,"void __%s_really_bad_hack_to_avoid_warnings(void);\n",
267                    funcbase);
268         out_printf(out,"void\n__%s_really_bad_hack_to_avoid_warnings(void)\n"
269                    "{\n",funcbase);
270         for(li=c->nodes;li;li=g_list_next(li)) {
271                 Node *node = li->data;
272                 if(node->type == METHOD_NODE) {
273                         Method *m = (Method *)node;
274                         
275                         if(m->scope == INIT_METHOD ||
276                            m->scope == CLASS_INIT_METHOD ||
277                            m->scope == OVERRIDE_METHOD)
278                                 continue;
279
280                         /* in C++ mode we don't alias new */
281                         if(for_cpp && strcmp(m->id,"new")==0)
282                                 continue;
283
284                         out_printf(out,"\t((void (*)(void))%s)();\n",m->id);
285                 }
286         }
287         out_printf(out,"}\n\n");
288 }
289
290 static void
291 put_variable(Variable *v)
292 {
293         out_printf(outh,"\t");
294         if(v->scope == PRIVATE_SCOPE)
295                 out_printf(outh,"/* private */ "); 
296         print_type(outh,v->vtype);
297
298         out_printf(outh,"%s;\n",v->id); 
299 }
300
301 static void
302 put_vs_method(Method *m)
303 {
304         if(m->scope != SIGNAL_LAST_METHOD &&
305            m->scope != SIGNAL_FIRST_METHOD &&
306            m->scope != PRIVATE_SIGNAL_LAST_METHOD &&
307            m->scope != PRIVATE_SIGNAL_FIRST_METHOD &&
308            m->scope != VIRTUAL_METHOD &&
309            m->scope != PRIVATE_VIRTUAL_METHOD)
310                 return;
311
312         print_method(outh,"\t","(* ",") ",";\n",m,TRUE);
313 }
314
315 static void
316 put_pub_method(Method *m)
317 {
318         if(m->scope == PRIVATE_SCOPE ||
319            m->scope == OVERRIDE_METHOD ||
320            m->scope == INIT_METHOD ||
321            m->scope == CLASS_INIT_METHOD ||
322            m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
323            m->scope == PRIVATE_SIGNAL_FIRST_METHOD ||
324            m->scope == PRIVATE_VIRTUAL_METHOD)
325                 return;
326
327         print_method(outh,"","\t","\t",";\n",m,FALSE);
328 }
329
330 static void
331 put_priv_method_prot(Method *m)
332 {
333         if(m->scope == PUBLIC_SCOPE)
334                 return;
335
336         if(m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
337            m->scope == PRIVATE_SIGNAL_FIRST_METHOD ||
338            m->scope == PRIVATE_VIRTUAL_METHOD) {
339                 if(m->cbuf)
340                         print_method(out,"static ","_real_"," ",";\n",m,FALSE);
341                 print_method(out,"static ",""," ",";\n",m,FALSE);
342         } else if(m->scope == SIGNAL_LAST_METHOD ||
343                   m->scope == SIGNAL_FIRST_METHOD ||
344                   m->scope == VIRTUAL_METHOD) {
345                 if(!m->cbuf)
346                         return;
347                 print_method(out,"static ","_real_"," ",";\n",m,FALSE);
348         } else {
349                 print_method(out,"static ",""," ",";\n",m,FALSE);
350         }
351 }
352
353 static GList *
354 make_init_args(Class *cl, char *name, int is_class)
355 {
356         Node *node;
357         Node *type;
358         char *tn;
359         
360         if(is_class)
361                 tn = g_strconcat(cl->otype,":Class",NULL);
362         else
363                 tn = g_strdup(cl->otype);
364
365         type = new_type(1,tn);
366         node = new_funcarg((Type *)type,name,NULL);
367         return g_list_prepend(NULL, node);
368 }
369
370 static void
371 make_inits(Class *cl)
372 {
373         int got_class_init = FALSE;
374         int got_init = FALSE;
375         GList *li;
376         Node *node;
377         for(li=cl->nodes;li;li=g_list_next(li)) {
378                 Node *n = li->data;
379                 if(n->type == METHOD_NODE) {
380                         Method *m = (Method *)n;
381                         if(m->scope == INIT_METHOD) {
382                                 if(got_init)
383                                         print_error(FALSE,"init defined more then once",m->line_no);
384                                 got_init = TRUE;
385                         } else if(m->scope == CLASS_INIT_METHOD) {
386                                 if(got_class_init)
387                                         print_error(FALSE,"class_init defined more then once",m->line_no);
388                                 got_class_init = TRUE;
389                         }
390                 }
391         }
392         if(!got_class_init) {
393                 node = new_method(CLASS_INIT_METHOD,
394                                   (Type *)new_type(0,g_strdup("void")),
395                                   NULL,NULL,g_strdup("class_init"),
396                                   make_init_args(cl,g_strdup("c"),TRUE),
397                                   NULL, NULL,0,0,FALSE);
398                 cl->nodes = g_list_prepend(cl->nodes,node);
399         }
400         if(!got_init) {
401                 node = new_method(INIT_METHOD,
402                                   (Type *)new_type(0,g_strdup("void")),
403                                   NULL,NULL,g_strdup("init"),
404                                   make_init_args(cl,g_strdup("o"),FALSE),
405                                   NULL, NULL,0,0,FALSE);
406                 cl->nodes = g_list_prepend(cl->nodes,node);
407         }
408 }
409
410 static GHashTable *marsh = NULL;
411
412 static void
413 add_signal_prots(Method *m)
414 {
415         GList *li;
416         static int sig = 1;
417         char *s;
418         
419         if(m->scope != SIGNAL_LAST_METHOD &&
420            m->scope != SIGNAL_FIRST_METHOD &&
421            m->scope != PRIVATE_SIGNAL_LAST_METHOD &&
422            m->scope != PRIVATE_SIGNAL_FIRST_METHOD)
423                 return;
424
425         if(!marsh)
426                 marsh = g_hash_table_new(NULL,NULL);
427         
428         if(strcmp(m->gtktypes->data,"NONE")==0 &&
429            strcmp(m->gtktypes->next->data,"NONE")==0)
430                 return;
431         
432         s = g_strdup_printf("__Sig%d",sig++);
433         
434         g_hash_table_insert(marsh,m,s);
435         
436         out_printf(out,"\ntypedef ");
437         print_type(out,m->mtype);
438         
439         out_printf(out,"(*%s) (",s);
440         
441         for(li=m->args;li;li=g_list_next(li)) {
442                 FuncArg *arg = li->data;
443                 print_type(out,arg->atype);
444                 out_printf(out,", "); 
445         }
446         out_printf(out,"gpointer);\n"); 
447         
448         out_printf(out,"\nstatic void\n"
449                 "marshal_%s (GtkObject * object,\n"
450                 "\tGtkSignalFunc func,\n"
451                 "\tgpointer func_data,\n"
452                 "\tGtkArg * args)\n"
453                 "{\n",s);
454         
455         if(strcmp(m->gtktypes->data,"NONE")==0) {
456                 int i;
457                 out_printf(out, "\t%s rfunc;\n\n"
458                         "\trfunc = (%s)func;\n\n"
459                         "\t(*rfunc)((%s *)object",s,s,typebase);
460                 if(strcmp(m->gtktypes->next->data,"NONE")!=0) {
461                         GList *ali = m->args->next;
462                         for(i=0,li=m->gtktypes->next;li;
463                             i++,li=g_list_next(li)) {
464                                 if(!for_cpp || !ali)
465                                         out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
466                                                    (char *)li->data,i);
467                                 else {
468                                         FuncArg *fa = ali->data;
469                                         out_printf(out, ",\n\t\t(");
470                                         print_type(out,fa->atype);
471                                         out_printf(out, ")GTK_VALUE_%s(args[%d])",
472                                                    (char *)li->data,i);
473                                 }
474
475                                 if(ali) ali = ali->next;
476                         }
477                 }
478                 out_printf(out, ",\n\t\tfunc_data);\n}\n\n");
479         } else {
480                 int i;
481                 out_printf(out, "\t%s rfunc;\n\t",s);
482                 print_type(out,m->mtype);
483                 out_printf(out, " *retval;\n\n"
484                         "\trfunc = (%s)func;\n\n"
485                         "\tretval = GTK_RETLOC_%s(args[%d]);\n\n"
486                         "\t*retval = (*rfunc)((%s *)object",
487                         s,(char *)m->gtktypes->data,
488                         g_list_length(m->gtktypes)-1,typebase);
489                 if(strcmp(m->gtktypes->next->data,"NONE")!=0) {
490                         GList *ali = m->args->next;
491                         for(i=0,li=m->gtktypes->next;li;
492                             i++,li=g_list_next(li)) {
493                                 if(!for_cpp || !ali)
494                                         out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
495                                                    (char *)li->data,i);
496                                 else {
497                                         FuncArg *fa = ali->data;
498                                         out_printf(out, ",\n\t\t(");
499                                         print_type(out,fa->atype);
500                                         out_printf(out, ")GTK_VALUE_%s(args[%d])",
501                                                    (char *)li->data,i);
502                                 }
503
504                                 if(ali) ali = ali->next;
505                         }
506                 }
507                 out_printf(out, ",\n\t\tfunc_data);\n}\n\n");
508         }
509
510 }
511
512 static void
513 add_enums(Class *c)
514 {
515         GList *li;
516         out_printf(out,"\n");
517         if(signals>0) {
518                 out_printf(out,"enum {\n");
519                 for(li=c->nodes;li;li=g_list_next(li)) {
520                         Node *n = li->data;
521                         if(n->type == METHOD_NODE) {
522                                 Method *m = (Method *)n;
523                                 if(m->scope == SIGNAL_LAST_METHOD ||
524                                    m->scope == SIGNAL_FIRST_METHOD ||
525                                    m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
526                                    m->scope == PRIVATE_SIGNAL_FIRST_METHOD) {
527                                         char *s = g_strdup(m->id);
528                                         g_strup(s);
529                                         out_printf(out,"\t%s_SIGNAL,\n",s);
530                                         g_free(s);
531                                 }
532                         }
533                 }
534                 out_printf(out,"\tLAST_SIGNAL\n};\n\n");
535         }
536         if(arguments>0) {
537                 out_printf(out,"enum {\n\tARG_0,\n");
538                 for(li=c->nodes;li;li=g_list_next(li)) {
539                         Node *n = li->data;
540                         if(n->type == ARGUMENT_NODE) {
541                                 Argument *a = (Argument *)n;
542                                 char *s = g_strdup(a->name);
543                                 g_strup(s);
544                                 out_printf(out,"\tARG_%s,\n",s);
545                                 g_free(s);
546                         }
547                 }
548                 out_printf(out, "};\n\n");
549         }
550
551         if(signals>0)
552                 out_printf(out,
553                            "static guint object_signals[LAST_SIGNAL] = {0};\n\n");
554
555         out_printf(out, "static %sClass *parent_class = NULL;\n\n",ptypebase);
556 }
557
558 static void
559 add_get_type(void)
560 {
561         out_printf(out, "guint\n"
562                 "%s_get_type (void)\n"
563                 "{\n"
564                 "\tstatic guint type = 0;\n\n"
565                 "\tif (!type) {\n"
566                 "\t\tstatic const GtkTypeInfo info = {\n"
567                 "\t\t\t\"%s\",\n"
568                 "\t\t\tsizeof (%s),\n"
569                 "\t\t\tsizeof (%sClass),\n"
570                 "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
571                 "\t\t\t(GtkObjectInitFunc) %s_init,\n"
572                 "\t\t\t/* reserved_1 */ NULL,\n"
573                 "\t\t\t/* reserved_2 */ NULL,\n"
574                 "\t\t\t(GtkClassInitFunc) NULL,\n"
575                 "\t\t};\n\n"
576                 "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n"
577                 "\t}\n\n"
578                 "\treturn type;\n"
579                 "}\n\n",
580                 funcbase,typebase,typebase,typebase,
581                 funcbase,funcbase,pfuncbase);
582 }
583
584 static void
585 add_overrides(Class *c, char *oname, gboolean did_gtk_obj)
586 {
587         GList *li;
588         GHashTable *done;
589         char *s;
590         
591         done = g_hash_table_new(g_str_hash,g_str_equal);
592         if(did_gtk_obj) {
593                 s = g_strdup("GtkObject"); /* This was already done */
594                 g_hash_table_insert(done,s,s);
595         }
596         for(li=c->nodes;li;li=g_list_next(li)) {
597                 Node *n = li->data;
598                 char *f;
599                 Method *m;
600                 if(n->type != METHOD_NODE ||
601                    ((Method *)n)->scope != OVERRIDE_METHOD)
602                         continue;
603                 m = (Method *)n;
604                 
605                 s = remove_sep(m->otype);
606                 
607                 if(g_hash_table_lookup(done,s)) {
608                         g_free(s);
609                         continue;
610                 }
611                 g_hash_table_insert(done,s,s);
612
613                 f = replace_sep(m->otype,'_');
614                 g_strdown(f);
615
616                 out_printf(out,"\t%sClass *%s_class = (%sClass *)%s;\n",
617                         s,f,s,oname);
618                 
619                 g_free(f);
620         }
621         g_hash_table_foreach(done,(GHFunc)g_free,NULL);
622         g_hash_table_destroy(done);
623 }
624
625 static void
626 add_signals(Class *c)
627 {
628         GList *li;
629
630         out_printf(out,"\n");
631         for(li=c->nodes;li;li=g_list_next(li)) {
632                 Node *n = li->data;
633                 Method *m;
634                 char *mar;
635                 char *sig;
636                 int is_none;
637                 int last = FALSE;
638                 if(n->type != METHOD_NODE ||
639                    (((Method *)n)->scope != SIGNAL_FIRST_METHOD &&
640                     ((Method *)n)->scope != SIGNAL_LAST_METHOD &&
641                     ((Method *)n)->scope != PRIVATE_SIGNAL_FIRST_METHOD &&
642                     ((Method *)n)->scope != PRIVATE_SIGNAL_LAST_METHOD))
643                         continue;
644
645                 m = (Method *)n;
646                 
647                 if(m->scope == SIGNAL_FIRST_METHOD ||
648                    m->scope == PRIVATE_SIGNAL_FIRST_METHOD)
649                         last = FALSE;
650                 else
651                         last = TRUE;
652
653                 if(g_hash_table_lookup(marsh,m))
654                         mar = g_strconcat("marshal_",
655                                           (char *)g_hash_table_lookup(marsh,m),
656                                           NULL);
657                 else
658                         mar = g_strdup("gtk_signal_default_marshaller");
659                 
660                 is_none = (strcmp(m->gtktypes->next->data,"NONE")==0);
661                 
662                 sig = g_strdup(m->id);
663                 g_strup(sig);
664                 out_printf(out,"\tobject_signals[%s_SIGNAL] =\n"
665                         "\t\tgtk_signal_new (\"%s\",\n"
666                         "\t\t\tGTK_RUN_%s,\n"
667                         "\t\t\tgtk_object_class->type,\n"
668                         "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n"
669                         "\t\t\t%s,\n"
670                         "\t\t\tGTK_TYPE_%s, %d",
671                         sig,m->id,
672                         last?"LAST":"FIRST",
673                         typebase,m->id,mar,(char *)m->gtktypes->data,
674                         is_none?0:g_list_length(m->gtktypes->next));
675                 g_free(mar);
676                 g_free(sig);
677                 
678                 if(!is_none) {
679                         GList *l;
680                         for(l=m->gtktypes->next;l;l=g_list_next(l))
681                                 out_printf(out,",\n\t\t\tGTK_TYPE_%s",
682                                         (char *)l->data);
683                 }
684
685                 out_printf(out,");\n");
686         }
687         out_printf(out,"\tgtk_object_class_add_signals (gtk_object_class,\n"
688                 "\t\tobject_signals, LAST_SIGNAL);\n\n");
689 }
690
691 static void
692 set_def_handlers(Class *c, char *oname)
693 {
694         GList *li;
695
696         out_printf(out,"\n");
697         for(li=c->nodes;li;li=g_list_next(li)) {
698                 Node *n = li->data;
699                 Method *m;
700                 if(n->type != METHOD_NODE ||
701                    (((Method *)n)->scope != SIGNAL_FIRST_METHOD &&
702                     ((Method *)n)->scope != SIGNAL_LAST_METHOD &&
703                     ((Method *)n)->scope != PRIVATE_SIGNAL_FIRST_METHOD &&
704                     ((Method *)n)->scope != PRIVATE_SIGNAL_LAST_METHOD &&
705                     ((Method *)n)->scope != VIRTUAL_METHOD &&
706                     ((Method *)n)->scope != PRIVATE_VIRTUAL_METHOD &&
707                     ((Method *)n)->scope != OVERRIDE_METHOD))
708                         continue;
709
710                 m = (Method *)n;
711
712                 if(m->scope == OVERRIDE_METHOD) {
713                         char *s;
714                         s = replace_sep(m->otype,'_');
715                         g_strdown(s);
716                         out_printf(out,"\t%s_class->%s = %s_%s;\n",
717                                 s,m->id,funcbase,m->id);
718                 } else {
719                         if(m->cbuf)
720                                 out_printf(out,"\t%s->%s = _real_%s_%s;\n",
721                                         oname,m->id,funcbase,m->id);
722                         else
723                                 out_printf(out,"\t%s->%s = NULL;\n",
724                                         oname,m->id);
725                 }
726         }
727 }
728
729 static void
730 make_arguments(Class *c)
731 {
732         GList *li;
733
734         out_printf(out,"\n");
735         for(li=c->nodes;li;li=g_list_next(li)) {
736                 Node *n = li->data;
737                 Argument *a;
738                 GString *flags;
739                 GList *l;
740                 char *s;
741                 if(n->type != ARGUMENT_NODE)
742                         continue;
743
744                 a = (Argument *)n;
745                 
746                 if(a->get && a->set)
747                         flags = g_string_new("GTK_ARG_READWRITE");
748                 else if(a->get)
749                         flags = g_string_new("GTK_ARG_READABLE");
750                 else
751                         flags = g_string_new("GTK_ARG_WRITABLE");
752                 
753                 for(l=a->flags;l;l=g_list_next(l))
754                         g_string_sprintfa(flags," | GTK_ARG_%s",(char *)l->data);
755
756                 s = g_strdup(a->name);
757                 g_strup(s);
758                 out_printf(out,"\tgtk_object_add_arg_type(\"%s::%s\",\n"
759                         "\t\tGTK_TYPE_%s,\n"
760                         "\t\t%s,\n"
761                         "\t\tARG_%s);\n",
762                         typebase,a->name,a->gtktype,flags->str,s);
763                 g_free(s);
764                 g_string_free(flags,TRUE);
765         }
766         
767         out_printf(out,
768                    "\n\tgtk_object_class->set_arg = __object_set_arg;\n"
769                    "\tgtk_object_class->get_arg = __object_get_arg;\n");
770 }
771
772 static void
773 add_inits(Class *c)
774 {
775         GList *li;
776         for(li=c->nodes;li;li=g_list_next(li)) {
777                 Node *n = li->data;
778                 Method *m;
779                 if(n->type != METHOD_NODE)
780                         continue;
781                 m = (Method *)n;
782                 if(m->scope == INIT_METHOD) {
783                         if(m->line_no>0)
784                                 out_addline_infile(out,m->line_no);
785                         print_method(out,"static ","\n"," ","\n",m,FALSE);
786                         if(m->line_no>0)
787                                 out_addline_outfile(out);
788                         out_printf(out,"{\n");
789                 } else if(m->scope == CLASS_INIT_METHOD) {
790                         if(m->line_no>0)
791                                 out_addline_infile(out,m->line_no);
792                         print_method(out,"static ","\n"," ","\n",m,FALSE);
793                         if(m->line_no>0)
794                                 out_addline_outfile(out);
795                         out_printf(out,"{\n");
796                         if(signals>0 ||
797                            arguments>0)
798                                 out_printf(out,
799                                            "\tGtkObjectClass *"
800                                            "gtk_object_class = "
801                                            "(GtkObjectClass*) %s;\n",
802                                            ((FuncArg *)m->args->data)->name);
803
804                         if(overrides>0)
805                                 add_overrides(c,
806                                               ((FuncArg *)m->args->data)->name,
807                                               (signals>0 || arguments>0));
808                         
809                         out_printf(out,"\n\tparent_class = ");
810                         if(for_cpp)
811                                 out_printf(out,"(%sClass *)",ptypebase);
812                         out_printf(out,"gtk_type_class (%s_get_type ());\n",
813                                    pfuncbase);
814
815                         if(signals>0)
816                                 add_signals(c);
817
818                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
819                         
820                         if(arguments>0)
821                                 make_arguments(c);
822
823                 } else
824                         continue;
825
826                 if(m->cbuf) {
827                         out_printf(out," {\n");
828                         out_addline_infile(out,m->ccode_line);
829                         out_printf(out,"%s\n",m->cbuf->str);
830                         out_addline_outfile(out);
831                         out_printf(out," }\n",m->cbuf->str);
832                 } else {
833                         out_printf(out,"return;\n");
834                 }
835                 out_printf(out,"}\n");
836         }
837 }
838
839 static void
840 add_getset_arg(Class *c, int is_set)
841 {
842         GList *li;
843         out_printf(out,"\nstatic void\n"
844                 "__object_%s_arg (GtkObject *object,\n"
845                 "\tGtkArg *arg,\n"
846                 "\tguint arg_id)\n"
847                 "{\n"
848                 "\t%s *self;\n\n"
849                 "\tself = %s (object);\n\n"
850                 "\tswitch (arg_id) {\n",
851                 is_set?"set":"get",typebase,macrobase);
852
853         for(li=c->nodes;li;li=g_list_next(li)) {
854                 Node *n = li->data;
855                 Argument *a;
856                 char *s;
857                 GString *cbuf;
858                 int line_no;
859                 if(n->type != ARGUMENT_NODE)
860                         continue;
861                 a = (Argument *)n;
862                 if(is_set) {
863                         cbuf = a->set;
864                         line_no = a->set_line;
865                 } else {
866                         cbuf = a->get;
867                         line_no = a->get_line;
868                 }
869                 if(!cbuf)
870                         continue;
871                 s = g_strdup(a->name);
872                 g_strup(s);
873                 out_printf(out,"\tcase ARG_%s:\n"
874                         "#define ARG (GTK_VALUE_%s(*arg))\n"
875                         "\t\t{\n",
876                         s,a->gtktype);
877                 g_free(s);
878                 out_addline_infile(out,line_no);
879                 out_printf(out,"%s\n",cbuf->str);
880                 out_addline_outfile(out);
881                 out_printf(out,"\t\t}\n\t\tbreak;\n"
882                         "#undef ARG\n");
883         }
884         out_printf(out,"\tdefault:\n\t\tbreak;\n\t}\n}\n");
885 }
886
887 static void
888 print_checks(Method *m, FuncArg *fa)
889 {
890         GList *li;
891         int is_void;
892         is_void = (strcmp(m->mtype->name,"void")==0 &&
893                    m->mtype->stars == 0);
894         
895         for(li=fa->checks;li;li=g_list_next(li)) {
896                 Check *ch = li->data;
897                 char *s;
898                 if(is_void)
899                         out_printf(out,"\tg_return_if_fail (");
900                 else
901                         out_printf(out,"\tg_return_val_if_fail (");
902                 switch(ch->chtype) {
903                 case NULL_CHECK:
904                         out_printf(out,"%s != NULL",fa->name);
905                         break;
906                 case TYPE_CHECK:
907                         s = make_pre_macro(fa->atype->name,"IS");
908                         out_printf(out,"%s (%s)",s,fa->name);
909                         g_free(s);
910                         break;
911                 case LT_CHECK:
912                         out_printf(out,"%s < %s",fa->name,ch->number);
913                         break;
914                 case GT_CHECK:
915                         out_printf(out,"%s > %s",fa->name,ch->number);
916                         break;
917                 case LE_CHECK:
918                         out_printf(out,"%s <= %s",fa->name,ch->number);
919                         break;
920                 case GE_CHECK:
921                         out_printf(out,"%s >= %s",fa->name,ch->number);
922                         break;
923                 case EQ_CHECK:
924                         out_printf(out,"%s == %s",fa->name,ch->number);
925                         break;
926                 case NE_CHECK:
927                         out_printf(out,"%s != %s",fa->name,ch->number);
928                         break;
929                 }
930                 if(is_void)
931                         out_printf(out,");\n");
932                 else {
933                         out_printf(out,", (");
934                         print_type(out,m->mtype);
935                         out_printf(out,")%s);\n",
936                                 m->onerror?m->onerror:"0");
937                 }
938         }
939 }
940
941 static void
942 print_preconditions(Method *m)
943 {
944         GList *li;
945         
946         for(li=m->args;li;li=g_list_next(li)) {
947                 FuncArg *fa = li->data;
948                 if(fa->checks)
949                         print_checks(m,fa);
950         }
951 }
952
953 static void
954 print_method_body(Method *m, int pre)
955 {
956         out_printf(out,"{\n");
957         if(pre) {
958                 print_preconditions(m);
959                 out_printf(out,"\t{\n");
960         }
961
962         out_addline_infile(out,m->ccode_line);
963         out_printf(out,"\t\t%s\n",m->cbuf->str);
964         out_addline_outfile(out);
965
966         if(pre)
967                 out_printf(out,"\t}\n");
968         out_printf(out,"}\n");
969 }
970
971 static void
972 put_method(Method *m)
973 {
974         char *s;
975         int private = FALSE;
976         out_printf(out,"\n");
977         switch(m->scope) {
978         case PUBLIC_SCOPE:
979                 out_addline_infile(out,m->line_no);
980                 print_method(out,"","\n"," ","\n",m,FALSE);
981                 print_method_body(m,TRUE);
982                 break;
983         case PRIVATE_SCOPE:
984                 out_addline_infile(out,m->line_no);
985                 print_method(out,"static ","\n"," ","\n",m,FALSE);
986                 print_method_body(m,TRUE);
987                 break;
988         case PRIVATE_SIGNAL_FIRST_METHOD:
989         case PRIVATE_SIGNAL_LAST_METHOD:
990                 private = TRUE;
991         case SIGNAL_FIRST_METHOD:
992         case SIGNAL_LAST_METHOD:
993                 out_addline_infile(out,m->line_no);
994                 print_method(out,private?"static ":"","\n"," ","\n",m,FALSE);
995                 out_addline_outfile(out);
996                 out_printf(out,"{\n");
997                 s = g_strdup(m->id);
998                 g_strup(s);
999                 if(strcmp(m->mtype->name,"void")==0 &&
1000                    m->mtype->stars==0) {
1001                         GList *li;
1002                         print_preconditions(m);
1003                         if(((FuncArg *)m->args->data)->name)
1004                         out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1005                                 "\t\tobject_signals[%s_SIGNAL]",
1006                                 ((FuncArg *)m->args->data)->name,s);
1007                         for(li=m->args->next;li;li=g_list_next(li)) {
1008                                 FuncArg *fa = li->data;
1009                                 out_printf(out,",\n\t\t%s",fa->name);
1010                         }
1011                         out_printf(out,");\n}\n");
1012                 } else {
1013                         GList *li;
1014                         out_printf(out,"\t");
1015                         print_type(out,m->mtype);
1016                         out_printf(out,"return_val;\n");
1017                         print_preconditions(m);
1018                         out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1019                                 "\t\tobject_signals[%s_SIGNAL]",
1020                                 ((FuncArg *)m->args->data)->name,s);
1021                         for(li=m->args->next;li;li=g_list_next(li)) {
1022                                 FuncArg *fa = li->data;
1023                                 out_printf(out,",\n\t\t%s",fa->name);
1024                         }
1025                         out_printf(out,",\n\t\t&return_val);\n"
1026                                 "\treturn return_val;\n}\n");
1027                 }
1028
1029                 if(!m->cbuf)
1030                         break;
1031                 out_addline_infile(out,m->line_no);
1032                 print_method(out,"static ","\n_real_"," ","\n",m,FALSE);
1033                 print_method_body(m,FALSE);
1034                 break;
1035         case PRIVATE_VIRTUAL_METHOD:
1036                 private = TRUE;
1037         case VIRTUAL_METHOD:
1038                 out_addline_infile(out,m->line_no);
1039                 print_method(out,private?"static ":"","\n"," ","\n",m,FALSE);
1040                 out_addline_outfile(out);
1041                 out_printf(out,"{\n"
1042                         "\t%sClass *klass;\n",typebase);
1043                 print_preconditions(m);
1044                 out_printf(out,"\tklass = %s_CLASS(GTK_OBJECT(%s)->klass);\n\n"
1045                         "\tif(klass->%s)\n",
1046                         macrobase, ((FuncArg *)m->args->data)->name, m->id);
1047                 if(strcmp(m->mtype->name,"void")==0 &&
1048                    m->mtype->stars==0) {
1049                         GList *li;
1050                         out_printf(out,"\t\t(*klass->%s)(%s",m->id,
1051                                    ((FuncArg *)m->args->data)->name);
1052                         for(li=m->args->next;li;li=g_list_next(li)) {
1053                                 FuncArg *fa = li->data;
1054                                 out_printf(out,",%s",fa->name);
1055                         }
1056                         out_printf(out,");\n}\n");
1057                 } else {
1058                         GList *li;
1059                         out_printf(out,"\t\treturn (*klass->%s)(%s",m->id,
1060                                    ((FuncArg *)m->args->data)->name);
1061                         for(li=m->args->next;li;li=g_list_next(li)) {
1062                                 FuncArg *fa = li->data;
1063                                 out_printf(out,",%s",fa->name);
1064                         }
1065                         out_printf(out,");\n"
1066                                 "\telse\n"
1067                                 "\t\treturn (");
1068                         print_type(out,m->mtype);
1069                         out_printf(out,")(%s);\n}\n",
1070                                 m->onerror?m->onerror:"0");
1071                 }
1072
1073                 if(!m->cbuf)
1074                         break;
1075                 out_addline_infile(out,m->line_no);
1076                 print_method(out,"static ","\n_real_"," ","\n",m,FALSE);
1077                 print_method_body(m,FALSE);
1078                 break;
1079         case OVERRIDE_METHOD:
1080                 out_addline_infile(out,m->line_no);
1081                 print_method(out,"static ","\n"," ","\n",m,FALSE);
1082                 s = replace_sep(m->otype,'_');
1083                 g_strup(s);
1084                 out_printf(out,"#define PARENT_HANDLER(args...) \\\n"
1085                            "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
1086                            "\t\t(* %s_CLASS(parent_class)->%s)(##args); }\n",
1087                            s,m->id,s,m->id);
1088                 g_free(s);
1089                 print_method_body(m,TRUE);
1090                 out_printf(out,"#undef PARENT_HANDLER\n");
1091                 break;
1092         default:
1093                 break;
1094         }
1095 }
1096
1097 static void
1098 check_duplicate(Class *c,Node *node,char *id, int line_no)
1099 {
1100         GList *l;
1101         for(l=c->nodes;l;l=g_list_next(l)) {
1102                 Node *n = l->data;
1103                 char *nid;
1104                 int nline_no;
1105                 char *s;
1106                 if(n->type == METHOD_NODE) {
1107                         Method *m = (Method *)n;
1108                         nid = m->id;
1109                         nline_no = m->line_no;
1110                 } else if(n->type == VARIABLE_NODE) {
1111                         Variable *v = (Variable *)n;
1112                         nid = v->id;
1113                         nline_no = v->line_no;
1114                 } else
1115                         continue;
1116                 if(n==node ||
1117                    line_no>=nline_no ||
1118                    strcmp(nid,id)!=0 ||
1119                    n->type != node->type)
1120                         continue;
1121                 s = g_strdup_printf("symbol '%s' redefined, "
1122                                     "first defined on line %d",
1123                                     id,line_no);
1124                 print_error(FALSE,s,nline_no);
1125         }
1126 }
1127
1128 static void
1129 check_duplicate_symbols(Class *c)
1130 {
1131         GList *l;
1132         for(l=c->nodes;l;l=g_list_next(l)) {
1133                 Node *n = l->data;
1134                 if(n->type == METHOD_NODE) {
1135                         Method *m = (Method *)n;
1136                         check_duplicate(c,n,m->id,m->line_no);
1137                 } else if(n->type == VARIABLE_NODE) {
1138                         Variable *v = (Variable *)n;
1139                         check_duplicate(c,n,v->id,v->line_no);
1140                 }
1141         }
1142 }
1143
1144 static void
1145 check_duplicate_named(Class *c,Node *node,char *id, int line_no)
1146 {
1147         GList *l;
1148         for(l=c->nodes;l;l=g_list_next(l)) {
1149                 Node *n = l->data;
1150                 char *nid;
1151                 int nline_no;
1152                 char *s;
1153                 if(n->type == METHOD_NODE) {
1154                         Method *m = (Method *)n;
1155                         if(m->scope == SIGNAL_LAST_METHOD ||
1156                            m->scope == SIGNAL_FIRST_METHOD ||
1157                            m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1158                            m->scope == PRIVATE_SIGNAL_FIRST_METHOD) {
1159                                 nid = m->id;
1160                                 nline_no = m->line_no;
1161                         } else
1162                                 continue;
1163                 } else if(n->type == ARGUMENT_NODE) {
1164                         Argument *a = (Argument *)n;
1165                         nid = a->name;
1166                         nline_no = a->line_no;
1167                 } else
1168                         continue;
1169                 if(n==node ||
1170                    line_no>=nline_no ||
1171                    strcmp(nid,id)!=0)
1172                         continue;
1173                 s = g_strdup_printf("named symbol (argument or signal) '%s' "
1174                                     "redefined, first defined on line %d",
1175                                     id,line_no);
1176                 print_error(FALSE,s,nline_no);
1177         }
1178 }
1179
1180 static void
1181 check_duplicate_signals_args(Class *c)
1182 {
1183         GList *l;
1184         for(l=c->nodes;l;l=g_list_next(l)) {
1185                 Node *n = l->data;
1186                 if(n->type == METHOD_NODE) {
1187                         Method *m = (Method *)n;
1188                         if(m->scope == SIGNAL_LAST_METHOD ||
1189                            m->scope == SIGNAL_FIRST_METHOD ||
1190                            m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1191                            m->scope == PRIVATE_SIGNAL_FIRST_METHOD)
1192                                 check_duplicate_named(c,n,m->id,m->line_no);
1193                 } else if(n->type == ARGUMENT_NODE) {
1194                         Argument *a = (Argument *)n;
1195                         check_duplicate_named(c,n,a->name,a->line_no);
1196                 }
1197         }
1198 }
1199
1200 static void
1201 check_public_new(Class *c)
1202 {
1203         GList *l;
1204         for(l=c->nodes;l;l=g_list_next(l)) {
1205                 Node *n = l->data;
1206                 if(n->type == METHOD_NODE) {
1207                         Method *m = (Method *)n;
1208                         if(m->scope!=PUBLIC_SCOPE &&
1209                            strcmp(m->id,"new")==0)
1210                                 print_error(TRUE,
1211                                             "'new' should be a public method",
1212                                             m->line_no);
1213                 }
1214         }
1215 }
1216
1217 static void
1218 check_vararg(Class *c)
1219 {
1220         GList *l;
1221         for(l=c->nodes;l;l=g_list_next(l)) {
1222                 Node *n = l->data;
1223                 if(n->type == METHOD_NODE) {
1224                         Method *m = (Method *)n;
1225                         if(!m->vararg)
1226                                 continue;
1227                         if(m->scope == OVERRIDE_METHOD ||
1228                            m->scope == SIGNAL_LAST_METHOD ||
1229                            m->scope == SIGNAL_FIRST_METHOD ||
1230                            m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1231                            m->scope == PRIVATE_SIGNAL_FIRST_METHOD ||
1232                            m->scope == VIRTUAL_METHOD ||
1233                            m->scope == PRIVATE_VIRTUAL_METHOD) {
1234                                 print_error(FALSE,
1235                                             "signals, overrides and virtuals, "
1236                                             "can't have variable argument "
1237                                             "lists",
1238                                             m->line_no);
1239                         }
1240                 }
1241         }
1242 }
1243
1244 static int
1245 count_signals(Class *c)
1246 {
1247         int num = 0;
1248         GList *l;
1249         for(l=c->nodes;l;l=g_list_next(l)) {
1250                 Node *n = l->data;
1251                 if(n->type == METHOD_NODE) {
1252                         Method *m = (Method *)n;
1253                         if(m->scope == SIGNAL_LAST_METHOD ||
1254                            m->scope == SIGNAL_FIRST_METHOD ||
1255                            m->scope == PRIVATE_SIGNAL_LAST_METHOD ||
1256                            m->scope == PRIVATE_SIGNAL_FIRST_METHOD)
1257                                 num++;
1258                 }
1259         }
1260         return num;
1261 }
1262
1263 static int
1264 count_arguments(Class *c)
1265 {
1266         int num = 0;
1267         GList *li;
1268
1269         for(li=c->nodes;li;li=g_list_next(li)) {
1270                 Node *n = li->data;
1271                 if(n->type == ARGUMENT_NODE)
1272                         num ++;
1273         }
1274         return num;
1275 }
1276
1277 static int
1278 count_overrides(Class *c)
1279 {
1280         int num = 0;
1281         GList *l;
1282         for(l=c->nodes;l;l=g_list_next(l)) {
1283                 Node *n = l->data;
1284                 if(n->type == METHOD_NODE) {
1285                         Method *m = (Method *)n;
1286                         if(m->scope == OVERRIDE_METHOD)
1287                                 num++;
1288                 }
1289         }
1290         return num;
1291 }
1292
1293
1294 static void
1295 open_files(void)
1296 {
1297         char *outfile,*outfileh;
1298
1299         if(!for_cpp)
1300                 outfile = g_strconcat(filebase,".c",NULL);
1301         else
1302                 outfile = g_strconcat(filebase,".cc",NULL);
1303         if(no_touch_headers)
1304                 outfileh = g_strconcat("#gob#",filebase,".h#gob#",NULL);
1305         else
1306                 outfileh = g_strconcat(filebase,".h",NULL);
1307         
1308         out = fopen(outfile,"w");
1309         if(!out) {
1310                 g_error("Cannot open outfile: %s",outfile);
1311         }
1312         outh = fopen(outfileh,"w");
1313         if(!outh) {
1314                 g_error("Cannot open outfile: %s",outfileh);
1315         }
1316 }
1317
1318 static void
1319 generate_outfiles(void)
1320 {
1321         char *p;
1322         GList *li;
1323         time_t curtime;
1324
1325         time(&curtime);
1326         out_printf(outh,"/* Generated by GOB (v%s)"
1327                "   (do not edit directly) */\n\n",VERSION);
1328         out_printf(out,"/* Generated by GOB (v%s) on %s"
1329                "   (do not edit directly) */\n\n",VERSION,ctime(&curtime));
1330         
1331         p = replace_sep(((Class *)class)->otype,'_');
1332         g_strup(p);
1333         out_printf(outh,"#ifndef __%s_H__\n#define __%s_H__\n\n"
1334                 "#include <gtk/gtk.h>\n\n",p,p);
1335         g_free(p);
1336
1337         if(!for_cpp)
1338                 out_printf(outh,"#ifdef __cplusplus\n"
1339                            "extern \"C\" {\n"
1340                            "#endif /* __cplusplus */\n\n");
1341         
1342         out_printf(out,"#include \"%s.h\"\n\n",filebase);
1343         
1344         for(li=nodes;li;li=g_list_next(li)) {
1345                 Node *node = li->data;
1346                 if(node->type == CCODE_NODE) {
1347                         CCode *cc = (CCode *)node;
1348                         FILE *fp;
1349                         if(cc->header) {
1350                                 fp = outh;
1351                                 out_printf(fp,"\n");
1352                         } else {
1353                                 fp = out;
1354                                 out_printf(fp,"\n");
1355                                 out_addline_infile(fp,cc->line_no);
1356                         }
1357                         out_printf(fp,"%s\n",cc->cbuf->str);
1358                         if(!cc->header)
1359                                 out_addline_outfile(fp);
1360                 } else if(node->type == CLASS_NODE) {
1361                         GList *l;
1362                         Class *c = (Class *)class;
1363                         char *otype,*ptype;
1364
1365                         signals = count_signals(c);
1366                         arguments = count_arguments(c);
1367                         overrides = count_overrides(c);
1368
1369                         out_printf(outh,"\n#define %s\t"
1370                                 "(%s_get_type())\n",
1371                                 macrotype,funcbase);
1372                         out_printf(outh,"#define %s(obj)\t"
1373                                 "GTK_CHECK_CAST((obj),%s_get_type(),%s)\n",
1374                                 macrobase,funcbase,typebase);
1375                         out_printf(outh,"#define %s_CLASS(klass)\t"
1376                                 "GTK_CHECK_CLASS_CAST((klass),%s_get_type(),%sClass)\n",
1377                                 macrobase,funcbase,typebase);
1378                         out_printf(outh,"#define %s(obj)\t"
1379                                 "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
1380                                 macrois,funcbase);
1381
1382                         otype = remove_sep(c->otype);
1383                         ptype = remove_sep(c->ptype);
1384                         out_printf(outh,"\ntypedef struct _%s %s;\n",otype,otype);
1385                         out_printf(outh,"struct _%s {\n\t%s __parent__;\n",
1386                                    otype,ptype);
1387                         for(l=c->nodes;l;l=g_list_next(l)) {
1388                                 Node *n = l->data;
1389                                 if(n->type == VARIABLE_NODE)
1390                                         put_variable((Variable *)n);
1391                         }
1392                         out_printf(outh,"};\n");
1393
1394                         out_printf(outh,"\ntypedef struct _%sClass %sClass;\n",
1395                                 otype,otype);
1396                         out_printf(outh,
1397                                 "struct _%sClass {\n\t%sClass __parent__;\n",
1398                                 otype,ptype);
1399                         for(l=c->nodes;l;l=g_list_next(l)) {
1400                                 Node *n = l->data;
1401                                 if(n->type == METHOD_NODE)
1402                                         put_vs_method((Method *)n);
1403                         }
1404                         out_printf(outh,"};\n\n");
1405
1406                         out_printf(outh,"guint\t%s_get_type\t(void);\n",funcbase);
1407                         
1408                         if(arguments>0) {
1409                                 out_printf(out,"static void __object_set_arg "
1410                                            "(GtkObject *object, GtkArg *arg, "
1411                                            "guint arg_id);\n"
1412                                            "static void __object_get_arg "
1413                                            "(GtkObject *object, GtkArg *arg, "
1414                                            "guint arg_id);\n");
1415                         }
1416
1417                         for(l=c->nodes;l;l=g_list_next(l)) {
1418                                 Node *n = l->data;
1419                                 if(n->type == METHOD_NODE) {
1420                                         put_pub_method((Method *)n);
1421                                         put_priv_method_prot((Method *)n);
1422                                 }
1423                         }
1424
1425                         if(signals>0) {
1426                                 for(l=c->nodes;l;l=g_list_next(l)) {
1427                                         Node *n = l->data;
1428                                         if(n->type == METHOD_NODE) {
1429                                                 add_signal_prots((Method *)n);
1430                                         }
1431                                 }
1432                         }
1433                         
1434                         add_enums(c);
1435                         
1436                         add_get_type();
1437
1438                         make_method_pointers(c);
1439
1440                         out_printf(out,"#define GET_NEW (gtk_type_new(%s_get_type()))\n",
1441                                    funcbase);
1442
1443                         add_inits(c);
1444
1445                         if(arguments>0) {
1446                                 add_getset_arg(c, TRUE);
1447                                 add_getset_arg(c, FALSE);
1448                         }
1449
1450                         for(l=c->nodes;l;l=g_list_next(l)) {
1451                                 Node *n = l->data;
1452                                 if(n->type == METHOD_NODE) {
1453                                         put_method((Method *)n);
1454                                 }
1455                         }
1456
1457                         out_printf(out,"#undef GET_NEW\n");
1458
1459                         add_bad_hack_to_avoid_unused_warnings(c);
1460
1461                         g_free(otype);
1462                         g_free(ptype);
1463                 } else
1464                         g_assert_not_reached();
1465         }
1466
1467         if(!for_cpp)
1468                 out_printf(outh,"\n#ifdef __cplusplus\n"
1469                            "}\n"
1470                            "#endif /* __cplusplus */\n");
1471         out_printf(outh,"\n#endif");
1472 }
1473
1474 #if 0
1475 static void
1476 usage(poptContext optCon, int exitcode, char *error, char *addl)
1477 {
1478         poptPrintUsage(optCon, stderr, 0);
1479         if (error) fprintf(stderr, "%s: %s", error, addl);
1480         exit(exitcode);
1481 }
1482 #endif
1483
1484 static void
1485 print_help(void)
1486 {
1487         fprintf(stderr,"Gob version %s\n\n",VERSION);
1488         fprintf(stderr,"Options:\n"
1489                 "\t--help,-h,-?         Display this help\n"
1490                 "\t--exit-on-warn,-w    Exit with an error on warnings\n"
1491                 "\t--no-exit-on-warn    Don't exit on warnings [default]\n"
1492                 "\t--for-cpp            Create C++ files\n"
1493                 "\t--no-touch-headers   Don't touch headers unless they "
1494                                        "really changed\n");
1495 }
1496
1497 static void
1498 parse_options(int argc, char *argv[])
1499 {
1500         int i;
1501         int got_file = FALSE;
1502         int no_opts = FALSE;
1503
1504         filename = NULL;
1505
1506         for(i=1;i<argc;i++) {
1507                 if(no_opts || argv[i][0]!='-') {
1508                         /*must be a file*/
1509                         if(got_file) {
1510                                 fprintf(stderr,"Specify only one file!\n");
1511                                 print_help();
1512                                 exit(1);
1513                         }
1514                         filename = argv[i];
1515                         got_file = TRUE;
1516                 } else if(strcmp(argv[i],"--help")==0) {
1517                         print_help();
1518                         exit(0);
1519                 } else if(strcmp(argv[i],"--exit-on-warn")==0) {
1520                         exit_on_warn = TRUE;
1521                 } else if(strcmp(argv[i],"--no-exit-on-warn")==0) {
1522                         exit_on_warn = FALSE;
1523                 } else if(strcmp(argv[i],"--for-cpp")==0) {
1524                         for_cpp = TRUE;
1525                 } else if(strcmp(argv[i],"--no-touch-headers")==0) {
1526                         no_touch_headers = TRUE;
1527                 } else if(strcmp(argv[i],"--")==0) {
1528                         /*further arguments are files*/
1529                         no_opts = TRUE;
1530                 } else if(strncmp(argv[i],"--",2)==0) {
1531                         /*unknown long option*/
1532                         fprintf(stderr,"Unknown option '%s'!\n",argv[i]);
1533                         print_help();
1534                         exit(1);
1535                 } else {
1536                         /*by now we know we have a string starting with
1537                           - which is a short option string*/
1538                         char *p = argv[i]+1;
1539                         for(p=argv[i]+1;*p;p++) {
1540                                 switch(*p) {
1541                                 case 'w':
1542                                         exit_on_warn=TRUE;
1543                                         break;
1544                                 case 'h':
1545                                 case '?':
1546                                         print_help();
1547                                         exit(0);
1548                                 default:
1549                                         fprintf(stderr,
1550                                                 "Unknown option '%c'!\n",*p);
1551                                         print_help();
1552                                         exit(1);
1553                                 }
1554                         }
1555                 }
1556         }
1557 }
1558
1559 static void
1560 compare_and_move_header(void)
1561 {
1562         char *hfnew = g_strconcat("#gob#",filebase,".h#gob#",NULL);
1563         char *hf = g_strconcat(filebase,".h",NULL);
1564         struct stat s;
1565         if(stat(hf,&s)==0) {
1566                 char *s;
1567                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null",hf,hfnew);
1568                 if(system(s)==0) {
1569                         if(unlink(hfnew)!=0)
1570                                 print_error(FALSE,"Can't remove new header file",0);
1571                         g_free(hfnew);
1572                         g_free(hf);
1573                         g_free(s);
1574                         return;
1575                 }
1576                 g_free(s);
1577                 if(unlink(hf)!=0)
1578                         print_error(FALSE,"Can't remove old header file",0);
1579         }
1580         if(rename(hfnew,hf)!=0)
1581                 print_error(FALSE,"Can't rename new header file",0);
1582         g_free(hfnew);
1583         g_free(hf);
1584 }
1585
1586 int
1587 main(int argc, char *argv[])
1588 {
1589 #if 0
1590         int c;
1591         poptContext optCon;
1592         
1593         struct poptOption optionsTable[] = {
1594                 { "exit-on-warn", 'w', 0, &exit_on_warn, 0,
1595                          "exit on warnings" },
1596                 POPT_AUTOHELP
1597                 { NULL, 0, 0, NULL, 0 }
1598         };
1599         
1600         optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
1601         poptSetOtherOptionHelp(optCon, "[OPTIONS]* [filename]");
1602         
1603         while ((c = poptGetNextOpt(optCon)) >= 0)
1604                 ;
1605         
1606         filename = poptGetArg(optCon);
1607         if(!(poptPeekArg(optCon) == NULL))
1608                 usage(optCon, 1, "Specify only one file",
1609                       ".e.g., filename.gob");
1610                         
1611         if (c < -1) {
1612                 /* an error occurred during option processing */
1613                 fprintf(stderr, "%s: %s\n",
1614                         poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
1615                         poptStrerror(c));
1616                 return 1;
1617         }
1618 #endif
1619
1620         parse_options(argc,argv);
1621         
1622         if(filename) {
1623                 yyin = fopen(filename,"r");
1624                 if(!yyin) {
1625                         fprintf(stderr,"Error: can't open file '%s'\n",
1626                                 filename);
1627                         exit(1);
1628                 }
1629         } else
1630                 filename = "stdin";
1631
1632         /*yydebug = 1;*/
1633         if(yyparse()!=0)
1634                 g_error("Parsing errors, quitting");
1635         if(!class)
1636                 print_error(FALSE," no class defined",0);
1637         
1638         make_bases();
1639         
1640         exit_on_error = FALSE;
1641         make_inits((Class *)class);
1642         check_duplicate_symbols((Class *)class);
1643         check_duplicate_signals_args((Class *)class);
1644         check_public_new((Class *)class);
1645         check_vararg((Class *)class);
1646         exit_on_error = TRUE;
1647         
1648         if(got_error)
1649                 exit(1);
1650
1651         open_files();
1652         
1653         generate_outfiles();
1654
1655         fclose(out);
1656         fclose(outh);
1657
1658         if(no_touch_headers)
1659                 compare_and_move_header();
1660         
1661 #if 0
1662         poptFreeContext(optCon);
1663 #endif
1664         return 0;
1665 }