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