]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
Release 0.93.1
[gob-dx.git] / src / main.c
1 /* GOB C Preprocessor
2  * Copyright (C) 1999 the Free Software Foundation.
3  *
4  * Author: George Lebl
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the  Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  * USA.
20  */
21
22 #include "config.h"
23 #include <glib.h>
24 #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 "tree.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, 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, 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,
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;\n");
1471                         print_preconditions(m);
1472                         out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1473                                 "\t\tobject_signals[%s_SIGNAL]",
1474                                 ((FuncArg *)m->args->data)->name,s);
1475                         put_signal_args(m);
1476                         out_printf(out,",\n\t\t&return_val);\n"
1477                                 "\treturn return_val;\n}\n");
1478                 }
1479
1480                 if(!m->cbuf)
1481                         break;
1482                 if(m->line_no>0)
1483                         out_addline_infile(out,m->line_no);
1484                 print_method(out,"static ","\n___real_",""," ","\n",
1485                              m,FALSE,FALSE);
1486                 print_method_body(m,FALSE);
1487                 break;
1488         case VIRTUAL_METHOD:
1489                 if(m->line_no>0)
1490                         out_addline_infile(out,m->line_no);
1491                 if(m->scope==PRIVATE_SCOPE)
1492                         print_method(out,"static ","\n",""," ","\n",
1493                                      m,FALSE,FALSE);
1494                 else /* PUBLIC, PROTECTED */
1495                         print_method(out,"","\n",""," ","\n",m,FALSE,FALSE);
1496                 out_addline_outfile(out);
1497                 out_printf(out,"{\n"
1498                         "\t%sClass *klass;\n",typebase);
1499                 print_preconditions(m);
1500                 out_printf(out,"\tklass = %s_CLASS(GTK_OBJECT(%s)->klass);\n\n"
1501                         "\tif(klass->%s)\n",
1502                         macrobase, ((FuncArg *)m->args->data)->name, m->id);
1503                 if(strcmp(m->mtype->name,"void")==0 &&
1504                    m->mtype->stars==0) {
1505                         GList *li;
1506                         out_printf(out,"\t\t(*klass->%s)(%s",m->id,
1507                                    ((FuncArg *)m->args->data)->name);
1508                         for(li=m->args->next;li;li=g_list_next(li)) {
1509                                 FuncArg *fa = li->data;
1510                                 out_printf(out,",%s",fa->name);
1511                         }
1512                         out_printf(out,");\n}\n");
1513                 } else {
1514                         GList *li;
1515                         out_printf(out,"\t\treturn (*klass->%s)(%s",m->id,
1516                                    ((FuncArg *)m->args->data)->name);
1517                         for(li=m->args->next;li;li=g_list_next(li)) {
1518                                 FuncArg *fa = li->data;
1519                                 out_printf(out,",%s",fa->name);
1520                         }
1521                         out_printf(out,");\n"
1522                                 "\telse\n"
1523                                 "\t\treturn (");
1524                         print_type(out,m->mtype,TRUE);
1525                         out_printf(out,")(%s);\n}\n",
1526                                 m->onerror?m->onerror:"0");
1527                 }
1528
1529                 if(!m->cbuf)
1530                         break;
1531                 if(m->line_no>0)
1532                         out_addline_infile(out,m->line_no);
1533                 print_method(out,"static ","\n___real_",""," ","\n",
1534                              m,FALSE,FALSE);
1535                 print_method_body(m,FALSE);
1536                 break;
1537         case OVERRIDE_METHOD:
1538                 if(!m->cbuf)
1539                         break;
1540                 if(m->line_no>0)
1541                         out_addline_infile(out,m->line_no);
1542                 print_method(out,"static ","\n",""," ","\n",
1543                              m,FALSE,FALSE);
1544                 s = replace_sep(m->otype,'_');
1545                 g_strup(s);
1546                 args = get_arg_names_for_macro(m);
1547                 if(is_void) {
1548                         out_printf(out,"#define PARENT_HANDLER(%s) \\\n"
1549                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
1550                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n",
1551                                    args,s,m->id,s,m->id,args);
1552                 } else {
1553                         out_printf(out,"#define PARENT_HANDLER(%s) \\\n"
1554                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
1555                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n"
1556                                    "\t\t(",
1557                                    args,s,m->id,s,m->id,args);
1558                         out_printf(out,"(");
1559                         print_type(out,m->mtype,TRUE);
1560                         out_printf(out,")%s))\n",
1561                                    m->onerror?m->onerror:"0");
1562                 }
1563                 g_free(args);
1564                 g_free(s);
1565                 print_method_body(m,TRUE);
1566                 out_printf(out,"#undef PARENT_HANDLER\n");
1567                 break;
1568         default:
1569                 break;
1570         }
1571 }
1572
1573 static void
1574 open_files(void)
1575 {
1576         char *outfile,*outfileh,*outfileph;
1577
1578         if(!for_cpp)
1579                 outfile = g_strconcat(filebase,".c",NULL);
1580         else
1581                 outfile = g_strconcat(filebase,".cc",NULL);
1582         if(no_touch_headers)
1583                 outfileh = g_strconcat("#gob#",filebase,".h#gob#",NULL);
1584         else
1585                 outfileh = g_strconcat(filebase, ".h", NULL);
1586
1587         if((privates > 0 || protecteds > 0 || always_private_header) &&
1588            !no_private_header)
1589                 outfileph = g_strconcat(filebase, "-private.h", NULL);
1590         else
1591                 outfileph = NULL;
1592
1593         
1594         if(no_write) {
1595                 devnull = fopen("/dev/null", "w");
1596                 if(!devnull)
1597                         g_error("Cannot open null device");
1598                 out = devnull;
1599                 outh = devnull;
1600                 if(outfileph)
1601                         outph = devnull;
1602         } else {
1603                 out = fopen(outfile, "w");
1604                 if(!out) {
1605                         g_error("Cannot open outfile: %s", outfile);
1606                 }
1607                 outh = fopen(outfileh, "w");
1608                 if(!outh)
1609                         g_error("Cannot open outfile: %s", outfileh);
1610                 if(outfileph) {
1611                         outph = fopen(outfileph, "w");
1612                         if(!outph)
1613                                 g_error("Cannot open outfile: %s", outfileh);
1614                 }
1615         }
1616 }
1617
1618 static void
1619 put_argument_nongnu_wrappers(Class *c)
1620 {
1621         GList *li;
1622
1623         if(arguments<0)
1624                 return;
1625
1626         for(li=c->nodes;li;li=g_list_next(li)) {
1627                 Node *n = li->data;
1628                 Argument *a = (Argument *)n;
1629                 char *aname;
1630                 char *cast;
1631
1632                 if(n->type != ARGUMENT_NODE)
1633                         continue;
1634
1635                 aname = g_strdup(a->name);
1636                 g_strup(aname);
1637
1638                 if(a->atype)
1639                         cast = get_type(a->atype, TRUE);
1640                 else
1641                         cast = g_strdup(get_cast(a->gtktype, TRUE));
1642
1643                 if(cast) {
1644                         if(a->set)
1645                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1646                                            "\"%s\",(%s)(arg)\n",
1647                                            macrobase, aname, a->name, cast);
1648                         if(a->get)
1649                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1650                                            "\"%s\",(%s*)(arg)\n",
1651                                            macrobase, aname, a->name, cast);
1652                 } else {
1653                         if(a->set)
1654                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1655                                            "\"%s\",(arg)\n",
1656                                            macrobase, aname, a->name);
1657                         if(a->get)
1658                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1659                                            "\"%s\",(arg)\n",
1660                                            macrobase, aname, a->name);
1661                 }
1662                 g_free(cast);
1663                 g_free(aname);
1664         }
1665 }
1666
1667 static void
1668 put_argument_gnu_wrappers(Class *c)
1669 {
1670         GList *li;
1671
1672         if(arguments<0)
1673                 return;
1674
1675         for(li=c->nodes;li;li=g_list_next(li)) {
1676                 Node *n = li->data;
1677                 Argument *a = (Argument *)n;
1678                 char *s;
1679                 char *cast;
1680                 if(n->type != ARGUMENT_NODE)
1681                         continue;
1682                 s = g_strdup(a->name);
1683                 g_strup(s);
1684                 if(a->atype)
1685                         cast = get_type(a->atype,TRUE);
1686                 else
1687                         cast = g_strdup(get_cast(a->gtktype, TRUE));
1688                 if(cast) {
1689                         if(a->set)
1690                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1691                                            "\"%s\",({%sz = (arg); z;})\n",
1692                                            macrobase, s, a->name, cast);
1693                         if(a->get)
1694                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1695                                            "\"%s\",({%s*z = (arg); z;})\n",
1696                                            macrobase, s, a->name, cast);
1697                 } else {
1698                         if(a->set)
1699                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1700                                            "\"%s\",(arg)\n",
1701                                            macrobase, s, a->name);
1702                         if(a->get)
1703                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1704                                            "\"%s\",(arg)\n",
1705                                            macrobase, s, a->name);
1706                 }
1707                 g_free(cast);
1708                 g_free(s);
1709         }
1710 }
1711
1712 static void
1713 print_ccode_block(CCode *cc)
1714 {
1715         FILE *fp;
1716         switch(cc->cctype) {
1717         case HT_CCODE:
1718                 /* HT code is printed exactly like normal header
1719                    code but is printed before */
1720         case H_CCODE:
1721                 fp = outh;
1722                 out_printf(fp, "\n");
1723                 break;
1724         case AT_CCODE:
1725                 /* AT code is printed exactly like normal 'all'
1726                    code but is printed before */
1727         case A_CCODE:
1728                 if(outph) {
1729                         out_printf(outph, "\n");
1730                         out_printf(outph, "%s\n", cc->cbuf);
1731                         out_addline_infile(outph, cc->line_no);
1732                         out_addline_outfile(outph);
1733                 }
1734                 out_printf(outh, "\n");
1735                 out_printf(outh, "%s\n", cc->cbuf);
1736                 fp = out;
1737                 out_printf(fp, "\n");
1738                 out_addline_infile(fp, cc->line_no);
1739                 break;
1740         default:
1741         case C_CCODE:
1742                 fp = out;
1743                 out_printf(fp,"\n");
1744                 out_addline_infile(fp, cc->line_no);
1745                 break;
1746         case PH_CCODE:
1747                 if(outph)
1748                         fp = outph;
1749                 else
1750                         fp = out;
1751                 out_printf(fp, "\n");
1752                 out_addline_infile(fp, cc->line_no);
1753                 break;
1754         }
1755         out_printf(fp, "%s\n", cc->cbuf);
1756         if(cc->cctype == C_CCODE ||
1757            cc->cctype == A_CCODE ||
1758            cc->cctype == AT_CCODE ||
1759            cc->cctype == PH_CCODE)
1760                 out_addline_outfile(fp);
1761 }
1762
1763 static void
1764 print_class_block(Class *c)
1765 {
1766         GList *l;
1767         char *s;
1768         gboolean printed_private = FALSE;
1769
1770         if(any_special) {
1771                 out_printf(out, "/* utility types we may need */\n");
1772                 if(special_array[SPECIAL_2POINTER])
1773                         out_printf(out, "typedef struct { "
1774                                    "gpointer a; gpointer b; "
1775                                    "} ___twopointertype;\n");
1776                 if(special_array[SPECIAL_3POINTER])
1777                         out_printf(out, "typedef struct { "
1778                                    "gpointer a; gpointer b; "
1779                                    "gpointer c; "
1780                                    "} ___threepointertype;\n");
1781                 if(special_array[SPECIAL_INT_POINTER])
1782                         out_printf(out, "typedef struct { "
1783                                    "gint a; gpointer b; "
1784                                    "} ___intpointertype;\n");
1785                 out_printf(out, "\n");
1786         }
1787
1788         out_printf(outh, "\n/*\n"
1789                    " * Type checking and casting macros\n"
1790                    " */\n");
1791         out_printf(outh,"#define %s\t"
1792                    "(%s_get_type())\n",
1793                    macrotype,funcbase);
1794         out_printf(outh,"#define %s(obj)\t"
1795                    "GTK_CHECK_CAST((obj),%s_get_type(),%s)\n",
1796                    macrobase,funcbase,typebase);
1797         out_printf(outh,"#define %s_CLASS(klass)\t"
1798                    "GTK_CHECK_CLASS_CAST((klass),%s_get_type(),%sClass)\n",
1799                    macrobase,funcbase,typebase);
1800         out_printf(outh,"#define %s(obj)\t"
1801                    "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
1802                    macrois,funcbase);
1803
1804         out_printf(out, "/* self casting macros */\n");
1805         out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
1806         out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
1807         out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n", macrobase);
1808
1809         if(privates>0) {
1810                 out_printf(outh, "\n/* Private structure type */\n");
1811                 out_printf(outh,"typedef struct _%sPrivate %sPrivate;\n",
1812                            typebase,typebase);
1813         }
1814
1815         out_printf(outh, "\n/*\n"
1816                    " * Main object structure\n"
1817                    " */\n");
1818         s = replace_sep(c->otype,'_');
1819         g_strup(s);
1820         out_printf(outh,"#ifndef __TYPEDEF_%s__\n"
1821                    "#define __TYPEDEF_%s__\n",s,s);
1822         g_free(s);
1823         out_printf(outh,"typedef struct _%s %s;\n"
1824                    "#endif\n",typebase,typebase);
1825         out_printf(outh,"struct _%s {\n\t%s __parent__;\n",
1826                    typebase,ptypebase);
1827         for(l=c->nodes;l;l=g_list_next(l)) {
1828                 static gboolean printed_public = FALSE;
1829                 Node *n = l->data;
1830                 Variable *v = (Variable *)n;
1831                 if(n->type == VARIABLE_NODE &&
1832                    v->scope == PUBLIC_SCOPE) {
1833                         if(!printed_public) {
1834                                 out_printf(outh,"\t/*< public >*/\n");
1835                                 printed_public = TRUE;
1836                         }
1837                         put_variable((Variable *)n,outh);
1838                 }
1839         }
1840         /* put protecteds always AFTER publics */
1841         for(l=c->nodes;l;l=g_list_next(l)) {
1842                 Node *n = l->data;
1843                 Variable *v = (Variable *)n;
1844                 if(n->type == VARIABLE_NODE &&
1845                    v->scope == PROTECTED_SCOPE) {
1846                         if(!printed_private) {
1847                                 out_printf(outh,"\t/*< private >*/\n");
1848                                 printed_private = TRUE;
1849                         }
1850                         put_variable((Variable *)n,outh);
1851                 }
1852         }
1853         if(privates>0) {
1854                 if(!printed_private)
1855                         out_printf(outh,"\t/*< private >*/\n");
1856                 out_printf(outh,"\t%sPrivate *_priv;\n",typebase);
1857         }
1858         out_printf(outh,"};\n");
1859
1860         if(privates>0) {
1861                 FILE *outfp;
1862
1863                 /* if we are to stick this into the private
1864                    header, if not stick it directly into the
1865                    C file */
1866                 if(outph) 
1867                         outfp = outph;
1868                 else
1869                         outfp = out;
1870
1871                 out_printf(outfp,"struct _%sPrivate {\n",
1872                            typebase);
1873                 for(l=c->nodes;l;l=l->next) {
1874                         Node *n = l->data;
1875                         Variable *v = (Variable *)n;
1876                         if(n->type == VARIABLE_NODE &&
1877                            v->scope == PRIVATE_SCOPE) {
1878                                 out_addline_infile(outfp,v->line_no);
1879                                 put_variable(v,outfp);
1880                         }
1881                 }
1882                 out_addline_outfile(outfp);
1883                 out_printf(outfp,"};\n");
1884         }
1885
1886         out_printf(outh, "\n/*\n"
1887                    " * Class definition\n"
1888                    " */\n");
1889         out_printf(outh,"typedef struct _%sClass %sClass;\n",
1890                    typebase,typebase);
1891         out_printf(outh,
1892                    "struct _%sClass {\n\t%sClass __parent__;\n",
1893                    typebase,ptypebase);
1894         for(l=c->nodes;l;l=g_list_next(l)) {
1895                 Node *n = l->data;
1896                 if(n->type == METHOD_NODE)
1897                         put_vs_method((Method *)n);
1898         }
1899         out_printf(outh,"};\n\n");
1900
1901         out_printf(out,"/* here are local prototypes */\n");
1902         if(arguments>0) {
1903                 out_printf(out,"static void ___object_set_arg "
1904                            "(GtkObject *object, GtkArg *arg, "
1905                            "guint arg_id);\n"
1906                            "static void ___object_get_arg "
1907                            "(GtkObject *object, GtkArg *arg, "
1908                            "guint arg_id);\n");
1909         }
1910
1911         out_printf(outh, "\n/*\n"
1912                    " * Public methods\n"
1913                    " */\n");
1914
1915         out_printf(outh,"guint\t%s_get_type\t(void);\n",funcbase);
1916         for(l=c->nodes;l;l=g_list_next(l)) {
1917                 Node *n = l->data;
1918                 if(n->type == METHOD_NODE) {
1919                         put_pub_method((Method *)n);
1920                         put_prot_method((Method *)n);
1921                         put_priv_method_prot((Method *)n);
1922                 }
1923         }
1924
1925 /* this idea is less and less apealing to me */
1926 #if 0
1927         if(!no_signal_connect) {
1928                 if(signals>0) {
1929                         out_printf(outh, "\n/*\n"
1930                                    " * Signal connection methods\n"
1931                                    " */\n");
1932                 }
1933
1934                 for(l=c->nodes;l;l=g_list_next(l)) {
1935                         Node *n = l->data;
1936                         if(n->type == METHOD_NODE)
1937                                 put_signal_connect((Method *)n);
1938                 }
1939         }
1940 #endif
1941
1942
1943         /* argument wrapping macros */
1944         if(arguments>0 && !no_gnu) {
1945                 out_printf(outh, "\n/*\n"
1946                            " * Argument wrapping macros\n"
1947                            " */\n");
1948                 out_printf(outh,"#ifdef __GNUC__\n");
1949                 put_argument_gnu_wrappers(c);
1950                 out_printf(outh,"#else /* __GNUC__ */\n");
1951                 put_argument_nongnu_wrappers(c);
1952                 out_printf(outh,"#endif /* __GNUC__ */\n\n");
1953         } else if(arguments>0 && no_gnu) {
1954                 out_printf(outh, "\n/*\n"
1955                            " * Argument wrapping macros\n"
1956                            " */\n");
1957                 put_argument_nongnu_wrappers(c);
1958         }
1959
1960         if(signals>0) {
1961                 for(l=c->nodes;l;l=g_list_next(l)) {
1962                         Node *n = l->data;
1963                         if(n->type == METHOD_NODE)
1964                                 add_signal_prots((Method *)n);
1965                 }
1966         }
1967
1968         add_enums(c);
1969
1970         add_get_type();
1971
1972         if(any_method_to_alias(c)) {
1973                 if(no_gnu)
1974                         make_method_nongnu_aliases(c);
1975                 else {
1976                         out_printf(out,"\n#ifdef __GNUC__\n");
1977                         make_method_gnu_aliases(c);
1978                         out_printf(out,"#else /* __GNUC__ */\n");
1979                         make_method_nongnu_aliases(c);
1980                         out_printf(out,"#endif /* __GNUC__ */\n\n");
1981                 }
1982         }
1983
1984         out_printf(out,"/* a macro for creating a new object of our type */\n");
1985         out_printf(out,
1986                    "#define GET_NEW ((%s *)gtk_type_new(%s_get_type()))\n\n",
1987                    typebase, funcbase);
1988
1989         add_inits(c);
1990
1991         if(arguments>0) {
1992                 add_getset_arg(c, TRUE);
1993                 add_getset_arg(c, FALSE);
1994         }
1995
1996         for(l=c->nodes;l;l=g_list_next(l)) {
1997                 Node *n = l->data;
1998                 if(n->type == METHOD_NODE)
1999                         put_method((Method *)n);
2000         }
2001
2002         add_bad_hack_to_avoid_unused_warnings(c);
2003 }
2004
2005 static void
2006 print_version_macros(void)
2007 {
2008         int major=0, minor=0, pl=0;
2009         sscanf(VERSION, "%d.%d.%d", &major, &minor, &pl);
2010
2011         out_printf(out, "#define GOB_VERSION_MAJOR %d\n", major);
2012         out_printf(out, "#define GOB_VERSION_MINOR %d\n", minor);
2013         out_printf(out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
2014 }
2015
2016 static void
2017 print_file_comments(void)
2018 {
2019         time_t curtime;
2020         time(&curtime);
2021         out_printf(outh, "/* Generated by GOB (v%s)"
2022                    "   (do not edit directly) */\n\n", VERSION);
2023         if(outph)
2024                 out_printf(outph, "/* Generated by GOB (v%s)"
2025                            "   (do not edit directly) */\n\n", VERSION);
2026         out_printf(out, "/* Generated by GOB (v%s) on %s"
2027                    "   (do not edit directly) */\n\n",
2028                    VERSION, ctime(&curtime));
2029 }
2030
2031 static void
2032 print_includes(void)
2033 {
2034         gboolean found_header;
2035         char *p;
2036
2037         p = g_strconcat(filebase, ".h", NULL);
2038         found_header = TRUE;
2039         if(!g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
2040                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
2041                 found_header = FALSE;
2042         }
2043         g_free(p);
2044
2045         /* if we are creating a private header see if it was included */
2046         if(outph) {
2047                 p = g_strconcat(filebase, "-private.h", NULL);
2048                 if(!g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
2049                         out_printf(out,"#include \"%s-private.h\"\n\n",
2050                                    filebase);
2051                         if(found_header)
2052                                 print_error(TRUE,
2053                                             "Implicit private header include "
2054                                             "added to top of\n"
2055                                             "\tsource file, while public "
2056                                             "header is at a custom location, "
2057                                             "you should\n"
2058                                             "\texplicitly include "
2059                                             "the private header below the "
2060                                             "public one.", 0);
2061                 }
2062                 g_free(p);
2063         }
2064 }
2065
2066 static void
2067 print_header_prefixes(void)
2068 {
2069         char *p;
2070
2071         p = replace_sep(((Class *)class)->otype, '_');
2072         g_strup(p);
2073         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
2074         if(outph)
2075                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
2076                            "#define __%s_PRIVATE_H__\n\n"
2077                            "#include \"%s.h\"\n\n", p, p, filebase);
2078         g_free(p);
2079
2080         if(!no_extern_c) {
2081                 out_printf(outh, "#ifdef __cplusplus\n"
2082                            "extern \"C\" {\n"
2083                            "#endif /* __cplusplus */\n\n");
2084                 if(outph)
2085                         out_printf(outph, "#ifdef __cplusplus\n"
2086                                    "extern \"C\" {\n"
2087                                    "#endif /* __cplusplus */\n\n");
2088         }
2089 }
2090
2091 static void
2092 print_header_postfixes(void)
2093 {
2094         if(!no_extern_c)
2095                 out_printf(outh,"\n#ifdef __cplusplus\n"
2096                            "}\n"
2097                            "#endif /* __cplusplus */\n");
2098         out_printf(outh,"\n#endif");
2099         if(outph) {
2100                 if(!no_extern_c)
2101                         out_printf(outph,"\n#ifdef __cplusplus\n"
2102                                    "}\n"
2103                                    "#endif /* __cplusplus */\n");
2104                 out_printf(outph,"\n#endif");
2105         }
2106 }
2107
2108 static void
2109 print_all_top(void)
2110 {
2111         GList *li;
2112
2113         /* print the AT_CCODE blocks */
2114         for(li=nodes;li;li=g_list_next(li)) {
2115                 Node *node = li->data;
2116                 if(node->type == CCODE_NODE) {
2117                         CCode *cc = (CCode *)node;
2118                         if(cc->cctype==AT_CCODE)
2119                                 print_ccode_block((CCode *)node);
2120                 }
2121         }
2122 }
2123
2124 static void
2125 print_header_top(void)
2126 {
2127         GList *li;
2128
2129         /* mandatory include */
2130         out_printf(outh,"#include <gtk/gtk.h>\n\n");
2131
2132         /* print the HT_CCODE blocks */
2133         for(li=nodes;li;li=g_list_next(li)) {
2134                 Node *node = li->data;
2135                 if(node->type == CCODE_NODE) {
2136                         CCode *cc = (CCode *)node;
2137                         if(cc->cctype==HT_CCODE)
2138                                 print_ccode_block((CCode *)node);
2139                 }
2140         }
2141 }
2142
2143 static void
2144 generate_outfiles(void)
2145 {
2146         GList *li;
2147
2148         print_file_comments();
2149
2150         print_all_top();
2151
2152         print_header_top();
2153
2154         print_header_prefixes();
2155
2156         print_version_macros();
2157
2158         print_includes();
2159
2160         for(li=nodes;li;li=g_list_next(li)) {
2161                 Node *node = li->data;
2162                 if(node->type == CCODE_NODE) {
2163                         CCode *cc = (CCode *)node;
2164                         if(cc->cctype!=HT_CCODE)
2165                                 print_ccode_block((CCode *)node);
2166                 } else if(node->type == CLASS_NODE) {
2167                         print_class_block((Class *)node);
2168                 } else
2169                         g_assert_not_reached();
2170         }
2171
2172         print_header_postfixes();
2173 }
2174
2175 static void
2176 print_help(void)
2177 {
2178         fprintf(stderr,"Gob version %s\n\n",VERSION);
2179         fprintf(stderr,"Options:\n"
2180                 "\t--help,-h,-?            Display this help\n"
2181                 "\t--version               Display version\n"
2182                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
2183                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
2184                 "\t--for-cpp               Create C++ files\n"
2185                 "\t--no-extern-c           Never print extern \"C\" into the "
2186                                           "header\n"
2187                 "\t--no-gnu                Never use GNU extentions\n"
2188                 "\t--no-touch-headers      Don't touch headers unless they "
2189                                           "really changed\n"
2190                 "\t--always-private-header Always create a private header "
2191                                           "file,\n"
2192                 "\t                        even if it would be empty\n"
2193                 "\t--no-private-header     Don't create a private header, "
2194                                           "put private\n"
2195                 "\t                        structure and protected "
2196                                           "prototypes inside c file\n"
2197                 "\t--no-write,-n           Don't write output files, just "
2198                                           "check syntax\n"
2199                 "\t--no-lines              Don't print '#line' to output\n");
2200 }
2201
2202 static void
2203 parse_options(int argc, char *argv[])
2204 {
2205         int i;
2206         int got_file = FALSE;
2207         int no_opts = FALSE;
2208
2209         filename = NULL;
2210
2211         for(i=1;i<argc;i++) {
2212                 if(no_opts || argv[i][0]!='-') {
2213                         /*must be a file*/
2214                         if(got_file) {
2215                                 fprintf(stderr, "Specify only one file!\n");
2216                                 print_help();
2217                                 exit(1);
2218                         }
2219                         filename = argv[i];
2220                         got_file = TRUE;
2221                 } else if(strcmp(argv[i],"--help")==0) {
2222                         print_help();
2223                         exit(0);
2224                 } else if(strcmp(argv[i],"--version")==0) {
2225                         fprintf(stderr, "Gob version %s\n", VERSION);
2226                         exit(0);
2227                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
2228                         exit_on_warn = TRUE;
2229                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
2230                         exit_on_warn = FALSE;
2231                 } else if(strcmp(argv[i], "--for-cpp")==0) {
2232                         for_cpp = TRUE;
2233                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
2234                         no_touch_headers = TRUE;
2235                 } else if(strcmp(argv[i], "--always-private-header")==0) {
2236                         no_private_header = FALSE;
2237                         always_private_header = TRUE;
2238                 } else if(strcmp(argv[i], "--no-private-header")==0) {
2239                         always_private_header = FALSE;
2240                         no_private_header = TRUE;
2241                 } else if(strcmp(argv[i], "--no-gnu")==0) {
2242                         no_gnu = TRUE;
2243                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
2244                         no_extern_c = TRUE;
2245                 } else if(strcmp(argv[i], "--no-write")==0) {
2246                         no_write = TRUE;
2247                 } else if(strcmp(argv[i], "--no-lines")==0) {
2248                         no_lines = TRUE;
2249                 } else if(strcmp(argv[i], "--")==0) {
2250                         /*further arguments are files*/
2251                         no_opts = TRUE;
2252                 } else if(strncmp(argv[i], "--",2)==0) {
2253                         /*unknown long option*/
2254                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
2255                         print_help();
2256                         exit(1);
2257                 } else {
2258                         /*by now we know we have a string starting with
2259                           - which is a short option string*/
2260                         char *p = argv[i]+1;
2261                         for(p=argv[i]+1; *p; p++) {
2262                                 switch(*p) {
2263                                 case 'w':
2264                                         exit_on_warn=TRUE;
2265                                         break;
2266                                 case 'n':
2267                                         no_write = TRUE;
2268                                         break;
2269                                 case 'h':
2270                                 case '?':
2271                                         print_help();
2272                                         exit(0);
2273                                 default:
2274                                         fprintf(stderr,
2275                                                 "Unknown option '%c'!\n", *p);
2276                                         print_help();
2277                                         exit(1);
2278                                 }
2279                         }
2280                 }
2281         }
2282 }
2283
2284 /* this is a somewhat ugly hack, but it appears to work */
2285 static void
2286 compare_and_move_header(void)
2287 {
2288         char *hfnew = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
2289         char *hf = g_strconcat(filebase, ".h", NULL);
2290         struct stat s;
2291         if(stat(hf,&s)==0) {
2292                 char *s;
2293                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
2294                 if(system(s)==0) {
2295                         if(unlink(hfnew)!=0)
2296                                 print_error(FALSE,
2297                                             "Can't remove new header file", 0);
2298                         g_free(hfnew);
2299                         g_free(hf);
2300                         g_free(s);
2301                         return;
2302                 }
2303                 g_free(s);
2304                 if(unlink(hf)!=0)
2305                         print_error(FALSE, "Can't remove old header file", 0);
2306         }
2307         if(rename(hfnew,hf)!=0)
2308                 print_error(FALSE, "Can't rename new header file", 0);
2309         g_free(hfnew);
2310         g_free(hf);
2311 }
2312
2313 int
2314 main(int argc, char *argv[])
2315 {
2316         parse_options(argc, argv);
2317         
2318         if(filename) {
2319                 yyin = fopen(filename, "r");
2320                 if(!yyin) {
2321                         fprintf(stderr, "Error: can't open file '%s'\n",
2322                                 filename);
2323                         exit(1);
2324                 }
2325         } else
2326                 filename = "stdin";
2327
2328         /*yydebug = 1;*/
2329         if(yyparse()!=0)
2330                 g_error("Parsing errors, quitting");
2331         if(!class)
2332                 print_error(FALSE, " no class defined", 0);
2333         
2334
2335         exit_on_error = FALSE;
2336
2337         signals = count_signals((Class *)class);
2338         arguments = count_arguments((Class *)class);
2339         overrides = count_overrides((Class *)class);
2340         privates = count_privates((Class *)class);
2341         protecteds = count_protecteds((Class *)class);
2342         destructors = count_destructors((Class *)class);
2343         initializers = count_initializers((Class *)class);
2344
2345         make_bases();
2346         make_inits((Class *)class);
2347         if(privates>0)
2348                 make_finalize((Class *)class);
2349         check_bad_symbols((Class *)class);
2350         check_duplicate_symbols((Class *)class);
2351         check_duplicate_signals_args((Class *)class);
2352         check_public_new((Class *)class);
2353         check_vararg((Class *)class);
2354         check_firstarg((Class *)class);
2355         check_nonvoidempty((Class *)class);
2356         check_signal_args((Class *)class);
2357         check_argument_types((Class *)class);
2358
2359         exit_on_error = TRUE;
2360         
2361         if(got_error)
2362                 exit(1);
2363
2364         any_special = setup_special_array((Class *)class, special_array);
2365
2366         open_files();
2367         
2368         generate_outfiles();
2369
2370         if(devnull)
2371                 fclose(devnull);
2372         else {
2373                 fclose(out);
2374                 fclose(outh);
2375                 if(outph)
2376                         fclose(outph);
2377         }
2378
2379         if(no_touch_headers && !no_write)
2380                 compare_and_move_header();
2381         
2382         return 0;
2383 }