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