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