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