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