]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
Release 0.0.2
[gob-dx.git] / src / main.c
1 /* GOB C Preprocessor
2  * Copyright (C) 1999 the Free Software Foundation.
3  *
4  * Author: George Lebl
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the  Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  * USA.
20  */
21
22 #include "config.h"
23 #include <glib.h>
24 #include <popt.h>
25 #include <time.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "tree.h"
30 #include "parse.h"
31
32 char *filename = "stdin";
33
34 int yyparse(void);
35
36 extern int yydebug;
37 extern FILE * yyin;
38 extern Node *class;
39 extern GList *nodes;
40
41 static char *filebase;
42 static char *funcbase;
43 static char *pfuncbase;
44 static char *macrobase;
45 static char *macrois;
46 static char *typebase;
47 static char *ptypebase;
48
49 static FILE *out;
50 static FILE *outh;
51
52 int exit_on_warn = FALSE;
53
54 static void
55 print_error(int is_warn, char *error,int line)
56 {
57         char *w;
58         if(is_warn)
59                 w = "Warning:";
60         else
61                 w = "Error:";
62         if(line>0)
63                 fprintf(stderr,"%s:%d: %s %s\n",filename,line,w,error);
64         else
65                 fprintf(stderr,"%s: %s %s\n",filename,w,error);
66         if(!is_warn || exit_on_warn)
67                 exit(1);
68 }
69
70 static char *
71 remove_sep(char *base)
72 {
73         char *p;
74         char *s = g_strdup(base);
75         while((p=strchr(s,':')))
76                 strcpy(p,p+1);
77         return s;
78 }
79
80 static char *
81 replace_sep(char *base, char r)
82 {
83         char *p;
84         char *s = g_strdup(base);
85         while((p=strchr(s,':')))
86                 *p = r;
87         if(*s == r) {
88                 p = g_strdup(s+1);
89                 g_free(s);
90                 return p;
91         }
92         return s;
93 }
94
95 /*separate the namespace part and then replace rest of
96   separators with r*/
97 static void
98 separns_replace_sep(char *base, char **ns, char **name, char r)
99 {
100         char *p;
101         char *s = g_strdup(base);
102         *ns = NULL;
103         if((p=strchr(s,':')) && p!=s) {
104                 *p = '\0';
105                 *ns = g_strdup(s);
106                 p = g_strdup(p+1);
107                 g_free(s);
108                 s = p;
109         }
110         while((p=strchr(s,':')))
111                 *p = r;
112         if(*s == r) {
113                 *name = g_strdup(s+1);
114                 g_free(s);
115         } else
116                 *name = s;
117 }
118
119 static char *
120 make_is_macro(char *base)
121 {
122         char *s1,*s2;
123         char *s;
124
125         separns_replace_sep(base,&s1,&s2,'_');
126         if(s1)
127                 s = g_strconcat(s1,"_IS_",s2,NULL);
128         else
129                 s = g_strconcat("IS_",s2,NULL);
130
131         g_strup(s);
132         
133         g_free(s1);
134         g_free(s2);
135
136         return s;
137 }
138
139 static void
140 make_bases(void)
141 {
142         filebase = replace_sep(((Class *)class)->otype,'-');
143         g_strdown(filebase);
144
145         funcbase = replace_sep(((Class *)class)->otype,'_');
146         g_strdown(funcbase);
147
148         pfuncbase = replace_sep(((Class *)class)->ptype,'_');
149         g_strdown(pfuncbase);
150
151         macrobase = replace_sep(((Class *)class)->otype,'_');
152         g_strup(macrobase);
153         
154         macrois = make_is_macro(((Class *)class)->otype);
155
156         typebase = remove_sep(((Class *)class)->otype);
157
158         ptypebase = remove_sep(((Class *)class)->ptype);
159 }
160
161 static void
162 def_methods(Class *c)
163 {
164         GList *li;
165         
166         fprintf(out,"\n");
167         for(li=c->nodes;li;li=g_list_next(li)) {
168                 Node *node = li->data;
169                 if(node->type == METHOD_NODE) {
170                         Method *m = (Method *)node;
171                         
172                         if(m->scope == INIT_METHOD ||
173                            m->scope == CLASS_INIT_METHOD ||
174                            m->scope == OVERRIDE_METHOD)
175                                 continue;
176                         
177                         fprintf(out,"#define %s %s_%s\n",m->id,funcbase,m->id); 
178                 }
179         }
180         fprintf(out,"\n");
181 }
182
183 static void
184 undef_methods(Class *c)
185 {
186         GList *li;
187         
188         fprintf(out,"\n");
189         for(li=c->nodes;li;li=g_list_next(li)) {
190                 Node *node = li->data;
191                 if(node->type == METHOD_NODE) {
192                         Method *m = (Method *)node;
193
194                         if(m->scope == INIT_METHOD ||
195                            m->scope == CLASS_INIT_METHOD ||
196                            m->scope == OVERRIDE_METHOD)
197                                 continue;
198                         
199                         fprintf(out,"#undef %s\n",m->id); 
200                 }
201         }
202         fprintf(out,"\n");
203 }
204
205 static void
206 print_type(FILE *fp, Type *t)
207 {
208         char *s;
209         int i;
210         s = remove_sep(t->name);
211         fprintf(fp,"%s ",s); 
212         g_free(s);
213         
214         for(i=0;i<t->stars;i++)
215                 fprintf(fp,"*"); 
216 }
217
218 static void
219 put_variable(Variable *v)
220 {
221         fprintf(outh,"\t");
222         if(v->scope == PRIVATE_SCOPE)
223                 fprintf(outh,"/* private */ "); 
224         print_type(outh,v->vtype);
225
226         fprintf(outh,"%s;\n",v->id); 
227 }
228
229 static void
230 print_method(FILE *fp, char *typeprefix, char *nameprefix,
231              char *namepostfix,char *postfix, Method *m)
232 {
233         GList *li;
234
235         fprintf(fp,"%s",typeprefix); 
236         print_type(fp,m->mtype);
237         fprintf(fp,"%s%s_%s%s(",
238                 nameprefix,funcbase,m->id,namepostfix); 
239         
240         for(li=m->args;li;li=g_list_next(li)) {
241                 FuncArg *arg = li->data;
242                 print_type(fp,arg->atype);
243                 if(li->next)
244                         fprintf(fp,"%s, ",arg->name); 
245                 else
246                         fprintf(fp,"%s",arg->name); 
247
248         }
249         fprintf(fp,")%s\n",postfix); 
250 }
251
252 static void
253 put_vs_method(Method *m)
254 {
255         if(m->scope != SIGNAL_LAST_METHOD &&
256            m->scope != SIGNAL_FIRST_METHOD &&
257            m->scope != VIRTUAL_METHOD)
258                 return;
259
260         print_method(outh,"\t","(* ",") ",";",m);
261 }
262
263 static void
264 put_pub_method(Method *m)
265 {
266         if(m->scope == PRIVATE_SCOPE ||
267            m->scope == OVERRIDE_METHOD ||
268            m->scope == INIT_METHOD ||
269            m->scope == CLASS_INIT_METHOD)
270                 return;
271
272         print_method(outh,"","\t","\t",";",m);
273 }
274
275 static void
276 put_priv_method_prot(Method *m)
277 {
278         if(m->scope == PUBLIC_SCOPE)
279                 return;
280
281         if(m->scope == SIGNAL_LAST_METHOD ||
282            m->scope == SIGNAL_FIRST_METHOD ||
283            m->scope == VIRTUAL_METHOD) {
284                 if(!m->cbuf)
285                         return;
286                 print_method(out,"static ","_real_"," ",";",m);
287         } else {
288                 print_method(out,"static ",""," ",";",m);
289         }
290 }
291
292 static GList *
293 make_init_args(Class *cl, char *name, int is_class)
294 {
295         Node *node;
296         Node *type;
297         char *tn;
298         
299         if(is_class)
300                 tn = g_strconcat(cl->otype,":Class",NULL);
301         else
302                 tn = g_strdup(cl->otype);
303
304         type = new_type(1,tn);
305         node = new_funcarg((Type *)type,name,NULL);
306         return g_list_prepend(NULL, node);
307 }
308
309 static void
310 make_inits(Class *cl)
311 {
312         int got_class_init = FALSE;
313         int got_init = FALSE;
314         GList *li;
315         Node *node;
316         for(li=cl->nodes;li;li=g_list_next(li)) {
317                 Node *n = li->data;
318                 if(n->type == METHOD_NODE) {
319                         Method *m = (Method *)n;
320                         if(m->scope == INIT_METHOD) {
321                                 if(got_init)
322                                         print_error(FALSE,"init defined more then once",m->line_no);
323                                 got_init = TRUE;
324                         } else if(m->scope == CLASS_INIT_METHOD) {
325                                 if(got_class_init)
326                                         print_error(FALSE,"class_init defined more then once",m->line_no);
327                                 got_class_init = TRUE;
328                         }
329                 }
330         }
331         if(!got_class_init) {
332                 node = new_method(CLASS_INIT_METHOD,
333                                   (Type *)new_type(0,g_strdup("void")),
334                                   NULL,NULL,g_strdup("class_init"),
335                                   make_init_args(cl,g_strdup("c"),TRUE),
336                                   NULL, NULL,0);
337                 cl->nodes = g_list_prepend(cl->nodes,node);
338         }
339         if(!got_init) {
340                 node = new_method(INIT_METHOD,
341                                   (Type *)new_type(0,g_strdup("void")),
342                                   NULL,NULL,g_strdup("init"),
343                                   make_init_args(cl,g_strdup("o"),FALSE),
344                                   NULL, NULL,0);
345                 cl->nodes = g_list_prepend(cl->nodes,node);
346         }
347 }
348
349 static GHashTable *marsh = NULL;
350
351 static void
352 add_signal_prots(Method *m)
353 {
354         GList *li;
355         static int sig = 1;
356         char *s;
357         
358         if(m->scope != SIGNAL_LAST_METHOD &&
359            m->scope != SIGNAL_FIRST_METHOD)
360                 return;
361
362         if(!marsh)
363                 marsh = g_hash_table_new(NULL,NULL);
364         
365         if(strcmp(m->gtktypes->data,"NONE")==0 &&
366            strcmp(m->gtktypes->next->data,"NONE")==0)
367                 return;
368         
369         s = g_strdup_printf("__Sig%d",sig++);
370         
371         g_hash_table_insert(marsh,m,s);
372         
373         fprintf(out,"\ntypedef ");
374         print_type(out,m->mtype);
375         
376         fprintf(out,"(*%s) (",s);
377         
378         for(li=m->args;li;li=g_list_next(li)) {
379                 FuncArg *arg = li->data;
380                 print_type(out,arg->atype);
381                 fprintf(out,", "); 
382         }
383         fprintf(out,"gpointer);\n"); 
384         
385         fprintf(out,"\nstatic void\n"
386                 "marshal_%s (GtkObject * object,\n"
387                 "\tGtkSignalFunc func,\n"
388                 "\tgpointer func_data,\n"
389                 "\tGtkArg * args)\n"
390                 "{\n",s);
391         
392         if(strcmp(m->gtktypes->data,"NONE")==0) {
393                 int i;
394                 fprintf(out, "\t%s rfunc;\n\n"
395                         "\trfunc = (%s)func;\n\n"
396                         "\t(*rfunc)((%s *)object",s,s,typebase);
397                 if(strcmp(m->gtktypes->next->data,"NONE")!=0) {
398                         for(i=0,li=m->gtktypes->next;li;
399                             i++,li=g_list_next(li)) {
400                                 fprintf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
401                                         (char *)li->data,i);
402                         }
403                 }
404                 fprintf(out, ",\n\t\tfunc_data);\n}\n\n");
405         } else {
406                 int i;
407                 fprintf(out, "\t%s rfunc;\n\t",s);
408                 print_type(out,m->mtype);
409                 fprintf(out, " *retval;\n\n"
410                         "\trfunc = (%s)func;\n\n"
411                         "\tretval = GTK_RETLOC_%s(args[%d]);\n\n"
412                         "\t*retval = (*rfunc)((%s *)object",
413                         s,(char *)m->gtktypes->data,
414                         g_list_length(m->gtktypes)-1,typebase);
415                 if(strcmp(m->gtktypes->next->data,"NONE")!=0) {
416                         for(i=0,li=m->gtktypes->next;li;
417                             i++,li=g_list_next(li)) {
418                                 fprintf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
419                                         (char *)li->data,i);
420                         }
421                 }
422                 fprintf(out, ",\n\t\tfunc_data);\n}\n\n");
423         }
424
425 }
426
427 static void
428 add_enums(Class *c)
429 {
430         GList *li;
431         fprintf(out,"\nenum {\n");
432         for(li=c->nodes;li;li=g_list_next(li)) {
433                 Node *n = li->data;
434                 if(n->type == METHOD_NODE) {
435                         Method *m = (Method *)n;
436                         if(m->scope == SIGNAL_LAST_METHOD ||
437                            m->scope == SIGNAL_FIRST_METHOD) {
438                                 char *s = g_strdup(m->id);
439                                 g_strup(s);
440                                 fprintf(out,"\t%s_SIGNAL,\n",s);
441                                 g_free(s);
442                         }
443                 }
444         }
445         fprintf(out,"\tLAST_SIGNAL\n"
446                 "};\n\n"
447                 "enum {\n"
448                 "\tARG_0,\n");
449         for(li=c->nodes;li;li=g_list_next(li)) {
450                 Node *n = li->data;
451                 if(n->type == ARGUMENT_NODE) {
452                         Argument *a = (Argument *)n;
453                         char *s = g_strdup(a->name);
454                         g_strup(s);
455                         fprintf(out,"\tARG_%s,\n",s);
456                         g_free(s);
457                 }
458         }
459         fprintf(out, "};\n\n"
460                 "static guint object_signals[LAST_SIGNAL] = {0};\n\n"
461                 "static %sClass *parent_class = NULL;\n\n",ptypebase);
462 }
463
464 static void
465 add_get_type(void)
466 {
467         fprintf(out, "guint\n"
468                 "%s_get_type (void)\n"
469                 "{\n"
470                 "\tstatic guint type = 0;\n\n"
471                 "\tif (!type) {\n"
472                 "\t\tstatic const GtkTypeInfo info = {\n"
473                 "\t\t\t\"%s\",\n"
474                 "\t\t\tsizeof (%s),\n"
475                 "\t\t\tsizeof (%sClass),\n"
476                 "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
477                 "\t\t\t(GtkObjectInitFunc) %s_init,\n"
478                 "\t\t\t/* reserved_1 */ NULL,\n"
479                 "\t\t\t/* reserved_2 */ NULL,\n"
480                 "\t\t\t(GtkClassInitFunc) NULL,\n"
481                 "\t\t};\n\n"
482                 "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n"
483                 "\t}\n\n"
484                 "\treturn type;\n"
485                 "}\n\n",
486                 funcbase,typebase,typebase,typebase,
487                 funcbase,funcbase,pfuncbase);
488 }
489
490 static void
491 add_overrides(Class *c, char *oname)
492 {
493         GList *li;
494         GHashTable *done;
495         char *s;
496         
497         done = g_hash_table_new(g_str_hash,g_str_equal);
498         s = g_strdup("GtkObject"); /* This was already done */
499         g_hash_table_insert(done,s,s);
500         for(li=c->nodes;li;li=g_list_next(li)) {
501                 Node *n = li->data;
502                 char *f;
503                 Method *m;
504                 if(n->type != METHOD_NODE ||
505                    ((Method *)n)->scope != OVERRIDE_METHOD)
506                         continue;
507                 m = (Method *)n;
508                 
509                 s = remove_sep(m->otype);
510                 
511                 if(g_hash_table_lookup(done,s)) {
512                         g_free(s);
513                         continue;
514                 }
515                 g_hash_table_insert(done,s,s);
516
517                 f = replace_sep(m->otype,'_');
518                 g_strdown(f);
519
520                 fprintf(out,"\t%sClass *%s_class = (%sClass *)%s;\n",
521                         s,f,s,oname);
522                 
523                 g_free(f);
524         }
525         g_hash_table_foreach(done,(GHFunc)g_free,NULL);
526         g_hash_table_destroy(done);
527 }
528
529 static void
530 add_signals(Class *c)
531 {
532         GList *li;
533
534         fprintf(out,"\n");
535         for(li=c->nodes;li;li=g_list_next(li)) {
536                 Node *n = li->data;
537                 Method *m;
538                 char *mar;
539                 char *sig;
540                 int is_none;
541                 if(n->type != METHOD_NODE ||
542                    (((Method *)n)->scope != SIGNAL_FIRST_METHOD &&
543                     ((Method *)n)->scope != SIGNAL_LAST_METHOD))
544                         continue;
545
546                 m = (Method *)n;
547
548                 if(g_hash_table_lookup(marsh,m))
549                         mar = g_strconcat("marshal_",
550                                           (char *)g_hash_table_lookup(marsh,m),
551                                           NULL);
552                 else
553                         mar = g_strdup("gtk_signal_default_marshaller");
554                 
555                 is_none = (strcmp(m->gtktypes->next->data,"NONE")==0);
556                 
557                 sig = g_strdup(m->id);
558                 g_strup(sig);
559                 fprintf(out,"\tobject_signals[%s_SIGNAL] =\n"
560                         "\t\tgtk_signal_new (\"%s\",\n"
561                         "\t\t\tGTK_RUN_%s,\n"
562                         "\t\t\tgtk_object_class->type,\n"
563                         "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n"
564                         "\t\t\t%s,\n"
565                         "\t\t\tGTK_TYPE_%s, %d",
566                         sig,m->id,
567                         m->scope==SIGNAL_LAST_METHOD?"LAST":"FIRST",
568                         typebase,m->id,mar,(char *)m->gtktypes->data,
569                         is_none?0:g_list_length(m->gtktypes->next));
570                 g_free(mar);
571                 g_free(sig);
572                 
573                 if(!is_none) {
574                         GList *l;
575                         for(l=m->gtktypes->next;l;l=g_list_next(l))
576                                 fprintf(out,",\n\t\t\tGTK_TYPE_%s",
577                                         (char *)l->data);
578                 }
579
580                 fprintf(out,");\n");
581         }
582         fprintf(out,"\tgtk_object_class_add_signals (gtk_object_class,\n"
583                 "\t\tobject_signals, LAST_SIGNAL);\n\n");
584 }
585
586 static void
587 set_def_handlers(Class *c, char *oname)
588 {
589         GList *li;
590
591         fprintf(out,"\n");
592         for(li=c->nodes;li;li=g_list_next(li)) {
593                 Node *n = li->data;
594                 Method *m;
595                 if(n->type != METHOD_NODE ||
596                    (((Method *)n)->scope != SIGNAL_FIRST_METHOD &&
597                     ((Method *)n)->scope != SIGNAL_LAST_METHOD &&
598                     ((Method *)n)->scope != VIRTUAL_METHOD &&
599                     ((Method *)n)->scope != OVERRIDE_METHOD))
600                         continue;
601
602                 m = (Method *)n;
603
604                 if(m->scope == OVERRIDE_METHOD) {
605                         char *s;
606                         s = replace_sep(m->otype,'_');
607                         g_strdown(s);
608                         fprintf(out,"\t%s_class->%s = %s_%s;\n",
609                                 s,m->id,funcbase,m->id);
610                 } else {
611                         if(m->cbuf)
612                                 fprintf(out,"\t%s->%s = _real_%s_%s;\n",
613                                         oname,m->id,funcbase,m->id);
614                         else
615                                 fprintf(out,"\t%s->%s = NULL;\n",
616                                         oname,m->id);
617                 }
618         }
619 }
620
621 static int
622 is_arguments(Class *c)
623 {
624         GList *li;
625
626         for(li=c->nodes;li;li=g_list_next(li)) {
627                 Node *n = li->data;
628                 if(n->type == ARGUMENT_NODE)
629                         return TRUE;
630         }
631         return FALSE;
632 }
633
634
635 static void
636 make_arguments(Class *c)
637 {
638         GList *li;
639
640         fprintf(out,"\n");
641         for(li=c->nodes;li;li=g_list_next(li)) {
642                 Node *n = li->data;
643                 Argument *a;
644                 GString *flags;
645                 GList *l;
646                 char *s;
647                 if(n->type != ARGUMENT_NODE)
648                         continue;
649
650                 a = (Argument *)n;
651                 
652                 if(a->get && a->set)
653                         flags = g_string_new("GTK_ARG_READWRITE");
654                 else if(a->get)
655                         flags = g_string_new("GTK_ARG_READABLE");
656                 else
657                         flags = g_string_new("GTK_ARG_WRITABLE");
658                 
659                 for(l=a->flags;l;l=g_list_next(l))
660                         g_string_sprintfa(flags," | GTK_ARG_%s",(char *)l->data);
661
662                 s = g_strdup(a->name);
663                 g_strup(s);
664                 fprintf(out,"\tgtk_object_add_arg_type(\"%s::%s\",\n"
665                         "\t\tGTK_TYPE_%s,\n"
666                         "\t\t%s,\n"
667                         "\t\tARG_%s);\n",
668                         typebase,a->name,a->gtktype,flags->str,s);
669                 g_free(s);
670                 g_string_free(flags,TRUE);
671         }
672         
673         if(is_arguments(c)) {
674                 fprintf(out,
675                         "\n\tgtk_object_class->set_arg = __object_set_arg;\n"
676                         "\tgtk_object_class->get_arg = __object_get_arg;\n");
677         }
678 }
679
680 static void
681 add_inits(Class *c)
682 {
683         GList *li;
684         for(li=c->nodes;li;li=g_list_next(li)) {
685                 Node *n = li->data;
686                 Method *m;
687                 if(n->type != METHOD_NODE)
688                         continue;
689                 m = (Method *)n;
690                 if(m->scope == INIT_METHOD) {
691                         print_method(out,"static ","\n"," ","",m);
692                         if(m->cbuf)
693                                 fprintf(out,"{\n%s\n}\n\n",m->cbuf->str);
694                         else
695                                 fprintf(out,"{\n\treturn;\n}\n\n");
696                 } else if(m->scope == CLASS_INIT_METHOD) {
697                         print_method(out,"static ","\n"," ","",m);
698                         fprintf(out,"{\n"
699                                 "\tGtkObjectClass *gtk_object_class = "
700                                 "(GtkObjectClass*) %s;\n",
701                                 ((FuncArg *)m->args->data)->name);
702                         
703                         add_overrides(c, ((FuncArg *)m->args->data)->name);
704                         
705                         fprintf(out,"\n\tparent_class = "
706                                 "gtk_type_class (%s_get_type ());\n",
707                                 pfuncbase);
708
709                         add_signals(c);
710
711                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
712                         
713                         make_arguments(c);
714                         
715                         if(m->cbuf)
716                                 fprintf(out," {\n%s\n }\n",m->cbuf->str);
717                         fprintf(out,"}\n");
718                 }
719         }
720 }
721
722 static void
723 add_getset_arg(Class *c, int is_set)
724 {
725         GList *li;
726         fprintf(out,"\nstatic void\n"
727                 "__object_%s_arg (GtkObject *object,\n"
728                 "\tGtkArg *arg,\n"
729                 "\tguint arg_id)\n"
730                 "{\n"
731                 "\t%s *this;\n\n"
732                 "\tthis = %s (object);\n\n"
733                 "\tswitch (arg_id) {\n",
734                 is_set?"set":"get",typebase,macrobase);
735
736         for(li=c->nodes;li;li=g_list_next(li)) {
737                 Node *n = li->data;
738                 Argument *a;
739                 char *s;
740                 if(n->type != ARGUMENT_NODE)
741                         continue;
742                 a = (Argument *)n;
743                 if((is_set && !a->set) ||
744                    (!is_set && !a->get))
745                         continue;
746                 s = g_strdup(a->name);
747                 g_strup(s);
748                 fprintf(out,"\tcase ARG_%s:\n"
749                         "#define ARG (GTK_VALUE_%s(*arg))\n"
750                         "\t\t{\n%s\n\t\t}\n\t\tbreak;\n"
751                         "#undef ARG\n",
752                         s,a->gtktype,a->set->str);
753                 g_free(s);
754         }
755         fprintf(out,"\tdefault:\n\t\tbreak;\n\t}\n}\n");
756 }
757
758 static void
759 print_checks(Method *m, FuncArg *fa)
760 {
761         GList *li;
762         int is_void;
763         is_void = (strcmp(m->mtype->name,"void")==0 &&
764                    m->mtype->stars == 0);
765         
766         for(li=fa->checks;li;li=g_list_next(li)) {
767                 Check *ch = li->data;
768                 char *s;
769                 if(is_void)
770                         fprintf(out,"\tg_return_if_fail (");
771                 else
772                         fprintf(out,"\tg_return_val_if_fail (");
773                 switch(ch->chtype) {
774                 case NULL_CHECK:
775                         fprintf(out,"%s != NULL",fa->name);
776                         break;
777                 case TYPE_CHECK:
778                         s = make_is_macro(fa->atype->name);
779                         fprintf(out,"%s (%s)",s,fa->name);
780                         g_free(s);
781                         break;
782                 case LT_CHECK:
783                         fprintf(out,"%s < %s",fa->name,ch->number);
784                         break;
785                 case GT_CHECK:
786                         fprintf(out,"%s > %s",fa->name,ch->number);
787                         break;
788                 case LE_CHECK:
789                         fprintf(out,"%s <= %s",fa->name,ch->number);
790                         break;
791                 case GE_CHECK:
792                         fprintf(out,"%s >= %s",fa->name,ch->number);
793                         break;
794                 case EQ_CHECK:
795                         fprintf(out,"%s == %s",fa->name,ch->number);
796                         break;
797                 case NE_CHECK:
798                         fprintf(out,"%s != %s",fa->name,ch->number);
799                         break;
800                 }
801                 if(is_void)
802                         fprintf(out,");\n");
803                 else {
804                         fprintf(out,", (");
805                         print_type(out,m->mtype);
806                         fprintf(out,")%s);\n",
807                                 m->onerror?m->onerror:"0");
808                 }
809         }
810 }
811
812 static void
813 print_preconditions(Method *m)
814 {
815         GList *li;
816         
817         for(li=m->args;li;li=g_list_next(li)) {
818                 FuncArg *fa = li->data;
819                 if(fa->checks)
820                         print_checks(m,fa);
821         }
822 }
823
824 static void
825 print_method_body(Method *m, int pre)
826 {
827         fprintf(out,"{\n");
828         if(pre) {
829                 print_preconditions(m);
830                 fprintf(out,"\t{\n");
831         }
832
833         fprintf(out,"\t\t%s\n",m->cbuf->str);
834
835         if(pre)
836                 fprintf(out,"\t}\n");
837         fprintf(out,"}\n");
838 }
839
840 static void
841 put_method(Method *m)
842 {
843         char *s;
844         fprintf(out,"\n");
845         if(strcmp(m->id,"new")==0) {
846                 fprintf(out,"#define GET_NEW (gtk_type_new(%s_get_type()))\n",
847                         funcbase);
848         }
849         switch(m->scope) {
850         case PUBLIC_SCOPE:
851                 print_method(out,"","\n"," ","",m);
852                 print_method_body(m,TRUE);
853                 break;
854         case PRIVATE_SCOPE:
855                 print_method(out,"static ","\n"," ","",m);
856                 print_method_body(m,TRUE);
857                 break;
858         case SIGNAL_FIRST_METHOD:
859         case SIGNAL_LAST_METHOD:
860                 print_method(out,"","\n"," ","",m);
861                 fprintf(out,"{\n");
862                 s = g_strdup(m->id);
863                 g_strup(s);
864                 if(strcmp(m->mtype->name,"void")==0 &&
865                    m->mtype->stars==0) {
866                         GList *li;
867                         print_preconditions(m);
868                         fprintf(out,"\tgtk_signal_emit (GTK_OBJECT (this),\n"
869                                 "\t\tobject_signals[%s_SIGNAL]",s);
870                         for(li=m->args->next;li;li=g_list_next(li)) {
871                                 FuncArg *fa = li->data;
872                                 fprintf(out,",\n\t\t%s",fa->name);
873                         }
874                         fprintf(out,");\n}\n");
875                 } else {
876                         GList *li;
877                         fprintf(out,"\t");
878                         print_type(out,m->mtype);
879                         fprintf(out,"return_val;\n");
880                         print_preconditions(m);
881                         fprintf(out,"\tgtk_signal_emit (GTK_OBJECT (this),\n"
882                                 "\t\tobject_signals[%s_SIGNAL]",s);
883                         for(li=m->args->next;li;li=g_list_next(li)) {
884                                 FuncArg *fa = li->data;
885                                 fprintf(out,",\n\t\t%s",fa->name);
886                         }
887                         fprintf(out,",\n\t\t&return_val);\n"
888                                 "\treturn return_val;\n}\n");
889                 }
890
891                 if(!m->cbuf)
892                         break;
893                 print_method(out,"static ","\n_real_"," ","",m);
894                 print_method_body(m,FALSE);
895                 break;
896         case VIRTUAL_METHOD:
897                 print_method(out,"","\n"," ","",m);
898                 fprintf(out,"{\n"
899                         "\t%sClass *class;\n",typebase);
900                 print_preconditions(m);
901                 fprintf(out,"\tclass = %s_CLASS(GTK_OBJECT(this)->klass);\n\n"
902                         "\tif(class->%s)\n",
903                         macrobase,m->id);
904                 if(strcmp(m->mtype->name,"void")==0 &&
905                    m->mtype->stars==0) {
906                         GList *li;
907                         fprintf(out,"\t\t(*class->%s)(this",m->id);
908                         for(li=m->args->next;li;li=g_list_next(li)) {
909                                 FuncArg *fa = li->data;
910                                 fprintf(out,",%s",fa->name);
911                         }
912                         fprintf(out,");\n}\n");
913                 } else {
914                         GList *li;
915                         fprintf(out,"\t\treturn (*class->%s)(this",m->id);
916                         for(li=m->args->next;li;li=g_list_next(li)) {
917                                 FuncArg *fa = li->data;
918                                 fprintf(out,",%s",fa->name);
919                         }
920                         fprintf(out,");\n"
921                                 "\telse\n"
922                                 "\t\treturn (");
923                         print_type(out,m->mtype);
924                         fprintf(out,")(%s);\n}\n",
925                                 m->onerror?m->onerror:"0");
926                 }
927
928                 if(!m->cbuf)
929                         break;
930                 print_method(out,"static ","\n_real_"," ","",m);
931                 print_method_body(m,FALSE);
932                 break;
933         case OVERRIDE_METHOD:
934                 print_method(out,"static ","\n"," ","",m);
935                 print_method_body(m,TRUE);
936                 break;
937         default:
938                 break;
939         }
940         if(strcmp(m->id,"new")==0)
941                 fprintf(out,"#undef GET_NEW\n");
942 }
943
944 static void
945 open_files(void)
946 {
947         char *outfile,*outfileh;
948
949         outfile = g_strconcat(filebase,".c",NULL);
950         outfileh = g_strconcat(filebase,".h",NULL);
951         
952         out = fopen(outfile,"w");
953         if(!out) {
954                 g_error("Cannot open outfile: %s",outfile);
955         }
956         outh = fopen(outfileh,"w");
957         if(!outh) {
958                 g_error("Cannot open outfile: %s",outfileh);
959         }
960 }
961
962 static void
963 generate_outfiles(void)
964 {
965         char *p;
966         GList *li;
967         time_t curtime;
968
969         time(&curtime);
970         fprintf(outh,"/* Generated by GOB (v%s) on %s"
971                "   (do not edit directly) */\n\n",VERSION,ctime(&curtime));
972         fprintf(out,"/* Generated by GOB (v%s) on %s"
973                "   (do not edit directly) */\n\n",VERSION,ctime(&curtime));
974         
975         p = replace_sep(((Class *)class)->otype,'_');
976         g_strup(p);
977         fprintf(outh,"#ifndef __%s_H__\n#define __%s_H__\n\n"
978                 "#include <gtk/gtk.h>\n\n",p,p);
979         g_free(p);
980
981         fprintf(outh,"#ifdef __cplusplus\n"
982                 "extern \"C\" {\n"
983                 "#endif /* __cplusplus */\n\n");
984         
985         fprintf(out,"#include \"%s.h\"\n\n",filebase);
986         
987         for(li=nodes;li;li=g_list_next(li)) {
988                 Node *node = li->data;
989                 if(node->type == CCODE_NODE) {
990                         CCode *cc = (CCode *)node;
991                         FILE *fp;
992                         if(cc->header)
993                                 fp = outh;
994                         else
995                                 fp = out;
996                         fprintf(fp,"\n%s\n",cc->cbuf->str);
997                 } else if(node->type == CLASS_NODE) {
998                         GList *l;
999                         Class *c = (Class *)class;
1000                         char *otype,*ptype;
1001                         
1002                         fprintf(outh,"\n#define %s(obj)\t"
1003                                 "GTK_CHECK_CAST((obj),%s_get_type(),%s)\n",
1004                                 macrobase,funcbase,typebase);
1005                         fprintf(outh,"#define %s_CLASS(klass)\t"
1006                                 "GTK_CHECK_CLASS_CAST((klass),%s_get_type(),%sClass)\n",
1007                                 macrobase,funcbase,typebase);
1008                         fprintf(outh,"#define %s(obj)\t"
1009                                 "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
1010                                 macrois,funcbase);
1011
1012                         otype = remove_sep(c->otype);
1013                         ptype = remove_sep(c->ptype);
1014                         fprintf(outh,"\ntypedef struct _%s %s;\n",otype,otype);
1015                         fprintf(outh,"struct _%s {\n\t%s __parent__;\n",
1016                                 otype,ptype);
1017                         for(l=c->nodes;l;l=g_list_next(l)) {
1018                                 Node *n = l->data;
1019                                 if(n->type == VARIABLE_NODE)
1020                                         put_variable((Variable *)n);
1021                         }
1022                         fprintf(outh,"};\n");
1023
1024                         fprintf(outh,"\ntypedef struct _%sClass %sClass;\n",
1025                                 otype,otype);
1026                         fprintf(outh,
1027                                 "struct _%sClass {\n\t%sClass __parent__;\n",
1028                                 otype,ptype);
1029                         for(l=c->nodes;l;l=g_list_next(l)) {
1030                                 Node *n = l->data;
1031                                 if(n->type == METHOD_NODE)
1032                                         put_vs_method((Method *)n);
1033                         }
1034                         fprintf(outh,"};\n\n");
1035
1036                         fprintf(outh,"guint\t%s_get_type\t(void);\n",funcbase);
1037                         
1038                         if(is_arguments(c)) {
1039                                 fprintf(out,"static void __object_set_arg "
1040                                         "(GtkObject *object, GtkArg *arg, "
1041                                         "guint arg_id);\n"
1042                                         "static void __object_get_arg "
1043                                         "(GtkObject *object, GtkArg *arg, "
1044                                         "guint arg_id);\n");
1045                         }
1046
1047                         for(l=c->nodes;l;l=g_list_next(l)) {
1048                                 Node *n = l->data;
1049                                 if(n->type == METHOD_NODE) {
1050                                         put_pub_method((Method *)n);
1051                                         put_priv_method_prot((Method *)n);
1052                                 }
1053                         }
1054
1055                         for(l=c->nodes;l;l=g_list_next(l)) {
1056                                 Node *n = l->data;
1057                                 if(n->type == METHOD_NODE) {
1058                                         add_signal_prots((Method *)n);
1059                                 }
1060                         }
1061                         
1062                         add_enums(c);
1063                         
1064                         add_get_type();
1065
1066                         def_methods(c);
1067                         
1068                         add_inits(c);
1069
1070                         if(is_arguments(c)) {
1071                                 add_getset_arg(c, TRUE);
1072                                 add_getset_arg(c, FALSE);
1073                         }
1074
1075                         for(l=c->nodes;l;l=g_list_next(l)) {
1076                                 Node *n = l->data;
1077                                 if(n->type == METHOD_NODE) {
1078                                         put_method((Method *)n);
1079                                 }
1080                         }
1081
1082                         undef_methods(c);
1083
1084                         g_free(otype);
1085                         g_free(ptype);
1086                 } else
1087                         g_assert_not_reached();
1088         }
1089
1090         fprintf(outh,"\n#ifdef __cplusplus\n"
1091                 "}\n"
1092                 "#endif /* __cplusplus */\n\n"
1093                 "#endif");
1094 }
1095
1096 static void
1097 usage(poptContext optCon, int exitcode, char *error, char *addl)
1098 {
1099         poptPrintUsage(optCon, stderr, 0);
1100         if (error) fprintf(stderr, "%s: %s", error, addl);
1101         exit(exitcode);
1102 }
1103
1104
1105 int
1106 main(int argc, char *argv[])
1107 {
1108         int c;
1109         poptContext optCon;
1110         
1111         struct poptOption optionsTable[] = {
1112                 { "exit-on-warn", 'w', 0, &exit_on_warn, 0,
1113                          "exit on warnings" },
1114                 POPT_AUTOHELP
1115                 { NULL, 0, 0, NULL, 0 }
1116         };
1117         
1118         optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
1119         poptSetOtherOptionHelp(optCon, "[OPTIONS]* [filename]");
1120         
1121         while ((c = poptGetNextOpt(optCon)) >= 0)
1122                 ;
1123         
1124         filename = poptGetArg(optCon);
1125         if(!(poptPeekArg(optCon) == NULL))
1126                 usage(optCon, 1, "Specify only one file",
1127                       ".e.g., filename.gob");
1128                         
1129         if (c < -1) {
1130                 /* an error occurred during option processing */
1131                 fprintf(stderr, "%s: %s\n",
1132                         poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
1133                         poptStrerror(c));
1134                 return 1;
1135         }
1136         
1137         if(filename) {
1138                 yyin = fopen(filename,"r");
1139                 if(!yyin) {
1140                         fprintf(stderr,"Error: can't open file '%s'\n",
1141                                 filename);
1142                         exit(1);
1143                 }
1144         } else
1145                 filename = "stdin";
1146
1147         /*yydebug = 1;*/
1148         if(yyparse()!=0)
1149                 g_error("Parsing errors, quitting");
1150         if(!class)
1151                 print_error(FALSE," no class defined",0);
1152         
1153         make_bases();
1154         
1155         make_inits((Class *)class);
1156         
1157         open_files();
1158         
1159         generate_outfiles();
1160
1161         fclose(out);
1162         fclose(outh);
1163         
1164         poptFreeContext(optCon);
1165         return 0;
1166 }