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