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