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