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