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