]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
Release 1.0.11
[gob-dx.git] / src / main.c
1 /* GOB C Preprocessor
2  * Copyright (C) 1999,2000 the Free Software Foundation.
3  * Copyright (C) 2000 Eazel, Inc.
4  *
5  * Author: George Lebl
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the  Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20  * USA.
21  */
22
23 #include "config.h"
24 #include <glib.h>
25 #include <time.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31
32 #include "treefuncs.h"
33 #include "parse.h"
34 #include "out.h"
35 #include "util.h"
36 #include "checks.h"
37
38 #include "main.h"
39
40 char *filename = NULL;
41
42 int yyparse(void);
43
44 extern int yydebug;
45 extern FILE * yyin;
46 extern Node *class;
47 extern GList *nodes;
48
49 extern GList *include_files;
50
51 extern GHashTable *gtk_doc_hash;
52
53 char *filebase;
54 static char *funcbase;
55 static char *pfuncbase;
56 static char *macrobase;
57 static char *macrois;
58 static char *macrotype;
59 static char *typebase;
60 static char *ptypebase;
61
62 static int signals = 0; /* number of signals */
63 static int set_arguments = 0; /* number of named (set) arguments */
64 static int get_arguments = 0; /* number of named (get) arguments */
65 static int overrides = 0; /* number of override methods */
66 static int privates = 0; /* number of private data members */
67 static int protecteds = 0; /* number of protected methods */
68 static int destructors = 0; /* number of variable destructors */
69 static int initializers = 0; /* number of variable initializers */
70 static gboolean overrode_get_type = FALSE; /* provided your won _get_type */
71
72 static gboolean made_aliases = FALSE;  /* if we made any shorthand aliases
73                                           and need the REALLY UGLY HACK to
74                                           avoid warnings */
75
76 /* the special variable types we need to define */
77 static gboolean special_array[SPECIAL_LAST] = {0};
78 static gboolean any_special = FALSE;
79
80 static gboolean need_destroy = FALSE;
81 static Method * destroy_handler = NULL;
82
83 static gboolean need_finalize = FALSE;
84 static Method * finalize_handler = NULL;
85
86 FILE *out = NULL;
87 FILE *outh = NULL;
88 FILE *outph = NULL;
89 FILE *devnull = NULL;
90
91 gboolean no_touch_headers = FALSE;
92 gboolean for_cpp = FALSE;
93 gboolean no_gnu = FALSE;
94 gboolean exit_on_warn = FALSE;
95 gboolean exit_on_error = TRUE;
96 gboolean got_error = FALSE;
97 gint private_header = PRIVATE_HEADER_ONDEMAND;
98 gboolean no_extern_c = FALSE;
99 gboolean no_write = FALSE;
100 gboolean no_lines = FALSE;
101 gboolean no_self_alias = FALSE;
102 gboolean no_kill_underscores = FALSE;
103 gboolean always_private_struct = FALSE;
104
105 int method_unique_id = 1;
106
107 static void
108 make_bases(void)
109 {
110         filebase = replace_sep(((Class *)class)->otype, '-');
111         g_strdown(filebase);
112
113         funcbase = replace_sep(((Class *)class)->otype, '_');
114         g_strdown(funcbase);
115
116         pfuncbase = replace_sep(((Class *)class)->ptype, '_');
117         g_strdown(pfuncbase);
118
119         macrobase = replace_sep(((Class *)class)->otype, '_');
120         g_strup(macrobase);
121         
122         macrois = make_pre_macro(((Class *)class)->otype, "IS");
123         macrotype = make_pre_macro(((Class *)class)->otype, "TYPE");
124
125         typebase = remove_sep(((Class *)class)->otype);
126
127         ptypebase = remove_sep(((Class *)class)->ptype);
128 }
129
130 static char *
131 get_type(const Type *t, gboolean postfix_to_stars)
132 {
133         char *s;
134         int i;
135         int extra;
136         GString *gs;
137
138         s = remove_sep(t->name);
139         gs = g_string_new(s);
140         g_free(s);
141
142         extra = 0;
143         if(postfix_to_stars) {
144                 const char *p;
145                 /*XXX: this is ugly perhaps we can do this whole postfix thing
146                   in a nicer way, we just count the number of '[' s and from
147                   that we deduce the number of dimensions, so that we can print
148                   that many stars */
149                 for(p=t->postfix; p && *p; p++)
150                         if(*p == '[') extra++;
151         }
152         g_string_append_c(gs, ' ');
153
154         if(t->pointer) {
155                 g_string_append(gs, t->pointer);
156                 for(i=0; i < extra; i++)
157                         g_string_append_c(gs, '*');
158                 g_string_append_c(gs, ' ');
159         }
160         
161         s = gs->str;
162         g_string_free(gs, FALSE);
163         return s;
164 }
165
166 static char *
167 get_gtk_doc(const char *id)
168 {
169         char *val;
170
171         if(!gtk_doc_hash)
172                 return NULL;
173
174         val = g_hash_table_lookup(gtk_doc_hash, id);
175         if(val)
176                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
177                                        funcbase, get_real_id(id), val);
178         val = g_hash_table_lookup(gtk_doc_hash, get_real_id(id));
179         if(val)
180                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
181                                        funcbase, get_real_id(id), val);
182         return NULL;
183 }
184
185 static void
186 print_type(FILE *fp, const Type *t, gboolean postfix_to_stars)
187 {
188         char *s;
189
190         s = get_type(t, postfix_to_stars);
191         out_printf(fp, "%s", s); 
192         g_free(s);
193 }
194
195
196 static void
197 print_method (FILE *fp,
198               const char *typeprefix,
199               const char *nameprefix,
200               const char *subnameprefix,
201               const char *namepostfix,
202               const char *afterargs,
203               const char *postfix,
204               const Method *m,
205               gboolean one_arg_per_line,
206               gboolean no_funcbase,
207               gboolean kill_underscore)
208 {
209         GList *li;
210         const char *id;
211
212         out_printf(fp, "%s", typeprefix); 
213         print_type(fp, m->mtype, TRUE);
214
215         if(kill_underscore)
216                 id = get_real_id(m->id);
217         else
218                 id = m->id;
219
220         if(no_funcbase)
221                 out_printf(fp, "%s%s%s%s(",
222                            nameprefix, subnameprefix, id, namepostfix); 
223         else
224                 out_printf(fp, "%s%s_%s%s%s(",
225                            nameprefix, funcbase, subnameprefix, id,
226                            namepostfix); 
227         
228         if(m->args) {
229                 for(li=m->args; li; li=g_list_next(li)) {
230                         FuncArg *arg = li->data;
231                         print_type(fp, arg->atype, FALSE);
232                         if(li->next)
233                                 out_printf(fp, "%s%s,%s", arg->name,
234                                            arg->atype->postfix ?
235                                            arg->atype->postfix : "",
236                                            one_arg_per_line ? "\n\t\t\t\t\t" : " ");
237                         else
238                                 out_printf(fp, "%s%s", arg->name,
239                                            arg->atype->postfix ?
240                                            arg->atype->postfix : ""); 
241                 }
242                 if(m->vararg)
243                         out_printf(fp, ",%s...",
244                                    one_arg_per_line ? "\n\t\t\t\t\t" : " "); 
245         } else {
246                 out_printf(fp, "void"); 
247         }
248         out_printf(fp, "%s)%s", afterargs, postfix); 
249 }
250
251 static gboolean
252 any_method_to_alias(Class *c)
253 {
254         GList *li;
255         
256         for(li=c->nodes;li;li=g_list_next(li)) {
257                 Node *node = li->data;
258                 if(node->type == METHOD_NODE) {
259                         Method *m = (Method *)node;
260                         
261                         if(m->method == INIT_METHOD ||
262                            m->method == CLASS_INIT_METHOD ||
263                            m->method == OVERRIDE_METHOD)
264                                 continue;
265
266                         return TRUE;
267                 }
268         }
269         return FALSE;
270 }
271
272
273 /* just the vararg macros, we use the same func pointers for these as in non-gnu */
274 static void
275 make_method_gnu_aliases(Class *c)
276 {
277         GList *li;
278         
279         for(li = c->nodes; li != NULL; li = li->next) {
280                 Node *node = li->data;
281                 if(node->type == METHOD_NODE) {
282                         Method *m = (Method *)node;
283                         
284                         if(m->method == INIT_METHOD ||
285                            m->method == CLASS_INIT_METHOD ||
286                            m->method == OVERRIDE_METHOD)
287                                 continue;
288
289                         /* in C++ mode don't alias new */
290                         if(for_cpp && strcmp(m->id, "new")==0)
291                                 continue;
292
293                         if(m->args != NULL)
294                                 out_printf(out, "#define %s(args...) "
295                                            "%s_%s(args)\n", m->id,
296                                            funcbase, get_real_id(m->id));
297                         else
298                                 out_printf(out, "#define %s() "
299                                            "%s_%s()\n", m->id,
300                                            funcbase, get_real_id(m->id));
301                 }
302         }
303 }
304
305 static void
306 make_method_nongnu_aliases(Class *c)
307 {
308         GList *li;
309
310         gboolean local_made_aliases = FALSE;
311         
312         for(li=c->nodes; li; li=g_list_next(li)) {
313                 Node *node = li->data;
314                 if(node->type == METHOD_NODE) {
315                         Method *m = (Method *)node;
316                         
317                         if(m->method == INIT_METHOD ||
318                            m->method == CLASS_INIT_METHOD ||
319                            m->method == OVERRIDE_METHOD)
320                                 continue;
321
322                         /* in C++ mode don't alias new */
323                         if(for_cpp && strcmp(m->id, "new")==0)
324                                 continue;
325
326                         if( ! local_made_aliases)
327                                 out_printf(out, "\n/* Short form pointers */\n");
328
329                         print_method(out, "static ", "(* const ", "", ") ",
330                                      "", "",
331                                      m, FALSE, TRUE, FALSE);
332                         out_printf(out, " = %s_%s;\n", funcbase,
333                                    get_real_id(m->id));
334
335                         local_made_aliases = TRUE;
336                 }
337         }
338         if(local_made_aliases) {
339                 out_printf(out, "\n");
340                 made_aliases = TRUE;
341         }
342 }
343
344 static void
345 add_bad_hack_to_avoid_unused_warnings(Class *c)
346 {
347         GList *li;
348
349         /* if we haven't had any methods, just return */
350         if( ! made_aliases)
351                 return;
352         
353         if( ! no_gnu)
354                 out_printf(out, "\n\n#if (!defined __GNUC__) || (defined __GNUC__ && defined __STRICT_ANSI__)\n");
355         out_printf(out,
356                    "/*REALLY BAD HACK\n"
357                    "  This is to avoid unused warnings if you don't call\n"
358                    "  some method.  I need to find a better way to do\n"
359                    "  this, not needed in GCC since we use some gcc\n"
360                    "  extentions to make saner, faster code */\n"
361                    "static void\n"
362                    "___%s_really_bad_hack_to_avoid_warnings(void)\n"
363                    "{\n", funcbase);
364         for(li=c->nodes;li;li=g_list_next(li)) {
365                 Node *node = li->data;
366                 if(node->type == METHOD_NODE) {
367                         Method *m = (Method *)node;
368                         
369                         if(m->method == INIT_METHOD ||
370                            m->method == CLASS_INIT_METHOD ||
371                            m->method == OVERRIDE_METHOD)
372                                 continue;
373
374                         /* in C++ mode we don't alias new */
375                         if(for_cpp && strcmp(m->id, "new")==0)
376                                 continue;
377
378                         out_printf(out, "\t((void (*)(void))%s)();\n", m->id);
379                 }
380         }
381         out_printf(out, "\t___%s_really_bad_hack_to_avoid_warnings();\n",
382                    funcbase);
383         if(!no_gnu)
384                 out_printf(out, "}\n#endif /* !__GNUC__ || (__GNUC__ && __STRICT_ANSI__) */\n\n");
385         else
386                 out_printf(out, "}\n\n");
387 }
388
389 static void
390 put_variable(Variable *v, FILE *fp)
391 {
392         out_printf(fp, "\t");
393         print_type(fp, v->vtype, FALSE);
394         out_printf(fp, "%s%s;", v->id,
395                    v->vtype->postfix?
396                    v->vtype->postfix:""); 
397         if(v->scope == PROTECTED_SCOPE)
398                 out_printf(fp, " /* protected */");
399         out_printf(fp, "\n");
400 }
401
402 static void
403 put_vs_method(const Method *m)
404 {
405         if(m->method != SIGNAL_LAST_METHOD &&
406            m->method != SIGNAL_FIRST_METHOD &&
407            m->method != VIRTUAL_METHOD)
408                 return;
409
410         /* if a signal mark it as such */
411         if(m->method != VIRTUAL_METHOD)
412                 print_method(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
413                              m, FALSE, TRUE, TRUE);
414         else
415                 print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
416                              m, FALSE, TRUE, TRUE);
417 }
418
419 static void
420 put_pub_method(const Method *m)
421 {
422         if(m->scope != PUBLIC_SCOPE)
423                 return;
424
425         print_method(outh, "", "\t", "", "\t", "", ";\n", m, TRUE, FALSE, TRUE);
426 }
427
428 static void
429 put_signal_macro (const Method *m, gboolean gnu)
430 {
431         char *id;
432
433         if(m->method != SIGNAL_LAST_METHOD &&
434            m->method != SIGNAL_FIRST_METHOD)
435                 return;
436
437         id = g_strdup (m->id);
438         g_strup (id);
439
440         if ( ! gnu) {
441                 out_printf (outh, "#define %s_SIGNAL_%s(func)\t"
442                             "\"%s\",GTK_SIGNAL_FUNC(func)\n",
443                             macrobase, id, get_real_id (m->id));
444         } else {
445                 out_printf (outh, "#define %s_SIGNAL_%s(func)\t"
446                             "\"%s\",GTK_SIGNAL_FUNC(({",
447                             macrobase, id, get_real_id (m->id));
448                 print_method (outh, "", "(* ___", "", ") ", ", gpointer data ",
449                               " = func; ", m, FALSE, TRUE, TRUE);
450                 out_printf (outh, "___%s; }))\n", get_real_id (m->id));
451
452         }
453         g_free (id);
454 }
455
456 static void
457 put_signal_macros (const Class *c, gboolean gnu)
458 {
459         const GList *li;
460
461         if (signals < 0)
462                 return;
463
464         for (li = c->nodes; li != NULL; li = li->next) {
465                 const Node *n = li->data;
466                 if (n->type == METHOD_NODE)
467                         put_signal_macro ((Method *)n, gnu);
468         }
469 }
470
471
472 static void
473 put_prot_method(const Method *m)
474 {
475         if(m->scope != PROTECTED_SCOPE)
476                 return;
477
478         if(outph)
479                 print_method(outph, "", "\t", "", "\t", "", ";\n",
480                              m, FALSE, FALSE, TRUE);
481         else
482                 print_method(out, "", "\t", "", "\t", "", ";\n",
483                              m, FALSE, FALSE, TRUE);
484 }
485
486 static void
487 put_priv_method_prot(Method *m)
488 {
489         if(m->method == SIGNAL_LAST_METHOD ||
490            m->method == SIGNAL_FIRST_METHOD ||
491            m->method == VIRTUAL_METHOD) {
492                 if(m->cbuf)
493                         print_method(out,
494                                      "static ", "___real_", "", " ", "", ";\n",
495                                      m, FALSE, FALSE, TRUE);
496         }
497         /* no else, here, it might still have a private prototype, it's not
498          * exclusive */
499
500         if((m->method == OVERRIDE_METHOD &&
501             m->cbuf)) {
502                 /* add unique ID */
503                 char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
504                 print_method(out, "static ", s, "", " ", "",
505                              no_gnu?";\n":" G_GNUC_UNUSED;\n",
506                              m, FALSE, FALSE, FALSE);
507                 g_free(s);
508         } else if(m->scope == PRIVATE_SCOPE ||
509                   m->method == INIT_METHOD ||
510                   m->method == CLASS_INIT_METHOD)
511                 print_method(out, "static ", "", "", " ", "",
512                              no_gnu?";\n":" G_GNUC_UNUSED;\n",
513                              m, FALSE, FALSE, TRUE);
514 }
515
516 static GList *
517 make_func_arg(char *typename, int is_class, char *name)
518 {
519         Node *node;
520         Node *type;
521         char *tn;
522         
523         if(is_class)
524                 tn = g_strconcat(typename, ":Class", NULL);
525         else
526                 tn = g_strdup(typename);
527
528         type = new_type(tn, g_strdup("*"), NULL);
529         node = new_funcarg((Type *)type, name, NULL);
530         return g_list_prepend(NULL, node);
531 }
532
533 static void
534 make_inits(Class *cl)
535 {
536         int got_class_init = FALSE;
537         int got_init = FALSE;
538         GList *li;
539         Node *node;
540         for(li=cl->nodes;li;li=g_list_next(li)) {
541                 Node *n = li->data;
542                 if(n->type == METHOD_NODE) {
543                         Method *m = (Method *)n;
544                         if(m->method == INIT_METHOD) {
545                                 if(got_init)
546                                         error_print(GOB_ERROR, m->line_no, "init defined more then once");
547                                 got_init = TRUE;
548                         } else if(m->method == CLASS_INIT_METHOD) {
549                                 if(got_class_init)
550                                         error_print(GOB_ERROR, m->line_no, "class_init defined more then once");
551                                 got_class_init = TRUE;
552                         }
553                 }
554         }
555         if(!got_class_init) {
556                 node = new_method(NO_SCOPE, CLASS_INIT_METHOD,
557                                   (Type *)new_type(g_strdup("void"),
558                                                    NULL, NULL),
559                                   NULL, NULL, NULL, g_strdup("class_init"),
560                                   make_func_arg(cl->otype, TRUE, g_strdup("c")),
561                                   NULL, NULL, NULL, 0, 0, FALSE,
562                                   method_unique_id++,
563                                   FALSE /*bonobo_x_func*/);
564                 cl->nodes = g_list_prepend(cl->nodes, node);
565         }
566         if(!got_init) {
567                 node = new_method(NO_SCOPE, INIT_METHOD,
568                                   (Type *)new_type(g_strdup("void"),
569                                                    NULL, NULL),
570                                   NULL, NULL, NULL, g_strdup("init"),
571                                   make_func_arg(cl->otype, FALSE, g_strdup("o")),
572                                   NULL, NULL, NULL, 0, 0, FALSE,
573                                   method_unique_id++,
574                                   FALSE /*bonobo_x_func*/);
575                 cl->nodes = g_list_prepend(cl->nodes, node);
576         }
577 }
578
579 static void
580 find_destroy(Class *cl)
581 {
582         GList *li;
583
584         destroy_handler = NULL;
585         for(li=cl->nodes;li;li=g_list_next(li)) {
586                 Node *n = li->data;
587                 if(n->type == METHOD_NODE) {
588                         Method *m = (Method *)n;
589                         if(m->method == OVERRIDE_METHOD &&
590                            strcmp(m->id, "destroy")==0) {
591                                 if(strcmp(m->otype, "Gtk:Object") != 0) {
592                                         error_print(GOB_ERROR, m->line_no,
593                                                     "destroy method override "
594                                                     "of class other then "
595                                                     "Gtk:Object");
596                                 }
597                                 if(g_list_length(m->args) != 1) {
598                                         error_print(GOB_ERROR, m->line_no,
599                                                     "destroy method override "
600                                                     "with more then one "
601                                                     "parameter");
602                                 }
603                                 destroy_handler = m;
604                                 break;
605                         }
606                 }
607         }
608 }
609
610 static void
611 find_finalize(Class *cl)
612 {
613         GList *li;
614
615         finalize_handler = NULL;
616         for(li=cl->nodes;li;li=g_list_next(li)) {
617                 Node *n = li->data;
618                 if(n->type == METHOD_NODE) {
619                         Method *m = (Method *)n;
620                         if(m->method == OVERRIDE_METHOD &&
621                            strcmp(m->id, "finalize")==0) {
622                                 if(strcmp(m->otype, "Gtk:Object") != 0 &&
623                                    strcmp(m->otype, "G:Object") != 0) {
624                                         error_print(GOB_ERROR, m->line_no,
625                                                     "finalize method override "
626                                                     "of class other then "
627                                                     "Gtk:Object (or G:Object"
628                                                     "for GTK+ 2.0)");
629                                 }
630                                 if(g_list_length(m->args) != 1) {
631                                         error_print(GOB_ERROR, m->line_no,
632                                                     "finalize method override "
633                                                     "with more then one "
634                                                     "parameter");
635                                 }
636                                 finalize_handler = m;
637                                 break;
638                         }
639                 }
640         }
641 }
642
643
644 /* hash of method -> name of signal prototype */
645 static GHashTable *marsh = NULL;
646
647 /* list of methods with different signal prototypes,
648    we check this list if we can use a signal prototype of a
649    previous signal method, there are only uniques here */
650 static GList *eq_signal_methods = NULL;
651
652 /* compare a list of strings */
653 static gboolean
654 is_list_equal(GList *a, GList *b)
655 {
656         for(;a && b; a=a->next, b=b->next) {
657                 if(strcmp(a->data, b->data)!=0) {
658                         return FALSE;
659                 }
660         }
661         /* the the lists were different length */
662         if(a || b)
663                 return FALSE;
664         return TRUE;
665 }
666
667 static Method *
668 find_same_type_signal(Method *m)
669 {
670         GList *li;
671         for(li=eq_signal_methods;li;li=li->next) {
672                 Method *mm = li->data;
673                 if(is_list_equal(mm->gtktypes, m->gtktypes))
674                         return mm;
675         }
676         return NULL;
677 }
678
679 static void
680 print_signal_marsal_args_gtk1 (Method *m)
681 {
682         if(strcmp(m->gtktypes->next->data, "NONE")!=0) {
683                 GList *li;
684                 int i;
685                 for(i=0, li=m->gtktypes->next;li;
686                     i++, li=g_list_next(li)) {
687                         if(!for_cpp)
688                                 out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
689                                            (char *)li->data, i);
690                         else {
691                                 out_printf(out, ",\n\t\t(%s)"
692                                            "GTK_VALUE_%s(args[%d])",
693                                            get_cast(li->data, FALSE),
694                                            (char *)li->data, i);
695                         }
696                 }
697         }
698         out_printf(out, ",\n\t\tfunc_data);\n}\n\n");
699 }
700
701 static void
702 add_marshal_gtk1 (Method *m, const char *mname)
703 {
704         out_printf(out, "\nstatic void\n"
705                 "___marshal_%s (GtkObject * object,\n"
706                 "\tGtkSignalFunc func,\n"
707                 "\tgpointer func_data,\n"
708                 "\tGtkArg * args)\n"
709                 "{\n", mname);
710         
711         if(strcmp(m->gtktypes->data, "NONE")==0) {
712                 out_printf(out, "\t___%s rfunc;\n\n"
713                         "\trfunc = (___%s)func;\n\n"
714                         "\t(*rfunc)((%s *)object", mname, mname, typebase);
715         } else {
716                 const char *retcast = get_cast(m->gtktypes->data, FALSE);
717                 gboolean is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
718                 out_printf(out,
719                            "\t___%s rfunc;\n\t"
720                            "%s *retval;\n\n"
721                            "\trfunc = (___%s)func;\n\n"
722                            "\tretval = GTK_RETLOC_%s(args[%d]);\n\n"
723                            "\t*retval = (*rfunc)((%s *)object",
724                            mname, retcast, mname,
725                            (char *)m->gtktypes->data,
726                            g_list_length(m->gtktypes) - (is_none ? 2 : 1),
727                            typebase);
728         }
729         print_signal_marsal_args_gtk1 (m);
730 }
731
732 static const char *
733 gtk2_debool (const char *s)
734 {
735         if (strcmp (s, "BOOL") == 0)
736                 return "BOOLEAN";
737         else
738                 return s;
739 }
740
741 static void
742 print_signal_marsal_args_gtk2 (Method *m)
743 {
744         if (strcmp (m->gtktypes->next->data, "NONE") != 0) {
745                 GList *li;
746                 int i;
747                 for (i = 0, li = m->gtktypes->next;
748                      li != NULL;
749                      i++, li = li->next) {
750                         char *get_func = g_strdup_printf
751                                 ("g_value_get_%s",
752                                  (char *)gtk2_debool (li->data));
753                         g_strdown (get_func);
754                         out_printf (out, ",\n\t\t(%s) "
755                                     "%s (param_values + %d)",
756                                     get_cast (li->data, FALSE),
757                                     get_func, i + 1);
758                         g_free (get_func);
759                 }
760         }
761         out_printf (out, ",\n\t\tdata2);\n");
762 }
763
764 static void
765 add_marshal_gtk2 (Method *m, const char *mname)
766 {
767         gboolean ret_none;
768         gboolean arglist_none;
769         const char *retcast;
770
771         ret_none = strcmp (m->gtktypes->data, "NONE") == 0;
772         arglist_none = strcmp (m->gtktypes->next->data, "NONE") == 0;
773
774         if (ret_none)
775                 retcast = NULL;
776         else
777                 retcast = get_cast (m->gtktypes->data, FALSE);
778
779         out_printf (out, "\nstatic void\n"
780                     "___marshal_%s (GClosure *closure,\n"
781                     "\tGValue *return_value,\n"
782                     "\tguint n_param_values,\n"
783                     "\tconst GValue *param_values,\n"
784                     "\tgpointer invocation_hint,\n"
785                     "\tgpointer marshal_data)\n"
786                     "{\n", mname);
787
788         if ( ! ret_none)
789                 out_printf (out, "\t%s v_return;\n", retcast);
790
791         out_printf (out, "\tregister ___%s callback;\n"
792                     "\tregister GCClosure *cc = (GCClosure*) closure;\n"
793                     "\tregister gpointer data1, data2;\n\n",
794                     mname);
795
796         out_printf (out, "\tg_return_if_fail (n_param_values == %d);\n\n",
797                     arglist_none ? 1 : g_list_length (m->gtktypes));
798
799         out_printf (out,
800                     "\tif (G_CCLOSURE_SWAP_DATA (closure)) {\n"
801                     "\t\tdata1 = closure->data;\n"
802                     "\t\tdata2 = g_value_peek_pointer (param_values + 0);\n"
803                     "\t} else {\n"
804                     "\t\tdata1 = g_value_peek_pointer (param_values + 0);\n"
805                     "\t\tdata2 = closure->data;\n"
806                     "\t}\n\n");
807
808         out_printf (out, "\tcallback = (___%s) "
809                     "(marshal_data != NULL ? marshal_data : cc->callback);"
810                     "\n\n", mname);
811         
812         if (ret_none) {
813                 out_printf (out, "\tcallback ((%s *)data1", typebase);
814         } else {
815                 out_printf (out, "\tv_return = callback ((%s *)data1",
816                             typebase);
817         }
818
819         print_signal_marsal_args_gtk2 (m);
820
821         if ( ! ret_none) {
822                 /* FIXME: This code is so fucking ugly it hurts */
823                 gboolean take_ownership = 
824                         (strcmp ((char *)m->gtktypes->data, "STRING") == 0 ||
825                          strcmp ((char *)m->gtktypes->data, "BOXED") == 0);
826                 char *set_func = g_strdup_printf ("g_value_set_%s%s",
827                                                   (char *)gtk2_debool (m->gtktypes->data),
828                                                   take_ownership ?
829                                                     "_take_ownership" : ""); 
830                 g_strdown (set_func);
831
832                 out_printf (out, "\n\t%s (return_value, v_return);\n",
833                             set_func);
834
835                 g_free (set_func);
836         }
837         out_printf (out, "}\n\n");
838 }
839
840
841
842 static void
843 add_signal_prots(Method *m)
844 {
845         GList *li;
846         static int sig = 1;
847         char *s;
848         Method *mm;
849         
850         if(m->method != SIGNAL_LAST_METHOD &&
851            m->method != SIGNAL_FIRST_METHOD)
852                 return;
853
854         if(!marsh)
855                 marsh = g_hash_table_new(NULL, NULL);
856         
857         if(strcmp(m->gtktypes->data, "NONE")==0 &&
858            strcmp(m->gtktypes->next->data, "NONE")==0)
859                 return;
860
861         /* if we already did a signal prototype just use that */
862         mm = find_same_type_signal(m);
863         if(mm) {
864                 s = g_hash_table_lookup(marsh, mm);
865                 g_hash_table_insert(marsh, m, s);
866                 return;
867         }
868         
869         s = g_strdup_printf("Sig%d", sig++);
870         
871         g_hash_table_insert(marsh, m, s);
872         eq_signal_methods = g_list_prepend(eq_signal_methods, m);
873
874         /* we know that we'll know all the gtktypes (so get_cast can't fail) */
875         out_printf(out, "\ntypedef %s (*___%s) (%s *, ",
876                    get_cast(m->gtktypes->data, FALSE), s, typebase);
877         
878         if (strcmp (m->gtktypes->next->data, "NONE") != 0) {
879                 for (li = m->gtktypes->next; li != NULL; li = li->next)
880                         out_printf(out, "%s, ", get_cast(li->data, FALSE));
881         }
882         out_printf (out, "gpointer);\n"); 
883         
884
885         out_printf (out, "\n#ifdef G_OBJECT_CLASS\n");
886         add_marshal_gtk2 (m, s);
887         out_printf (out, "#else /* ! G_OBJECT_CLASS */\n");
888         add_marshal_gtk1 (m, s);
889         out_printf (out, "#endif /* G_OBJECT_CLASS */\n\n");
890 }
891
892 static void
893 add_enums(Class *c)
894 {
895         GList *li;
896         out_printf(out, "\n");
897         if(signals>0) {
898                 out_printf(out, "enum {\n");
899                 for(li=c->nodes;li;li=g_list_next(li)) {
900                         Node *n = li->data;
901                         if(n->type == METHOD_NODE) {
902                                 Method *m = (Method *)n;
903                                 if(m->method == SIGNAL_LAST_METHOD ||
904                                    m->method == SIGNAL_FIRST_METHOD) {
905                                         char *s = g_strdup(get_real_id(m->id));
906                                         g_strup(s);
907                                         out_printf(out, "\t%s_SIGNAL,\n", s);
908                                         g_free(s);
909                                 }
910                         }
911                 }
912                 out_printf(out, "\tLAST_SIGNAL\n};\n\n");
913         }
914         if(set_arguments > 0 || get_arguments > 0) {
915                 out_printf(out, "enum {\n\tARG_0");
916                 for(li=c->nodes;li;li=g_list_next(li)) {
917                         Node *n = li->data;
918                         if(n->type == ARGUMENT_NODE) {
919                                 Argument *a = (Argument *)n;
920                                 char *s = g_strdup(a->name);
921                                 g_strup(s);
922                                 out_printf(out, ",\n\tARG_%s", s);
923                                 g_free(s);
924                         }
925                 }
926                 out_printf(out, "\n};\n\n");
927         }
928
929         if(signals>0)
930                 out_printf(out,
931                            "static guint object_signals[LAST_SIGNAL] = {0};\n\n");
932
933         out_printf(out, "/* pointer to the class of our parent */\n");
934         out_printf(out, "static %sClass *parent_class = NULL;\n\n", ptypebase);
935 }
936
937 static void
938 add_get_type(void)
939 {
940         char *chunk_size = ((Class*)class)->chunk_size;
941         
942         out_printf(out,
943                    "GtkType\n"
944                    "%s_get_type (void)\n"
945                    "{\n"
946                    "\tstatic GtkType type = 0;\n\n"
947                    "\tif (type == 0) {\n"
948                    "\t\tstatic const GtkTypeInfo info = {\n"
949                    "\t\t\t\"%s\",\n"
950                    "\t\t\tsizeof (%s),\n"
951                    "\t\t\tsizeof (%sClass),\n"
952                    "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
953                    "\t\t\t(GtkObjectInitFunc) %s_init,\n"
954                    "\t\t\t/* reserved_1 */ NULL,\n"
955                    "\t\t\t/* reserved_2 */ NULL,\n"
956                    "\t\t\t(GtkClassInitFunc) NULL\n"
957                    "\t\t};\n\n"
958                    "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n",
959                    funcbase, typebase, typebase, typebase,
960                    funcbase, funcbase, pfuncbase);
961         if(chunk_size)  {
962                 out_printf(out,
963                            "#if %s > 0\n"
964                            "\t\tgtk_type_set_chunk_alloc(type, %s);\n"
965                            "#endif\n", 
966                            chunk_size, chunk_size);
967         }
968         out_printf(out,
969                    "\t}\n\n"
970                    "\treturn type;\n"
971                    "}\n\n");
972 }
973
974 static void
975 add_bonobo_x_get_type (void)
976 {
977         char *chunk_size = ((Class*)class)->chunk_size;
978         
979         out_printf(out,
980                    "GtkType\n"
981                    "%s_get_type (void)\n"
982                    "{\n"
983                    "\tstatic GtkType type = 0;\n\n"
984                    "\tif (type == 0) {\n"
985                    "\t\tstatic const GtkTypeInfo info = {\n"
986                    "\t\t\t\"%s\",\n"
987                    "\t\t\tsizeof (%s),\n"
988                    "\t\t\tsizeof (%sClass),\n"
989                    "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
990                    "\t\t\t(GtkObjectInitFunc) %s_init,\n"
991                    "\t\t\t/* reserved_1 */ NULL,\n"
992                    "\t\t\t/* reserved_2 */ NULL,\n"
993                    "\t\t\t(GtkClassInitFunc) NULL\n"
994                    "\t\t};\n\n"
995                    "\t\ttype = bonobo_x_type_unique\n"
996                    "\t\t\t(%s_get_type (),\n"
997                    "\t\t\tPOA_%s__init, NULL,\n"
998                    "\t\t\tGTK_STRUCT_OFFSET (%sClass, _epv),\n"
999                    "\t\t\t&info);\n",
1000                    funcbase, typebase, typebase, typebase,
1001                    funcbase, funcbase, pfuncbase,
1002                    ((Class*)class)->bonobo_x_class,
1003                    typebase);
1004         if(chunk_size)  {
1005                 out_printf(out,
1006                            "#if %s > 0\n"
1007                            "\t\tgtk_type_set_chunk_alloc(type, %s);\n"
1008                            "#endif\n", 
1009                            chunk_size, chunk_size);
1010         }
1011         out_printf(out,
1012                    "\t}\n\n"
1013                    "\treturn type;\n"
1014                    "}\n\n");
1015 }
1016
1017 static void
1018 add_overrides(Class *c, const char *oname, gboolean did_base_obj)
1019 {
1020         GList *li;
1021         GHashTable *done;
1022         char *s;
1023         
1024         done = g_hash_table_new(g_str_hash, g_str_equal);
1025         if(did_base_obj) {
1026                 s = g_strdup("GtkObject"); /* This was already done */
1027                 g_hash_table_insert(done, s, s);
1028                 s = g_strdup("GObject"); /* This was probably already done as well (if using Gtk/Glib 1.3/2.0) */
1029                 g_hash_table_insert(done, s, s);
1030         }
1031         for(li=c->nodes; li; li=g_list_next(li)) {
1032                 Node *n = li->data;
1033                 char *f;
1034                 Method *m = (Method *)n;
1035                 if(n->type != METHOD_NODE ||
1036                    m->method != OVERRIDE_METHOD)
1037                         continue;
1038
1039                 s = remove_sep(m->otype);
1040                 
1041                 if(g_hash_table_lookup(done, s)) {
1042                         g_free(s);
1043                         continue;
1044                 }
1045                 g_hash_table_insert(done, s, s);
1046
1047                 f = replace_sep(m->otype, '_');
1048                 g_strdown(f);
1049
1050                 out_printf(out, "\t%sClass *%s_class = (%sClass *)%s;\n",
1051                            s, f, s, oname);
1052                 
1053                 g_free(f);
1054         }
1055         g_hash_table_foreach(done, (GHFunc)g_free, NULL);
1056         g_hash_table_destroy(done);
1057 }
1058
1059 static char *
1060 make_run_signal_flags(Method *m, gboolean last)
1061 {
1062         GList *li;
1063         GString *gs;
1064         char *flags[] = {
1065                 "FIRST",
1066                 "LAST",
1067                 "BOTH",
1068                 "NO_RECURSE",
1069                 "ACTION",
1070                 "NO_HOOKS",
1071                 NULL
1072         };
1073
1074         gs = g_string_new(NULL);
1075
1076         if(last)
1077                 g_string_assign(gs, "GTK_RUN_LAST");
1078         else
1079                 g_string_assign(gs, "GTK_RUN_FIRST");
1080
1081         if(m->scope == PUBLIC_SCOPE)
1082                 g_string_append(gs, " | GTK_RUN_ACTION");
1083
1084         for(li = m->flags; li; li = li->next) {
1085                 char *flag = li->data;
1086                 int i;
1087                 for(i=0;flags[i];i++) {
1088                         if(strcmp(flags[i], flag)==0)
1089                                 break;
1090                 }
1091                 /* if we haven't found it in our list */
1092                 if( ! flags[i]) {
1093                         error_printf(GOB_WARN, m->line_no,
1094                                      "Unknown flag '%s' used, "
1095                                      "perhaps it was misspelled",
1096                                      flag);
1097                 }
1098                 g_string_sprintfa(gs, " | GTK_RUN_%s", flag);
1099         }
1100
1101         {
1102                 char *ret = gs->str;
1103                 g_string_free(gs, FALSE);
1104                 return ret;
1105         }
1106 }
1107                 
1108
1109 static void
1110 add_signals(Class *c)
1111 {
1112         GList *li;
1113
1114         out_printf(out, "\n");
1115         for(li=c->nodes;li;li=g_list_next(li)) {
1116                 Node *n = li->data;
1117                 char *mar, *sig, *flags;
1118                 gboolean is_none, last = FALSE;
1119                 Method *m = (Method *)n;
1120
1121                 if(n->type != METHOD_NODE ||
1122                    (m->method != SIGNAL_FIRST_METHOD &&
1123                     m->method != SIGNAL_LAST_METHOD))
1124                         continue;
1125
1126                 if(m->method == SIGNAL_FIRST_METHOD)
1127                         last = FALSE;
1128                 else
1129                         last = TRUE;
1130
1131                 if(g_hash_table_lookup(marsh, m))
1132                         mar = g_strconcat("___marshal_",
1133                                           (char *)g_hash_table_lookup(marsh, m),
1134                                           NULL);
1135                 else
1136                         mar = g_strdup("gtk_signal_default_marshaller");
1137                 
1138                 is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
1139
1140                 sig = g_strdup(get_real_id(m->id));
1141                 g_strup(sig);
1142                 flags = make_run_signal_flags(m, last);
1143                 out_printf(out, "\tobject_signals[%s_SIGNAL] =\n"
1144                         "\t\tgtk_signal_new (\"%s\",\n"
1145                         "\t\t\t(GtkSignalRunType)(%s),\n"
1146                         "\t\t\tGTK_CLASS_TYPE(gtk_object_class),\n"
1147                         "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n"
1148                         "\t\t\t%s,\n"
1149                         "\t\t\tGTK_TYPE_%s, %d",
1150                         sig, get_real_id(m->id),
1151                         flags,
1152                         typebase, get_real_id(m->id), mar,
1153                         (char *)m->gtktypes->data,
1154                         is_none ? 0 : g_list_length(m->gtktypes->next));
1155                 g_free(mar);
1156                 g_free(sig);
1157                 g_free(flags);
1158                 
1159                 if( ! is_none) {
1160                         GList *l;
1161                         for(l = m->gtktypes->next; l != NULL; l = l->next)
1162                                 out_printf(out, ",\n\t\t\tGTK_TYPE_%s",
1163                                         (char *)l->data);
1164                 }
1165
1166                 out_printf(out, ");\n");
1167
1168                 if(strcmp(m->gtktypes->data, "NONE") != 0 ||
1169                    ! is_none) {
1170                         GList *gl, *al;
1171                         char *sep = "";
1172                         out_printf(out, "\tif(");
1173                         if(strcmp(m->gtktypes->data, "NONE") != 0) {
1174                                 out_printf(out, "%s sizeof(", sep);
1175                                 print_type(out, m->mtype, FALSE);
1176                                 out_printf(out, "%s",
1177                                            m->mtype->postfix ?
1178                                            m->mtype->postfix : ""); 
1179                                 out_printf(out, ") != sizeof(%s)",
1180                                            get_cast(m->gtktypes->data, FALSE));
1181
1182                                 sep = " || ";
1183                         }
1184
1185                         for(al = m->args->next, gl = m->gtktypes->next;
1186                             al != NULL && gl != NULL;
1187                             al = al->next, gl = gl->next) {
1188                                 FuncArg *arg = al->data;
1189                                 char *gtkarg = gl->data;
1190
1191                                 out_printf(out, "%ssizeof(", sep);
1192                                 print_type(out, arg->atype, FALSE);
1193                                 out_printf(out, "%s",
1194                                            arg->atype->postfix ?
1195                                            arg->atype->postfix : ""); 
1196                                 out_printf(out, ") != sizeof(%s)",
1197                                            get_cast(gtkarg, FALSE));
1198
1199                                 sep = " || ";
1200                         }
1201                         out_printf(out, ") {\n"
1202                                    "\t\tg_error(\"%s line %d: Type mismatch "
1203                                    "of \\\"%s\\\" signal signature\");\n"
1204                                    "\t}\n",
1205                                    filename, m->line_no, get_real_id(m->id));
1206
1207                 }
1208         }
1209         out_printf (out, "#ifndef G_OBJECT_CLASS\n");
1210         out_printf (out, "\tgtk_object_class_add_signals (gtk_object_class,\n"
1211                     "\t\tobject_signals, LAST_SIGNAL);\n");
1212         out_printf (out, "#endif /* ! G_OBJECT_CLASS */\n\n");
1213 }
1214
1215 static void
1216 set_def_handlers(Class *c, const char *oname)
1217 {
1218         GList *li;
1219         gboolean set_line = FALSE;
1220
1221         out_printf(out, "\n");
1222         for(li = c->nodes; li; li = g_list_next(li)) {
1223                 Node *n = li->data;
1224                 Method *m = (Method *)n;
1225
1226                 if(n->type != METHOD_NODE ||
1227                    (m->method != SIGNAL_FIRST_METHOD &&
1228                     m->method != SIGNAL_LAST_METHOD &&
1229                     m->method != VIRTUAL_METHOD &&
1230                     m->method != OVERRIDE_METHOD))
1231                         continue;
1232
1233                 if(m->line_no > 0 && m->cbuf) {
1234                         out_addline_infile(out, m->line_no);
1235                         set_line = TRUE;
1236                 } else if(set_line) {
1237                         out_addline_outfile(out);
1238                         set_line = FALSE;
1239                 }
1240
1241
1242                 if(m->method == OVERRIDE_METHOD) {
1243                         char *s;
1244                         s = replace_sep(m->otype, '_');
1245                         g_strdown(s);
1246
1247                         if(need_destroy &&
1248                            destroy_handler &&
1249                            strcmp(get_real_id(m->id), "destroy") == 0)
1250                                 out_printf(out, "\tgtk_object_class->destroy "
1251                                            "= ___destroy;\n");
1252                         else if(need_finalize &&
1253                                 finalize_handler &&
1254                                 strcmp(get_real_id(m->id), "finalize") == 0)
1255                                 out_printf(out,
1256                                            "#ifdef G_OBJECT_CLASS\n"
1257                                            "\tg_object_class->finalize = ___finalize;\n"
1258                                            "#else /* !G_OBJECT_CLASS */\n"
1259                                            "\tgtk_object_class->finalize = ___finalize;\n"
1260                                            "#endif /* G_OBJECT_CLASS */\n");
1261                         else if(m->cbuf)
1262                                 out_printf(out,
1263                                            "\t%s_class->%s = ___%x_%s_%s;\n",
1264                                            s, get_real_id(m->id), (guint)m->unique_id,
1265                                            funcbase, get_real_id(m->id));
1266                         else
1267                                 out_printf(out, "\t%s_class->%s = NULL;\n",
1268                                            s, get_real_id(m->id));
1269                 } else {
1270                         if(m->cbuf)
1271                                 out_printf(out, "\t%s->%s = ___real_%s_%s;\n",
1272                                            oname, get_real_id(m->id),
1273                                            funcbase, get_real_id(m->id));
1274                         else
1275                                 out_printf(out, "\t%s->%s = NULL;\n",
1276                                            oname, get_real_id(m->id));
1277                 }
1278         }
1279         if(set_line)
1280                 out_addline_outfile(out);
1281 }
1282
1283 static void
1284 make_arguments(Class *c)
1285 {
1286         GList *li;
1287         char *argflags[] = {
1288                 "CONSTRUCT",
1289                 "CONSTRUCT_ONLY",
1290                 "CHILD_ARG",
1291                 "MASK",
1292                 NULL
1293         };
1294
1295         out_printf(out, "\n");
1296         for(li=c->nodes;li;li=g_list_next(li)) {
1297                 Node *n = li->data;
1298                 Argument *a;
1299                 GString *flags;
1300                 GList *l;
1301                 char *s;
1302                 if(n->type != ARGUMENT_NODE)
1303                         continue;
1304
1305                 a = (Argument *)n;
1306                 
1307                 if(a->get && a->set)
1308                         flags = g_string_new("GTK_ARG_READWRITE");
1309                 else if(a->get)
1310                         flags = g_string_new("GTK_ARG_READABLE");
1311                 else
1312                         flags = g_string_new("GTK_ARG_WRITABLE");
1313
1314                 g_assert(a->get || a->set);
1315                 
1316                 for(l=a->flags;l;l=g_list_next(l)) {
1317                         char *flag = l->data;
1318                         int i;
1319                         if(strcmp(flag, "READWRITE")==0 ||
1320                            strcmp(flag, "READABLE")==0 ||
1321                            strcmp(flag, "WRITABLE")==0) {
1322                                 error_print(GOB_WARN, a->line_no,
1323                                             "READWRITE, READABLE and "
1324                                             "WRITABLE argument flags are "
1325                                             "set automatically");
1326                                 continue;
1327                         }
1328                         for(i = 0; argflags[i]; i++) {
1329                                 if(strcmp(argflags[i], flag)==0)
1330                                         break;
1331                         }
1332                         /* if we haven't found it in our list */
1333                         if( ! argflags[i]) {
1334                                 error_printf(GOB_WARN, a->line_no,
1335                                              "Unknown flag '%s' used, "
1336                                              "perhaps it was misspelled", flag);
1337                         }
1338                         g_string_sprintfa(flags, " | GTK_ARG_%s", flag);
1339                 }
1340
1341                 s = g_strdup(a->name);
1342                 g_strup(s);
1343                 out_printf(out, "\tgtk_object_add_arg_type(\"%s::%s\",\n"
1344                         "\t\tGTK_TYPE_%s,\n"
1345                         "\t\t%s,\n"
1346                         "\t\tARG_%s);\n",
1347                         typebase, a->name, a->gtktype, flags->str, s);
1348                 g_free(s);
1349                 g_string_free(flags, TRUE);
1350         }
1351         
1352         out_printf(out, "\n");
1353         if(get_arguments > 0)
1354                 out_printf(out, "\tgtk_object_class->get_arg = ___object_get_arg;\n");
1355         if(set_arguments > 0)
1356                 out_printf(out, "\tgtk_object_class->set_arg = ___object_set_arg;\n");
1357 }
1358
1359 static void
1360 print_initializer(Method *m, Variable *v)
1361 {
1362         char *root;
1363
1364         if(v->initializer == NULL)
1365                 return;
1366
1367         if(v->scope == PRIVATE_SCOPE)
1368                 root = g_strconcat(((FuncArg *)m->args->data)->name,
1369                                    "->_priv", NULL);
1370         else
1371                 root = g_strdup(((FuncArg *)m->args->data)->name);
1372
1373         if(v->initializer_line > 0)
1374                 out_addline_infile(out, v->initializer_line);
1375
1376         out_printf(out, "\t%s->%s = %s;\n",
1377                    root, v->id, v->initializer);
1378
1379         if(v->initializer_line > 0)
1380                 out_addline_outfile(out);
1381
1382         g_free(root);
1383 }
1384
1385 static void
1386 print_destructor(Variable *v)
1387 {
1388         char *root;
1389
1390         if(v->destructor == NULL)
1391                 return;
1392
1393         if(v->scope == PRIVATE_SCOPE)
1394                 root = "self->_priv";
1395         else
1396                 root = "self";
1397
1398         if(v->destructor_simple) {
1399                 if(v->destructor_line > 0)
1400                         out_addline_infile(out, v->destructor_line);
1401
1402                 out_printf(out, "\tif(%s->%s) { "
1403                            "((*(void (*)(void *))%s)) (%s->%s); "
1404                            "%s->%s = NULL; }\n",
1405                            root, v->id, v->destructor, root, v->id,
1406                            root, v->id);
1407
1408                 if(v->destructor_line > 0)
1409                         out_addline_outfile(out);
1410         } else {
1411                 out_printf(out, "#define VAR (%s->%s)\n", root, v->id);
1412                 out_printf(out, "\t{\n");
1413                 if(v->destructor_line > 0)
1414                         out_addline_infile(out, v->destructor_line);
1415
1416                 out_printf(out, "\t%s}\n", v->destructor);
1417
1418                 if(v->destructor_line > 0)
1419                         out_addline_outfile(out);
1420                 out_printf(out, "\tmemset(&VAR, 0, sizeof(VAR));\n");
1421                 out_printf(out, "#undef VAR\n");
1422         }
1423 }
1424
1425 static void
1426 add_destroy(Class *c)
1427 {
1428         out_printf(out, "\nstatic void\n"
1429                    "___destroy(GtkObject *obj_self)\n"
1430                    "{\n");
1431         out_printf(out,
1432                    "#define __GOB_FUNCTION__ \"%s::destroy\"\n",
1433                    c->otype);
1434
1435         if(destructors > 0) {
1436                 out_printf(out, "\t%s *self = %s (obj_self);\n",
1437                            typebase, macrobase);
1438         }
1439
1440         if(destroy_handler) {
1441                 /* so we get possible bad argument warning */
1442                 if(destroy_handler->line_no > 0)
1443                         out_addline_infile(out, destroy_handler->line_no);
1444                 out_printf(out, "\t___%x_%s_destroy(obj_self);\n",
1445                            (guint)destroy_handler->unique_id, funcbase);
1446                 if(destroy_handler->line_no > 0)
1447                         out_addline_outfile(out);
1448         } else {
1449                 out_printf(out,
1450                            "\tif(GTK_OBJECT_CLASS(parent_class)->destroy) \\\n"
1451                            "\t\t(* GTK_OBJECT_CLASS(parent_class)->destroy)(obj_self);\n");
1452         }
1453
1454         if(destructors > 0) {
1455                 GList *li;
1456                 for(li = ((Class *)class)->nodes;
1457                     li != NULL;
1458                     li = li->next) {
1459                         Node *n = li->data;
1460                         Variable *v = (Variable *)n;
1461                         if(n->type == VARIABLE_NODE &&
1462                            v->scope != CLASS_SCOPE)
1463                                 print_destructor(v);
1464                 }
1465         }
1466
1467         out_printf(out, "\treturn;\n");
1468         if(destructors > 0)
1469                 out_printf(out, "\tself = NULL;\n");
1470         out_printf(out, "}\n"
1471                    "#undef __GOB_FUNCTION__\n\n");
1472 }
1473
1474 static void
1475 add_finalize(Class *c)
1476 {
1477         /* Sort of a hack to make it work with gtk+ 1.3/2.0 */
1478         out_printf(out,
1479                    "\n#ifdef G_OBJECT_CLASS\n"
1480                    "static void\n"
1481                    "___finalize(GObject *obj_self)\n"
1482                    "#else /* !G_OBJECT_CLASS */\n"
1483                    "static void\n"
1484                    "___finalize(GtkObject *obj_self)\n"
1485                    "#endif /* G_OBJECT_CLASS */\n"
1486                    "{\n");
1487         out_printf(out,
1488                    "#define __GOB_FUNCTION__ \"%s::finalize\"\n",
1489                    c->otype);
1490
1491         if(privates > 0) {
1492                 out_printf(out, "\t%s *self = %s (obj_self);\n",
1493                            typebase, macrobase);
1494                 out_printf(out, "\tgpointer priv = self->_priv;\n");
1495         }
1496
1497         if(finalize_handler) {
1498                 /* so we get possible bad argument warning */
1499                 if(finalize_handler->line_no > 0)
1500                         out_addline_infile(out, finalize_handler->line_no);
1501                 out_printf(out, "\t___%x_%s_finalize(obj_self);\n",
1502                            (guint)finalize_handler->unique_id, funcbase);
1503                 if(finalize_handler->line_no > 0)
1504                         out_addline_outfile(out);
1505         } else {
1506                 /* Sort of a hack to make it work with gtk+ 1.3/2.0 */
1507                 out_printf(out,
1508                            "#ifdef G_OBJECT_CLASS\n"
1509                            "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
1510                            "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n"
1511                            "#else /* !G_OBJECT_CLASS */\n"
1512                            "\tif(GTK_OBJECT_CLASS(parent_class)->finalize) \\\n"
1513                            "\t\t(* GTK_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n"
1514                            "#endif /* G_OBJECT_CLASS */\n");
1515         }
1516
1517         if(privates > 0) {
1518                 out_printf(out, "\tg_free(priv);\n");
1519         }
1520
1521         out_printf(out, "}\n"
1522                    "#undef __GOB_FUNCTION__\n\n");
1523 }
1524
1525 static void
1526 make_bonobo_x_epv (Class *c, const char *classname)
1527 {
1528         GList *li;
1529         gboolean added_line = FALSE;
1530
1531         for (li = c->nodes; li != NULL; li = li->next) {
1532                 Node *n = li->data;
1533                 Method *m = (Method *)n;
1534                 if(n->type != METHOD_NODE ||
1535                    m->method == OVERRIDE_METHOD)
1536                         continue;
1537
1538                 if (m->bonobo_x_func) {
1539                         if(m->line_no > 0) {
1540                                 out_addline_infile(out, m->line_no);
1541                                 added_line = TRUE;
1542                         } else if (m->line_no == 0 &&
1543                                    added_line) {
1544                                 out_addline_outfile(out);
1545                                 added_line = FALSE;
1546                         }
1547                         out_printf (out, "\t%s->_epv.%s = %s;\n",
1548                                     classname, m->id, m->id);
1549                 }
1550         }
1551         if (added_line)
1552                 out_addline_outfile(out);
1553 }
1554
1555 static void
1556 add_inits(Class *c)
1557 {
1558         GList *li;
1559         for(li=c->nodes;li;li=g_list_next(li)) {
1560                 Node *n = li->data;
1561                 Method *m;
1562
1563                 gboolean add_unused_class = FALSE;
1564
1565                 if(n->type != METHOD_NODE)
1566                         continue;
1567                 m = (Method *)n;
1568                 if(m->method == INIT_METHOD) {
1569                         if(m->line_no > 0)
1570                                 out_addline_infile(out, m->line_no);
1571                         print_method(out, "static ", "\n", "", " ", "", "\n",
1572                                      m, FALSE, FALSE, TRUE);
1573                         if(m->line_no > 0)
1574                                 out_addline_outfile(out);
1575                         out_printf(out, "{\n"
1576                                    "#define __GOB_FUNCTION__ \"%s::init\"\n",
1577                                    c->otype);
1578                         if(privates > 0) {
1579                                 out_printf(out, "\t%s->_priv = "
1580                                            "g_new0 (%sPrivate, 1);\n",
1581                                            ((FuncArg *)m->args->data)->name,
1582                                            typebase);
1583                         } else if(always_private_struct) {
1584                                 out_printf(out, "\t%s->_priv = NULL;\n",
1585                                            ((FuncArg *)m->args->data)->name);
1586                         }
1587                         if(initializers > 0) {
1588                                 GList *li;
1589                                 for(li = ((Class *)class)->nodes;
1590                                     li != NULL;
1591                                     li = li->next) {
1592                                         Node *n = li->data;
1593                                         Variable *v = (Variable *)n;
1594                                         if(n->type != VARIABLE_NODE ||
1595                                            v->scope == CLASS_SCOPE)
1596                                                 continue;
1597                                         print_initializer(m, v);
1598                                 }
1599                         }
1600                 } else if(m->method == CLASS_INIT_METHOD) {
1601                         gboolean did_base_obj = FALSE;
1602
1603                         if(m->line_no > 0)
1604                                 out_addline_infile(out, m->line_no);
1605                         print_method(out, "static ", "\n", "", " ", "", "\n",
1606                                      m, FALSE, FALSE, TRUE);
1607                         if(m->line_no > 0)
1608                                 out_addline_outfile(out);
1609                         out_printf(out, "{\n"
1610                                    "#define __GOB_FUNCTION__ \"%s::class_init\"\n",
1611                                    c->otype);
1612                         if(signals > 0 ||
1613                            set_arguments > 0 ||
1614                            get_arguments > 0 ||
1615                            need_destroy ||
1616                            need_finalize) {
1617                                 add_unused_class = TRUE;
1618                                 out_printf(out,
1619                                            "\tGtkObjectClass *"
1620                                            "gtk_object_class = "
1621                                            "(GtkObjectClass*) %s;\n",
1622                                            ((FuncArg *)m->args->data)->name);
1623                                 out_printf(out,
1624                                            "#ifdef G_OBJECT_CLASS\n"
1625                                            "\tGObjectClass *"
1626                                            "g_object_class = "
1627                                            "(GObjectClass*) %s;\n"
1628                                            "#endif /* G_OBJECT_CLASS */\n",
1629                                            ((FuncArg *)m->args->data)->name);
1630                                 did_base_obj = TRUE;
1631                         }
1632
1633                         if(overrides > 0)
1634                                 add_overrides(c,
1635                                               ((FuncArg *)m->args->data)->name,
1636                                               did_base_obj);
1637
1638                         if(initializers > 0) {
1639                                 GList *li;
1640                                 for(li = ((Class *)class)->nodes;
1641                                     li != NULL;
1642                                     li = li->next) {
1643                                         Node *n = li->data;
1644                                         Variable *v = (Variable *)n;
1645                                         if(n->type == VARIABLE_NODE &&
1646                                            v->scope == CLASS_SCOPE)
1647                                                 print_initializer(m, v);
1648                                 }
1649                         }
1650                         
1651                         out_printf(out, "\n\tparent_class = ");
1652                         if(for_cpp)
1653                                 out_printf(out, "(%sClass *)", ptypebase);
1654                         out_printf(out, "gtk_type_class (%s_get_type ());\n",
1655                                    pfuncbase);
1656
1657                         if(signals > 0)
1658                                 add_signals(c);
1659
1660                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
1661
1662                         /* if there are no handlers for these things, we
1663                          * need to set them up here */
1664                         if(need_destroy && !destroy_handler)
1665                                 out_printf(out, "\tgtk_object_class->destroy "
1666                                            "= ___destroy;\n");
1667                         if(need_finalize && !finalize_handler)
1668                                 out_printf(out,
1669                                            "#ifdef G_OBJECT_CLASS\n"
1670                                            "\tg_object_class->finalize = ___finalize;\n"
1671                                            "#else /* !G_OBJECT_CLASS */\n"
1672                                            "\tgtk_object_class->finalize = ___finalize;\n"
1673                                            "#endif /* G_OBJECT_CLASS */\n");
1674                         
1675                         if(get_arguments > 0 || set_arguments > 0)
1676                                 make_arguments(c);
1677
1678                         if (c->bonobo_x_class != NULL) {
1679                                 make_bonobo_x_epv (c, ((FuncArg *)m->args->data)->name);
1680                         }
1681                 } else
1682                         continue;
1683
1684                 if(m->cbuf) {
1685                         out_printf(out, " {\n");
1686                         out_addline_infile(out, m->ccode_line);
1687                         out_printf(out, "%s\n", m->cbuf);
1688                         out_addline_outfile(out);
1689                         out_printf(out, " }\n");
1690                 }
1691                 out_printf(out, "\treturn;\n");
1692                 out_printf(out,
1693                            "\t%s = NULL;\n",
1694                            ((FuncArg *)m->args->data)->name);
1695                 if(add_unused_class) {
1696                         out_printf(out,
1697                                    "\tgtk_object_class = NULL;\n"
1698                                    "#ifdef G_OBJECT_CLASS\n"
1699                                    "\tg_object_class = NULL;\n"
1700                                    "#endif /* G_OBJECT_CLASS */\n");
1701                 }
1702                 out_printf(out, "}\n"
1703                            "#undef __GOB_FUNCTION__\n");
1704         }
1705 }
1706
1707 static void
1708 add_getset_arg(Class *c, gboolean is_set)
1709 {
1710         GList *li;
1711         out_printf(out, "\nstatic void\n"
1712                    "___object_%s_arg (GtkObject *object,\n"
1713                    "\tGtkArg *arg,\n"
1714                    "\tguint arg_id)\n"
1715                    "#define __GOB_FUNCTION__ \"%s::%s_arg\"\n"
1716                    "{\n"
1717                    "\t%s *self;\n\n"
1718                    "\tself = %s (object);\n\n"
1719                    "\tswitch (arg_id) {\n",
1720                    is_set ? "set" : "get",
1721                    c->otype, is_set ? "set" : "get",
1722                    typebase, macrobase);
1723
1724         for(li=c->nodes;li;li=g_list_next(li)) {
1725                 Node *n = li->data;
1726                 Argument *a;
1727                 char *s;
1728                 char *cbuf;
1729                 int line_no;
1730                 if(n->type != ARGUMENT_NODE)
1731                         continue;
1732                 a = (Argument *)n;
1733                 if(is_set) {
1734                         cbuf = a->set;
1735                         line_no = a->set_line;
1736                 } else {
1737                         cbuf = a->get;
1738                         line_no = a->get_line;
1739                 }
1740                 if(!cbuf)
1741                         continue;
1742                 s = g_strdup(a->name);
1743                 g_strup(s);
1744                 out_printf(out, "\tcase ARG_%s:\n", s);
1745                 if(is_set && a->atype) {
1746                         char *cast = get_type(a->atype, TRUE);
1747                         if(no_gnu || for_cpp) {
1748                                 out_printf(out, "#define ARG "
1749                                            "((%s)GTK_VALUE_%s(*arg))\n",
1750                                            cast, a->gtktype);
1751                         } else {
1752                                 out_printf(out, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
1753                                 if(strcmp(a->gtktype, "OBJECT")==0) {
1754                                         out_printf(out, "#define ARG "
1755                                                    "({%s foo = "
1756                                                    "GTK_VALUE_POINTER(*arg); "
1757                                                    "foo; })\n",
1758                                                    cast);
1759                                 } else {
1760                                         out_printf(out, "#define ARG "
1761                                                    "({%s foo = "
1762                                                    "GTK_VALUE_%s(*arg); "
1763                                                    "foo; })\n",
1764                                                    cast, a->gtktype);
1765                                 }
1766                                 out_printf(out, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
1767                                 out_printf(out, "#define ARG "
1768                                            "((%s)GTK_VALUE_%s(*arg))\n",
1769                                            cast, a->gtktype);
1770                                 out_printf(out, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
1771                         }
1772                         out_printf(out, "\t\t{\n");
1773                         g_free(cast);
1774                 } else if(!is_set && strcmp(a->gtktype, "OBJECT")==0) {
1775                         out_printf(out,
1776                                    "#define ARG (GTK_VALUE_POINTER(*arg))\n"
1777                                    "\t\t{\n");
1778                 } else {
1779                         out_printf(out,
1780                                    "#define ARG (GTK_VALUE_%s(*arg))\n"
1781                                    "\t\t{\n",
1782                                    a->gtktype);
1783                 }
1784                 g_free(s);
1785                 if(line_no > 0)
1786                         out_addline_infile(out, line_no);
1787                 out_printf(out, "%s\n", cbuf);
1788                 if(line_no > 0)
1789                         out_addline_outfile(out);
1790                 out_printf(out, "\t\t}\n\t\tbreak;\n"
1791                         "#undef ARG\n");
1792         }
1793         out_printf(out, "\tdefault:\n\t\tbreak;\n\t}\n"
1794                    "\treturn;\n\tself = NULL;\n\targ = NULL;\n}\n"
1795                    "#undef __GOB_FUNCTION__\n");
1796 }
1797
1798 static void
1799 print_checks(Method *m, FuncArg *fa)
1800 {
1801         GList *li;
1802         gboolean is_void;
1803         gboolean checked_null = FALSE;
1804         is_void = (strcmp(m->mtype->name, "void")==0 &&
1805                    m->mtype->pointer == NULL);
1806         
1807         for(li = fa->checks; li; li = g_list_next(li)) {
1808                 Check *ch = li->data;
1809                 char *s;
1810                 /* point to the method prot in .gob for failed checks */
1811                 if(m->line_no > 0)
1812                         out_addline_infile(out, m->line_no);
1813                 if(is_void)
1814                         out_printf(out, "\tg_return_if_fail (");
1815                 else
1816                         out_printf(out, "\tg_return_val_if_fail (");
1817                 switch(ch->chtype) {
1818                 case NULL_CHECK:
1819                         out_printf(out, "%s != NULL", fa->name);
1820                         checked_null = TRUE;
1821                         break;
1822                 case TYPE_CHECK:
1823                         s = make_pre_macro(fa->atype->name, "IS");
1824                         if(checked_null)
1825                                 out_printf(out, "%s (%s)", s, fa->name);
1826                         else
1827                                 /* if not check null, null may be valid */
1828                                 out_printf(out, "!(%s) || %s (%s)", fa->name,
1829                                            s, fa->name);
1830                         g_free(s);
1831                         break;
1832                 case LT_CHECK:
1833                         out_printf(out, "%s < %s", fa->name, ch->number);
1834                         break;
1835                 case GT_CHECK:
1836                         out_printf(out, "%s > %s", fa->name, ch->number);
1837                         break;
1838                 case LE_CHECK:
1839                         out_printf(out, "%s <= %s", fa->name, ch->number);
1840                         break;
1841                 case GE_CHECK:
1842                         out_printf(out, "%s >= %s", fa->name, ch->number);
1843                         break;
1844                 case EQ_CHECK:
1845                         out_printf(out, "%s == %s", fa->name, ch->number);
1846                         break;
1847                 case NE_CHECK:
1848                         out_printf(out, "%s != %s", fa->name, ch->number);
1849                         break;
1850                 }
1851                 if(is_void)
1852                         out_printf(out, ");\n");
1853                 else {
1854                         out_printf(out, ", (");
1855                         print_type(out, m->mtype, TRUE);
1856                         out_printf(out, ")%s);\n",
1857                                 m->onerror?m->onerror:"0");
1858                 }
1859         }
1860 }
1861
1862 static void
1863 print_preconditions(Method *m)
1864 {
1865         GList *li;
1866         
1867         for(li=m->args;li;li=g_list_next(li)) {
1868                 FuncArg *fa = li->data;
1869                 if(fa->checks)
1870                         print_checks(m, fa);
1871         }
1872         if(m->line_no>0)
1873                 out_addline_outfile(out);
1874 }
1875
1876 static void
1877 print_method_body(Method *m, int pre)
1878 {
1879         if (m->line_no > 0)
1880                 out_addline_outfile(out);
1881         out_printf(out, "{\n"
1882                    "#define __GOB_FUNCTION__ \"%s::%s\"\n",
1883                    ((Class *)class)->otype,
1884                    get_real_id(m->id));
1885         if(pre)
1886                 print_preconditions(m);
1887
1888         /* Note: the trailing }'s are on one line, this is so
1889            that we get the no return warning correctly and point to
1890            the correct line in the .gob file, yes this is slightly
1891            ugly in the .c file, but that is not supposed to be
1892            human readable anyway. */
1893         if(m->cbuf) {
1894                 out_printf(out, "{\n");
1895                 if(m->ccode_line>0)
1896                         out_addline_infile(out, m->ccode_line);
1897                 out_printf(out, "\t%s}", m->cbuf);
1898         }
1899
1900         /* Note, there is no \n between the last } and this } so that
1901          * errors/warnings reported on the end of the body get pointed to the
1902          * right line in the .gob source */
1903         out_printf(out, "}\n");
1904
1905         if(m->cbuf)
1906                 out_addline_outfile(out);
1907         out_printf(out, "#undef __GOB_FUNCTION__\n");
1908 }
1909
1910 static void
1911 put_signal_args(Method *m)
1912 {
1913         GList *li;
1914         GList *ali;
1915         for(ali = m->gtktypes->next, li=m->args->next;
1916             li && ali;
1917             li=li->next, ali=ali->next) {
1918                 FuncArg *fa = li->data;
1919                 const char *cast = get_cast(ali->data, FALSE);
1920                 /* we should have already proved before that
1921                    the we know all the types */
1922                 g_assert(cast);
1923
1924                 out_printf(out, ",\n\t\t(%s)%s", cast,
1925                            fa->name);
1926         }
1927 }
1928
1929 static char *
1930 get_arg_names_for_macro(Method *m)
1931 {
1932         char *p;
1933         GList *li;
1934         GString *gs = g_string_new(NULL);
1935         p = "";
1936         for(li=m->args;li;li=g_list_next(li)) {
1937                 FuncArg *arg = li->data;
1938                 g_string_sprintfa(gs, "%s___%s", p, arg->name);
1939                 p = ",";
1940         }
1941         p = gs->str;
1942         g_string_free(gs, FALSE);
1943         return p;
1944 }
1945
1946 static void
1947 put_method(Method *m)
1948 {
1949         char *s, *args, *doc;
1950         gboolean is_void;
1951         is_void = (strcmp(m->mtype->name, "void")==0 &&
1952                    m->mtype->pointer == NULL);
1953         out_printf(out, "\n");
1954         if(m->method != OVERRIDE_METHOD) {
1955                 doc = get_gtk_doc(m->id);
1956                 if(doc) {
1957                         out_printf(out, "%s", doc);
1958                         g_free(doc);
1959                 }
1960         }
1961         switch(m->method) {
1962         case REGULAR_METHOD:
1963                 if(m->line_no > 0)
1964                         out_addline_infile(out, m->line_no);
1965                 if(m->scope == PRIVATE_SCOPE)
1966                         print_method(out, "static ", "\n", "", " ", "", "\n",
1967                                      m, FALSE, FALSE, TRUE);
1968                 else /* PUBLIC, PROTECTED */
1969                         print_method(out, "", "\n", "", " ", "", "\n",
1970                                      m, FALSE, FALSE, TRUE);
1971                 print_method_body(m, TRUE);
1972                 /* the outfile line was added above */
1973                 break;
1974         case SIGNAL_FIRST_METHOD:
1975         case SIGNAL_LAST_METHOD:
1976                 if(m->line_no > 0)
1977                         out_addline_infile(out, m->line_no);
1978                 if(m->scope == PRIVATE_SCOPE)
1979                         print_method(out, "static ", "\n", "", " ", "", "\n",
1980                                      m, FALSE, FALSE, TRUE);
1981                 else /* PUBLIC, PROTECTED */
1982                         print_method(out, "", "\n", "", " ", "", "\n",
1983                                      m, FALSE, FALSE, TRUE);
1984                 out_addline_outfile(out);
1985                 out_printf(out, "{\n");
1986                 s = g_strdup(get_real_id(m->id));
1987                 g_strup(s);
1988                 if(strcmp(m->mtype->name, "void") == 0 &&
1989                    m->mtype->pointer == NULL) {
1990                         print_preconditions(m);
1991                         if(((FuncArg *)m->args->data)->name)
1992                         out_printf(out, "\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1993                                 "\t\tobject_signals[%s_SIGNAL]",
1994                                 ((FuncArg *)m->args->data)->name, s);
1995                         put_signal_args(m);
1996                         out_printf(out, ");\n}\n");
1997                 } else {
1998                         out_printf(out, "\t");
1999                         print_type(out, m->mtype, TRUE);
2000                         out_printf(out, "return_val = (");
2001                         print_type(out, m->mtype, TRUE);
2002                         if(m->defreturn)
2003                                 out_printf(out, ")(%s);\n", m->defreturn);
2004                         else if(m->onerror)
2005                                 out_printf(out, ")(%s);\n", m->onerror);
2006                         else
2007                                 out_printf(out, ")(0);\n");
2008                         print_preconditions(m);
2009                         out_printf(out, "\tgtk_signal_emit (GTK_OBJECT (%s),\n"
2010                                 "\t\tobject_signals[%s_SIGNAL]",
2011                                 ((FuncArg *)m->args->data)->name, s);
2012                         put_signal_args(m);
2013                         out_printf(out, ",\n\t\t&return_val);\n"
2014                                 "\treturn return_val;\n}\n");
2015                 }
2016
2017                 if(!m->cbuf)
2018                         break;
2019                 if(m->line_no > 0)
2020                         out_addline_infile(out, m->line_no);
2021                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
2022                              m, FALSE, FALSE, TRUE);
2023                 print_method_body(m, FALSE);
2024                 /* the outfile line was added above */
2025                 break;
2026         case VIRTUAL_METHOD:
2027                 if(m->line_no > 0)
2028                         out_addline_infile(out, m->line_no);
2029                 if(m->scope==PRIVATE_SCOPE)
2030                         print_method(out, "static ", "\n", "", " ", "", "\n",
2031                                      m, FALSE, FALSE, TRUE);
2032                 else /* PUBLIC, PROTECTED */
2033                         print_method(out, "", "\n", "", " ", "", "\n",
2034                                      m, FALSE, FALSE, TRUE);
2035                 out_addline_outfile(out);
2036                 out_printf(out, "{\n"
2037                         "\t%sClass *klass;\n", typebase);
2038                 print_preconditions(m);
2039                 out_printf(out, "\tklass = %s_GET_CLASS(%s);\n\n"
2040                         "\tif(klass->%s)\n",
2041                         macrobase, ((FuncArg *)m->args->data)->name,
2042                         get_real_id(m->id));
2043                 if(strcmp(m->mtype->name, "void") == 0 &&
2044                    m->mtype->pointer == NULL) {
2045                         GList *li;
2046                         out_printf(out, "\t\t(*klass->%s)(%s",
2047                                    get_real_id(m->id),
2048                                    ((FuncArg *)m->args->data)->name);
2049                         for(li=m->args->next;li;li=g_list_next(li)) {
2050                                 FuncArg *fa = li->data;
2051                                 out_printf(out, ",%s", fa->name);
2052                         }
2053                         out_printf(out, ");\n}\n");
2054                 } else {
2055                         GList *li;
2056                         out_printf(out, "\t\treturn (*klass->%s)(%s",
2057                                    get_real_id(m->id),
2058                                    ((FuncArg *)m->args->data)->name);
2059                         for(li=m->args->next;li;li=g_list_next(li)) {
2060                                 FuncArg *fa = li->data;
2061                                 out_printf(out, ",%s", fa->name);
2062                         }
2063                         out_printf(out, ");\n"
2064                                 "\telse\n"
2065                                 "\t\treturn (");
2066                         print_type(out, m->mtype, TRUE);
2067                         if(m->defreturn)
2068                                 out_printf(out, ")(%s);\n}\n", m->defreturn);
2069                         else if(m->onerror)
2070                                 out_printf(out, ")(%s);\n}\n", m->onerror);
2071                         else
2072                                 out_printf(out, ")(0);\n}\n");
2073                 }
2074
2075                 if(!m->cbuf)
2076                         break;
2077                 if(m->line_no > 0)
2078                         out_addline_infile(out, m->line_no);
2079                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
2080                              m, FALSE, FALSE, TRUE);
2081                 print_method_body(m, FALSE);
2082                 /* the outfile line was added above */
2083                 break;
2084         case OVERRIDE_METHOD:
2085                 if(!m->cbuf)
2086                         break;
2087                 if(m->line_no > 0)
2088                         out_addline_infile(out, m->line_no);
2089                 s = g_strdup_printf("\n___%x_", (guint)m->unique_id);
2090                 print_method(out, "static ", s, "", " ", "", "\n",
2091                              m, FALSE, FALSE, FALSE);
2092                 g_free(s);
2093                 out_addline_outfile(out);
2094                 s = replace_sep(m->otype, '_');
2095                 g_strup(s);
2096                 args = get_arg_names_for_macro(m);
2097                 if(is_void) {
2098                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
2099                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
2100                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n",
2101                                    args, s, get_real_id(m->id), s, get_real_id(m->id), args);
2102                 } else {
2103                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
2104                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
2105                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n"
2106                                    "\t\t(",
2107                                    args, s, get_real_id(m->id), s, get_real_id(m->id), args);
2108                         out_printf(out, "(");
2109                         print_type(out, m->mtype, TRUE);
2110                         out_printf(out, ")%s))\n",
2111                                    m->onerror?m->onerror:"0");
2112                 }
2113                 g_free(args);
2114                 g_free(s);
2115                 print_method_body(m, TRUE);
2116                 /* the outfile line was added above */
2117                 out_printf(out, "#undef PARENT_HANDLER\n");
2118                 break;
2119         default:
2120                 break;
2121         }
2122 }
2123
2124 static void
2125 open_files(void)
2126 {
2127         char *outfile, *outfileh, *outfileph;
2128
2129         if(!for_cpp)
2130                 outfile = g_strconcat(filebase, ".c", NULL);
2131         else
2132                 outfile = g_strconcat(filebase, ".cc", NULL);
2133         if(no_touch_headers)
2134                 outfileh = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
2135         else
2136                 outfileh = g_strconcat(filebase, ".h", NULL);
2137
2138         if((privates > 0 || protecteds > 0 ||
2139             private_header == PRIVATE_HEADER_ALWAYS) &&
2140            private_header != PRIVATE_HEADER_NEVER)
2141                 outfileph = g_strconcat(filebase, "-private.h", NULL);
2142         else
2143                 outfileph = NULL;
2144
2145         
2146         if(no_write) {
2147                 devnull = fopen("/dev/null", "w");
2148                 if(!devnull)
2149                         g_error("Cannot open null device");
2150                 out = devnull;
2151                 outh = devnull;
2152                 if(outfileph)
2153                         outph = devnull;
2154         } else {
2155                 out = fopen(outfile, "w");
2156                 if(!out) {
2157                         g_error("Cannot open outfile: %s", outfile);
2158                 }
2159                 outh = fopen(outfileh, "w");
2160                 if(!outh)
2161                         g_error("Cannot open outfile: %s", outfileh);
2162                 if(outfileph) {
2163                         outph = fopen(outfileph, "w");
2164                         if(!outph)
2165                                 g_error("Cannot open outfile: %s", outfileh);
2166                 }
2167         }
2168 }
2169
2170 static void
2171 put_argument_nongnu_wrappers(Class *c)
2172 {
2173         GList *li;
2174
2175         if(get_arguments < 0 && set_arguments < 0)
2176                 return;
2177
2178         for(li=c->nodes;li;li=g_list_next(li)) {
2179                 Node *n = li->data;
2180                 Argument *a = (Argument *)n;
2181                 char *aname;
2182                 char *cast;
2183
2184                 if(n->type != ARGUMENT_NODE)
2185                         continue;
2186
2187                 aname = g_strdup(a->name);
2188                 g_strup(aname);
2189
2190                 if(a->atype)
2191                         cast = get_type(a->atype, TRUE);
2192                 else
2193                         cast = g_strdup(get_cast(a->gtktype, TRUE));
2194
2195                 if(cast) {
2196                         if(a->set)
2197                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2198                                            "\"%s\",(%s)(arg)\n",
2199                                            macrobase, aname, a->name, cast);
2200                         if(a->get)
2201                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2202                                            "\"%s\",(%s*)(arg)\n",
2203                                            macrobase, aname, a->name, cast);
2204                 } else {
2205                         if(a->set)
2206                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2207                                            "\"%s\",(arg)\n",
2208                                            macrobase, aname, a->name);
2209                         if(a->get)
2210                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2211                                            "\"%s\",(arg)\n",
2212                                            macrobase, aname, a->name);
2213                 }
2214                 g_free(cast);
2215                 g_free(aname);
2216         }
2217 }
2218
2219 static void
2220 put_argument_gnu_wrappers(Class *c)
2221 {
2222         GList *li;
2223
2224         if(get_arguments < 0 && set_arguments < 0)
2225                 return;
2226
2227         for(li=c->nodes;li;li=g_list_next(li)) {
2228                 Node *n = li->data;
2229                 Argument *a = (Argument *)n;
2230                 char *s;
2231                 char *cast;
2232                 if(n->type != ARGUMENT_NODE)
2233                         continue;
2234                 s = g_strdup(a->name);
2235                 g_strup(s);
2236                 if(a->atype)
2237                         cast = get_type(a->atype, TRUE);
2238                 else
2239                         cast = g_strdup(get_cast(a->gtktype, TRUE));
2240                 if(cast) {
2241                         if(a->set)
2242                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2243                                            "\"%s\",({%sz = (arg); z;})\n",
2244                                            macrobase, s, a->name, cast);
2245                         if(a->get)
2246                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2247                                            "\"%s\",({%s*z = (arg); z;})\n",
2248                                            macrobase, s, a->name, cast);
2249                 } else {
2250                         if(a->set)
2251                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2252                                            "\"%s\",(arg)\n",
2253                                            macrobase, s, a->name);
2254                         if(a->get)
2255                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2256                                            "\"%s\",(arg)\n",
2257                                            macrobase, s, a->name);
2258                 }
2259                 g_free(cast);
2260                 g_free(s);
2261         }
2262 }
2263
2264 static void
2265 print_ccode_block(CCode *cc)
2266 {
2267         FILE *fp;
2268         switch(cc->cctype) {
2269         case HT_CCODE:
2270                 /* HT code is printed exactly like normal header
2271                    code but is printed before */
2272         case H_CCODE:
2273                 fp = outh;
2274                 out_printf(fp, "\n");
2275                 break;
2276         case AT_CCODE:
2277                 /* AT code is printed exactly like normal 'all'
2278                    code but is printed before */
2279         case A_CCODE:
2280                 if(outph) {
2281                         out_printf(outph, "\n");
2282                         out_printf(outph, "%s\n", cc->cbuf);
2283                         out_addline_infile(outph, cc->line_no);
2284                         out_addline_outfile(outph);
2285                 }
2286                 out_printf(outh, "\n");
2287                 out_printf(outh, "%s\n", cc->cbuf);
2288                 fp = out;
2289                 out_printf(fp, "\n");
2290                 out_addline_infile(fp, cc->line_no);
2291                 break;
2292         default:
2293         case C_CCODE:
2294                 fp = out;
2295                 out_printf(fp, "\n");
2296                 out_addline_infile(fp, cc->line_no);
2297                 break;
2298         case PH_CCODE:
2299                 if(outph)
2300                         fp = outph;
2301                 else
2302                         fp = out;
2303                 out_printf(fp, "\n");
2304                 out_addline_infile(fp, cc->line_no);
2305                 break;
2306         }
2307         out_printf(fp, "%s\n", cc->cbuf);
2308         if(cc->cctype == C_CCODE ||
2309            cc->cctype == A_CCODE ||
2310            cc->cctype == AT_CCODE ||
2311            cc->cctype == PH_CCODE)
2312                 out_addline_outfile(fp);
2313 }
2314
2315 static void
2316 print_class_block(Class *c)
2317 {
2318         GList *l;
2319         char *s;
2320         gboolean printed_private = FALSE;
2321
2322         if(any_special) {
2323                 out_printf(out, "/* utility types we may need */\n");
2324                 if(special_array[SPECIAL_2POINTER])
2325                         out_printf(out, "typedef struct { "
2326                                    "gpointer a; gpointer b; "
2327                                    "} ___twopointertype;\n");
2328                 if(special_array[SPECIAL_3POINTER])
2329                         out_printf(out, "typedef struct { "
2330                                    "gpointer a; gpointer b; "
2331                                    "gpointer c; "
2332                                    "} ___threepointertype;\n");
2333                 if(special_array[SPECIAL_INT_POINTER])
2334                         out_printf(out, "typedef struct { "
2335                                    "gint a; gpointer b; "
2336                                    "} ___intpointertype;\n");
2337                 out_printf(out, "\n");
2338         }
2339
2340         out_printf(outh, "\n/*\n"
2341                    " * Type checking and casting macros\n"
2342                    " */\n");
2343         out_printf(outh, "#define %s\t"
2344                    "(%s_get_type())\n",
2345                    macrotype, funcbase);
2346         out_printf(outh, "#define %s(obj)\t"
2347                    "GTK_CHECK_CAST((obj), %s_get_type(), %s)\n",
2348                    macrobase, funcbase, typebase);
2349         out_printf(outh, "#define %s_CONST(obj)\t"
2350                    "GTK_CHECK_CAST((obj), %s_get_type(), %s const)\n",
2351                    macrobase, funcbase, typebase); 
2352         out_printf(outh, "#define %s_CLASS(klass)\t"
2353                    "GTK_CHECK_CLASS_CAST((klass), %s_get_type(), %sClass)\n",
2354                    macrobase, funcbase, typebase);
2355         out_printf(outh, "#define %s(obj)\t"
2356                    "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
2357                    macrois, funcbase);
2358         out_printf(outh, "#ifdef GTK_CHECK_GET_CLASS\n"
2359                    "#define %s_GET_CLASS(obj)\t"
2360                    "GTK_CHECK_GET_CLASS((obj), %s_get_type(), %sClass)\n",
2361                    macrobase, funcbase, typebase);
2362         out_printf(outh, "#else /* !GTK_CHECK_GET_CLASS */\n"
2363                    "#define %s_GET_CLASS(obj)\t"
2364                    "((%sClass *)GTK_OBJECT(obj)->klass)\n"
2365                    "#endif /* GTK_CHECK_GET_CLASS */\n",
2366                    macrobase, typebase);
2367
2368         if( ! no_self_alias) {
2369                 out_printf(out, "/* self casting macros */\n");
2370                 out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
2371                 out_printf(out, "#define SELF_CONST(x) %s_CONST(x)\n", macrobase);
2372                 out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
2373                 out_printf(out, "#define TYPE_SELF %s\n", macrotype);
2374                 out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n",
2375                            macrobase);
2376                 out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n",
2377                            macrobase);
2378
2379                 out_printf(out, "/* self typedefs */\n");
2380                 out_printf(out, "typedef %s Self;\n", typebase);
2381                 out_printf(out, "typedef %sClass SelfClass;\n\n", typebase);
2382         }
2383
2384         out_printf(out, "/* GTK_CLASS_TYPE for 1.2<->1.3/2.0 GTK+ compatibility */\n");
2385         out_printf(out,
2386                    "#ifndef GTK_CLASS_TYPE\n"
2387                    "#define GTK_CLASS_TYPE(x) (GTK_OBJECT_CLASS(x)->type)\n"
2388                    "#endif /* GTK_CLASS_TYPE */\n\n");
2389
2390         if(privates > 0 || always_private_struct) {
2391                 out_printf(outh, "\n/* Private structure type */\n");
2392                 out_printf(outh, "typedef struct _%sPrivate %sPrivate;\n",
2393                            typebase, typebase);
2394                 if(privates == 0)
2395                         out_printf(outh, "/* There are no privates, this "
2396                                    "structure is thus never defined */\n");
2397         }
2398
2399         out_printf(outh, "\n/*\n"
2400                    " * Main object structure\n"
2401                    " */\n");
2402         s = replace_sep(c->otype, '_');
2403         g_strup(s);
2404         out_printf(outh, "#ifndef __TYPEDEF_%s__\n"
2405                    "#define __TYPEDEF_%s__\n", s, s);
2406         g_free(s);
2407         out_printf(outh, "typedef struct _%s %s;\n"
2408                    "#endif\n", typebase, typebase);
2409         out_printf(outh, "struct _%s {\n\t%s __parent__;\n",
2410                    typebase, ptypebase);
2411         for(l=c->nodes; l; l=g_list_next(l)) {
2412                 static gboolean printed_public = FALSE;
2413                 Node *n = l->data;
2414                 Variable *v = (Variable *)n;
2415                 if(n->type == VARIABLE_NODE &&
2416                    v->scope == PUBLIC_SCOPE) {
2417                         if( ! printed_public) {
2418                                 out_printf(outh, "\t/*< public >*/\n");
2419                                 printed_public = TRUE;
2420                         }
2421                         put_variable((Variable *)n, outh);
2422                 }
2423         }
2424         /* put protecteds always AFTER publics */
2425         for(l=c->nodes; l; l=g_list_next(l)) {
2426                 Node *n = l->data;
2427                 Variable *v = (Variable *)n;
2428                 if(n->type == VARIABLE_NODE &&
2429                    v->scope == PROTECTED_SCOPE) {
2430                         if( ! printed_private) {
2431                                 out_printf(outh, "\t/*< private >*/\n");
2432                                 printed_private = TRUE;
2433                         }
2434                         put_variable((Variable *)n, outh);
2435                 }
2436         }
2437         if(privates > 0 || always_private_struct) {
2438                 if( ! printed_private)
2439                         out_printf(outh, "\t/*< private >*/\n");
2440                 out_printf(outh, "\t%sPrivate *_priv;\n", typebase);
2441         }
2442         out_printf(outh, "};\n");
2443
2444         if(privates > 0) {
2445                 FILE *outfp;
2446
2447                 /* if we are to stick this into the private
2448                    header, if not stick it directly into the
2449                    C file */
2450                 if(outph) 
2451                         outfp = outph;
2452                 else
2453                         outfp = out;
2454
2455                 out_printf(outfp, "struct _%sPrivate {\n",
2456                            typebase);
2457                 for(l=c->nodes; l; l=l->next) {
2458                         Node *n = l->data;
2459                         Variable *v = (Variable *)n;
2460                         if(n->type == VARIABLE_NODE &&
2461                            v->scope == PRIVATE_SCOPE) {
2462                                 out_addline_infile(outfp, v->line_no);
2463                                 put_variable(v, outfp);
2464                         }
2465                 }
2466                 out_addline_outfile(outfp);
2467                 out_printf(outfp, "};\n");
2468         }
2469
2470         out_printf(outh, "\n/*\n"
2471                    " * Class definition\n"
2472                    " */\n");
2473         out_printf(outh, "typedef struct _%sClass %sClass;\n",
2474                    typebase, typebase);
2475         out_printf(outh,
2476                    "struct _%sClass {\n\t%sClass __parent__;\n",
2477                    typebase, ptypebase);
2478         for(l = c->nodes; l != NULL; l = l->next) {
2479                 Node *n = l->data;
2480                 if(n->type == METHOD_NODE)
2481                         put_vs_method((Method *)n);
2482         }
2483         /* If BonoboX type class put down the epv */
2484         if (c->bonobo_x_class != NULL) {
2485                 out_printf (outh,
2486                             "\t/* Bonobo object epv */\n"
2487                             "\tPOA_%s__epv _epv;\n",
2488                             c->bonobo_x_class);
2489         }
2490         /* put class scope variables */
2491         for(l = c->nodes; l != NULL; l = l->next) {
2492                 Node *n = l->data;
2493                 Variable *v = (Variable *)n;
2494                 if(n->type == VARIABLE_NODE &&
2495                    v->scope == CLASS_SCOPE)
2496                         put_variable((Variable *)n, outh);
2497         }
2498         out_printf(outh, "};\n\n");
2499
2500         out_printf(out, "/* here are local prototypes */\n");
2501         if(set_arguments > 0) {
2502                 out_printf(out, "static void ___object_set_arg "
2503                            "(GtkObject *object, GtkArg *arg, "
2504                            "guint arg_id);\n");
2505         }
2506         if(get_arguments > 0) {
2507                 out_printf(out, "static void ___object_get_arg "
2508                            "(GtkObject *object, GtkArg *arg, "
2509                            "guint arg_id);\n");
2510         }
2511
2512         out_printf(outh, "\n/*\n"
2513                    " * Public methods\n"
2514                    " */\n");
2515
2516         if ( ! overrode_get_type) {
2517                 out_printf(outh, "GtkType\t%s_get_type\t(void)", funcbase);
2518                 if ( ! no_gnu) {
2519                         out_printf(outh, " G_GNUC_CONST;\n");
2520                 } else {
2521                         out_printf(outh, ";\n");
2522                 }
2523         }
2524
2525         for(l = c->nodes; l != NULL; l = l->next) {
2526                 Node *n = l->data;
2527                 if(n->type == METHOD_NODE) {
2528                         put_pub_method((Method *)n);
2529                         put_prot_method((Method *)n);
2530                         put_priv_method_prot((Method *)n);
2531                 }
2532         }
2533
2534         /* this idea is less and less apealing to me */
2535         if (signals > 0) {
2536                 out_printf (outh, "\n/*\n"
2537                             " * Signal connection wrapper macros\n"
2538                             " */\n");
2539                 if( ! no_gnu) {
2540                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2541                         put_signal_macros (c, TRUE);
2542                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
2543                         put_signal_macros (c, FALSE);
2544                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
2545                 } else {
2546                         put_signal_macros (c, FALSE);
2547                 }
2548         }
2549
2550         /* argument wrapping macros */
2551         if(get_arguments > 0 || set_arguments > 0) {
2552                 out_printf(outh, "\n/*\n"
2553                            " * Argument wrapping macros\n"
2554                            " */\n");
2555                 if( ! no_gnu) {
2556                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2557                         put_argument_gnu_wrappers(c);
2558                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
2559                         put_argument_nongnu_wrappers(c);
2560                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
2561                 } else {
2562                         put_argument_nongnu_wrappers(c);
2563                 }
2564         }
2565
2566         if(signals > 0) {
2567                 for(l = c->nodes; l != NULL; l = l->next) {
2568                         Node *n = l->data;
2569                         if(n->type == METHOD_NODE)
2570                                 add_signal_prots((Method *)n);
2571                 }
2572         }
2573
2574         add_enums(c);
2575
2576         if ( ! overrode_get_type) {
2577                 if (c->bonobo_x_class != NULL)
2578                         add_bonobo_x_get_type ();
2579                 else
2580                         add_get_type ();
2581         }
2582
2583         if(any_method_to_alias(c)) {
2584                 if( ! no_gnu) {
2585                         out_printf(out, "/* Short form macros */\n");
2586                         out_printf(out, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2587                         make_method_gnu_aliases(c);
2588                         out_printf(out, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n");
2589                 }
2590                 make_method_nongnu_aliases(c);
2591         }
2592
2593         out_printf(out, "/* a macro for creating a new object of our type */\n");
2594         out_printf(out,
2595                    "#define GET_NEW ((%s *)gtk_type_new(%s_get_type()))\n\n",
2596                    typebase, funcbase);
2597
2598         if(need_destroy)
2599                 add_destroy(c);
2600
2601         if(need_finalize)
2602                 add_finalize(c);
2603
2604         add_inits(c);
2605
2606         if(set_arguments > 0) {
2607                 add_getset_arg(c, TRUE);
2608         }
2609
2610         if(get_arguments > 0) {
2611                 add_getset_arg(c, FALSE);
2612         }
2613
2614         for(l = c->nodes; l != NULL; l = l->next) {
2615                 Node *n = l->data;
2616                 if(n->type == METHOD_NODE)
2617                         put_method((Method *)n);
2618         }
2619
2620         add_bad_hack_to_avoid_unused_warnings(c);
2621 }
2622
2623 static void
2624 print_version_macros(void)
2625 {
2626         int major=0, minor=0, pl=0;
2627         sscanf(VERSION, "%d.%d.%d", &major, &minor, &pl);
2628
2629         out_printf(out, "#define GOB_VERSION_MAJOR %d\n", major);
2630         out_printf(out, "#define GOB_VERSION_MINOR %d\n", minor);
2631         out_printf(out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
2632 }
2633
2634 static void
2635 print_file_comments(void)
2636 {
2637         time_t curtime;
2638         time(&curtime);
2639         out_printf(outh, "/* Generated by GOB (v%s)"
2640                    "   (do not edit directly) */\n\n", VERSION);
2641         if(outph)
2642                 out_printf(outph, "/* Generated by GOB (v%s)"
2643                            "   (do not edit directly) */\n\n", VERSION);
2644         out_printf(out, "/* Generated by GOB (v%s) on %s"
2645                    "   (do not edit directly) */\n\n",
2646                    VERSION, ctime(&curtime));
2647
2648         out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
2649 }
2650
2651 static void
2652 print_includes(void)
2653 {
2654         gboolean found_header;
2655         char *p;
2656
2657         /* We may need string.h for memset */
2658         if(destructors > 0 &&
2659            ! g_list_find_custom(include_files, "string.h", (GCompareFunc)strcmp)) {
2660                 out_printf(out, "#include <string.h> /* memset() */\n\n");
2661         }
2662
2663         p = g_strconcat(filebase, ".h", NULL);
2664         found_header = TRUE;
2665         if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
2666                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
2667                 found_header = FALSE;
2668         }
2669         g_free(p);
2670
2671         /* if we are creating a private header see if it was included */
2672         if(outph) {
2673                 p = g_strconcat(filebase, "-private.h", NULL);
2674                 if( ! g_list_find_custom(include_files, p,
2675                                          (GCompareFunc)strcmp)) {
2676                         out_printf(out, "#include \"%s-private.h\"\n\n",
2677                                    filebase);
2678                         if(found_header)
2679                                 error_printf(GOB_WARN, 0,
2680                                             "Implicit private header include "
2681                                             "added to top of\n"
2682                                             "\tsource file, while public "
2683                                             "header is at a custom location, "
2684                                             "you should\n"
2685                                             "\texplicitly include "
2686                                             "the private header below the "
2687                                             "public one.");
2688                 }
2689                 g_free(p);
2690         }
2691 }
2692
2693 static void
2694 print_header_prefixes(void)
2695 {
2696         char *p;
2697
2698         p = replace_sep(((Class *)class)->otype, '_');
2699         g_strup(p);
2700         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
2701         if(outph)
2702                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
2703                            "#define __%s_PRIVATE_H__\n\n"
2704                            "#include \"%s.h\"\n\n", p, p, filebase);
2705         g_free(p);
2706
2707         if( ! no_extern_c) {
2708                 out_printf(outh, "#ifdef __cplusplus\n"
2709                            "extern \"C\" {\n"
2710                            "#endif /* __cplusplus */\n\n");
2711                 if(outph)
2712                         out_printf(outph, "#ifdef __cplusplus\n"
2713                                    "extern \"C\" {\n"
2714                                    "#endif /* __cplusplus */\n\n");
2715         }
2716 }
2717
2718 static void
2719 print_header_postfixes(void)
2720 {
2721         if( ! no_extern_c)
2722                 out_printf(outh, "\n#ifdef __cplusplus\n"
2723                            "}\n"
2724                            "#endif /* __cplusplus */\n");
2725         out_printf(outh, "\n#endif\n");
2726         if(outph) {
2727                 if( ! no_extern_c)
2728                         out_printf(outph, "\n#ifdef __cplusplus\n"
2729                                    "}\n"
2730                                    "#endif /* __cplusplus */\n");
2731                 out_printf(outph, "\n#endif\n");
2732         }
2733 }
2734
2735 static void
2736 print_all_top(void)
2737 {
2738         GList *li;
2739
2740         /* print the AT_CCODE blocks */
2741         for(li = nodes; li != NULL; li = li->next) {
2742                 Node *node = li->data;
2743                 if(node->type == CCODE_NODE) {
2744                         CCode *cc = (CCode *)node;
2745                         if(cc->cctype == AT_CCODE)
2746                                 print_ccode_block((CCode *)node);
2747                 }
2748         }
2749 }
2750
2751 static void
2752 print_header_top(void)
2753 {
2754         GList *li;
2755
2756         /* mandatory include */
2757         out_printf(outh, "#include <gtk/gtk.h>\n\n");
2758
2759         /* print the HT_CCODE blocks */
2760         for(li=nodes;li;li=g_list_next(li)) {
2761                 Node *node = li->data;
2762                 if(node->type == CCODE_NODE) {
2763                         CCode *cc = (CCode *)node;
2764                         if(cc->cctype == HT_CCODE)
2765                                 print_ccode_block((CCode *)node);
2766                 }
2767         }
2768 }
2769
2770 static void
2771 generate_outfiles(void)
2772 {
2773         GList *li;
2774
2775         print_file_comments();
2776
2777         print_all_top();
2778
2779         print_header_top();
2780
2781         print_header_prefixes();
2782
2783         print_version_macros();
2784
2785         print_includes();
2786
2787         for(li=nodes;li;li=g_list_next(li)) {
2788                 Node *node = li->data;
2789                 if(node->type == CCODE_NODE) {
2790                         CCode *cc = (CCode *)node;
2791                         if(cc->cctype != HT_CCODE &&
2792                            cc->cctype != AT_CCODE)
2793                                 print_ccode_block((CCode *)node);
2794                 } else if(node->type == CLASS_NODE) {
2795                         print_class_block((Class *)node);
2796                 } else
2797                         g_assert_not_reached();
2798         }
2799
2800         print_header_postfixes();
2801 }
2802
2803 static void
2804 print_help(void)
2805 {
2806         fprintf(stderr, "Gob version %s\n\n", VERSION);
2807         fprintf(stderr, "gob [options] file.gob\n\n");
2808         fprintf(stderr, "Options:\n"
2809                 "\t--help,-h,-?            Display this help\n"
2810                 "\t--version               Display version\n"
2811                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
2812                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
2813                 "\t--for-cpp               Create C++ files\n"
2814                 "\t--no-extern-c           Never print extern \"C\" into the "
2815                                           "header\n"
2816                 "\t--no-gnu                Never use GNU extentions\n"
2817                 "\t--no-touch-headers      Don't touch headers unless they "
2818                                           "really changed\n"
2819                 "\t--always-private-header Always create a private header "
2820                                           "file,\n"
2821                 "\t                        even if it would be empty "
2822                                           "[default]\n"
2823                 "\t--ondemand-private-header Create private header only when "
2824                                           "needed\n"
2825                 "\t--no-private-header     Don't create a private header, "
2826                                           "put private\n"
2827                 "\t                        structure and protected "
2828                                           "prototypes inside c file\n"
2829                 "\t--always-private-struct Always create a private pointer "
2830                                           "in\n"
2831                 "\t                        the object structure\n"
2832                 "\t--no-write,-n           Don't write output files, just "
2833                                           "check syntax\n"
2834                 "\t--no-lines              Don't print '#line' to output\n"
2835                 "\t--no-self-alias         Don't create self type and macro "
2836                                           "aliases\n"
2837                 "\t--no-kill-underscores   Don't remove the leading underscore "
2838                                           "from\n"
2839                 "\t                        short id names\n");
2840 }
2841
2842 static void
2843 parse_options(int argc, char *argv[])
2844 {
2845         int i;
2846         int got_file = FALSE;
2847         int no_opts = FALSE;
2848
2849         filename = NULL;
2850
2851         for(i = 1 ; i < argc; i++) {
2852                 if(no_opts ||
2853                    argv[i][0] != '-') {
2854                         /*must be a file*/
2855                         if(got_file) {
2856                                 fprintf(stderr, "Specify only one file!\n");
2857                                 print_help();
2858                                 exit(1);
2859                         }
2860                         filename = argv[i];
2861                         got_file = TRUE;
2862                 } else if(strcmp(argv[i], "--help")==0) {
2863                         print_help();
2864                         exit(0);
2865                 } else if(strcmp(argv[i], "--version")==0) {
2866                         fprintf(stderr, "Gob version %s\n", VERSION);
2867                         exit(0);
2868                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
2869                         exit_on_warn = TRUE;
2870                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
2871                         exit_on_warn = FALSE;
2872                 } else if(strcmp(argv[i], "--for-cpp")==0) {
2873                         for_cpp = TRUE;
2874                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
2875                         no_touch_headers = TRUE;
2876                 } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
2877                         private_header = PRIVATE_HEADER_ONDEMAND;
2878                 } else if(strcmp(argv[i], "--always-private-header")==0) {
2879                         private_header = PRIVATE_HEADER_ALWAYS;
2880                 } else if(strcmp(argv[i], "--no-private-header")==0) {
2881                         private_header = PRIVATE_HEADER_NEVER;
2882                 } else if(strcmp(argv[i], "--no-gnu")==0) {
2883                         no_gnu = TRUE;
2884                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
2885                         no_extern_c = TRUE;
2886                 } else if(strcmp(argv[i], "--no-write")==0) {
2887                         no_write = TRUE;
2888                 } else if(strcmp(argv[i], "--no-lines")==0) {
2889                         no_lines = TRUE;
2890                 } else if(strcmp(argv[i], "--no-self-alias")==0) {
2891                         no_self_alias = TRUE;
2892                 } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
2893                         no_kill_underscores = TRUE;
2894                 } else if(strcmp(argv[i], "--always-private-struct")==0) {
2895                         always_private_struct = TRUE;
2896                 } else if(strcmp(argv[i], "--")==0) {
2897                         /*further arguments are files*/
2898                         no_opts = TRUE;
2899                 } else if(strncmp(argv[i], "--", 2)==0) {
2900                         /*unknown long option*/
2901                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
2902                         print_help();
2903                         exit(1);
2904                 } else {
2905                         /*by now we know we have a string starting with
2906                           - which is a short option string*/
2907                         char *p;
2908                         for(p = argv[i] + 1; *p; p++) {
2909                                 switch(*p) {
2910                                 case 'w':
2911                                         exit_on_warn=TRUE;
2912                                         break;
2913                                 case 'n':
2914                                         no_write = TRUE;
2915                                         break;
2916                                 case 'h':
2917                                 case '?':
2918                                         print_help();
2919                                         exit(0);
2920                                 default:
2921                                         fprintf(stderr,
2922                                                 "Unknown option '%c'!\n", *p);
2923                                         print_help();
2924                                         exit(1);
2925                                 }
2926                         }
2927                 }
2928         }
2929 }
2930
2931 /* this is a somewhat ugly hack, but it appears to work */
2932 static void
2933 compare_and_move_header(void)
2934 {
2935         char *hfnew = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
2936         char *hf = g_strconcat(filebase, ".h", NULL);
2937         struct stat s;
2938         if(stat(hf, &s) == 0) {
2939                 char *s;
2940                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
2941                 if(system(s) == 0) {
2942                         if(unlink(hfnew) != 0)
2943                                 error_printf(GOB_ERROR, 0,
2944                                              "Can't remove new header file");
2945                         g_free(hfnew);
2946                         g_free(hf);
2947                         g_free(s);
2948                         return;
2949                 }
2950                 g_free(s);
2951                 if(unlink(hf) != 0)
2952                         error_printf(GOB_ERROR, 0,
2953                                      "Can't remove old header file");
2954         }
2955         if(rename(hfnew, hf) != 0)
2956                 error_printf(GOB_ERROR, 0,
2957                              "Can't rename new header file");
2958         g_free(hfnew);
2959         g_free(hf);
2960 }
2961
2962 int
2963 main(int argc, char *argv[])
2964 {
2965         parse_options(argc, argv);
2966         
2967         if(filename) {
2968                 yyin = fopen(filename, "r");
2969                 if(!yyin) {
2970                         fprintf(stderr, "Error: can't open file '%s'\n",
2971                                 filename);
2972                         exit(1);
2973                 }
2974         } else
2975                 filename = "stdin";
2976
2977         /* This is where parsing is done */
2978         /*yydebug = 1;*/
2979         if(yyparse() != 0)
2980                 g_error("Parsing errors, quitting");
2981
2982         if( ! class)
2983                 error_print(GOB_ERROR, 0, " no class defined");
2984         
2985
2986         exit_on_error = FALSE;
2987
2988         signals = count_signals((Class *)class);
2989         set_arguments = count_set_arguments((Class *)class);
2990         get_arguments = count_get_arguments((Class *)class);
2991         overrides = count_overrides((Class *)class);
2992         privates = count_privates((Class *)class);
2993         protecteds = count_protecteds((Class *)class);
2994         destructors = count_destructors((Class *)class);
2995         initializers = count_initializers((Class *)class);
2996         overrode_get_type = find_get_type((Class *)class);
2997
2998         make_bases();
2999         make_inits((Class *)class);
3000         if(destructors > 0) {
3001                 need_destroy = TRUE;
3002                 find_destroy((Class *)class);
3003         }
3004         if(privates > 0) {
3005                 need_finalize = TRUE;
3006                 find_finalize((Class *)class);
3007         }
3008         check_bad_symbols((Class *)class);
3009         check_duplicate_symbols((Class *)class);
3010         check_duplicate_overrides((Class *)class);
3011         check_duplicate_signals_args((Class *)class);
3012         check_public_new((Class *)class);
3013         check_vararg((Class *)class);
3014         check_firstarg((Class *)class);
3015         check_nonvoidempty((Class *)class);
3016         check_signal_args((Class *)class);
3017         check_argument_types((Class *)class);
3018         check_func_arg_checks((Class *)class);
3019
3020         exit_on_error = TRUE;
3021         
3022         if(got_error)
3023                 exit(1);
3024
3025         any_special = setup_special_array((Class *)class, special_array);
3026
3027         open_files();
3028         
3029         generate_outfiles();
3030
3031         if(devnull)
3032                 fclose(devnull);
3033         else {
3034                 fclose(out);
3035                 fclose(outh);
3036                 if(outph)
3037                         fclose(outph);
3038         }
3039
3040         if(no_touch_headers &&
3041            ! no_write)
3042                 compare_and_move_header();
3043         
3044         return 0;
3045 }