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