]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
61125d8727b83100307f729ff384f630c9e8cdcf
[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  * Copyright (C) 2001-2011 George (Jiri) Lebl
5  * Copyright © 2019-2020 Nick Bowler
6  *
7  * Author: George (Jiri) Lebl
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the  Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22  * USA.
23  */
24
25 #include <config.h>
26 #include <glib.h>
27 #include <time.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <sys/stat.h>
34
35 #include "treefuncs.h"
36 #include "parse.h"
37 #include "out.h"
38 #include "util.h"
39 #include "checks.h"
40
41 #include "main.h"
42
43 char *filename = NULL;
44
45 int yyparse(void);
46
47 extern int yydebug;
48 extern FILE * yyin;
49 extern Node *class;
50 extern GList *nodes;
51 extern GList *enums;
52
53 extern GList *include_files;
54
55 extern GHashTable *gtk_doc_hash;
56
57 char *filebase;
58 char *fullfilebase;
59 static char *outfilebase;
60 static char *outfilehbase;
61 static char *outfilephbase;
62 static char *funcbase;
63 static char *pfuncbase;
64 static char *macrobase;
65 static char *macrois;
66 static char *pmacrois;
67 static char *macrotype;
68 static char *pmacrotype;
69 static char *typebase;
70 static char *ptypebase;
71
72 char *output_dir = NULL;
73
74 char file_sep = '-';
75
76 static int signals = 0; /* number of signals */
77 static int set_properties = 0; /* number of named (set) properties */
78 static int get_properties = 0; /* number of named (get) properties */
79 static int overrides = 0; /* number of override methods */
80 static int privates = 0; /* number of private data members */
81 static int protecteds = 0; /* number of protected methods */
82 static int unreftors = 0; /* number of variable unreffing destructors */
83 static int destructors = 0; /* number of variable non-unreffing destructors */
84 static int initializers = 0; /* number of variable initializers */
85 static int glade_widgets = 0; /* number of glade widgets */
86 static gboolean overrode_get_type = FALSE; /* provided your won _get_type */
87
88 static gboolean made_aliases = FALSE;  /* if we made any shorthand aliases
89                                           and need the REALLY UGLY HACK to
90                                           avoid warnings */
91
92 /* the special variable types we need to define */
93 static gboolean special_array[SPECIAL_LAST] = {0};
94 static gboolean any_special = FALSE;
95
96 static gboolean need_constructor = FALSE;
97 static Method * user_constructor = NULL;
98
99 static gboolean need_dispose = FALSE;
100 static Method * dispose_handler = NULL;
101 static Method * user_dispose_method = NULL;
102  
103 static gboolean need_finalize = FALSE;
104 static Method * finalize_handler = NULL;
105 static Method * user_finalize_method = NULL;
106
107 FILE *out = NULL;
108 FILE *outh = NULL;
109 FILE *outph = NULL;
110
111 gboolean no_touch = FALSE;
112 gboolean no_touch_headers = FALSE;
113 gboolean for_cpp = FALSE;
114 gboolean no_gnu = FALSE;
115 gboolean exit_on_warn = FALSE;
116 gboolean exit_on_error = TRUE;
117 gboolean got_error = FALSE;
118 gint private_header = PRIVATE_HEADER_ONDEMAND;
119 gboolean no_extern_c = FALSE;
120 gboolean no_write = FALSE;
121 gboolean no_lines = FALSE;
122 gboolean no_self_alias = FALSE;
123 gboolean always_private_struct = FALSE;
124 gboolean gtk3_ok = FALSE;
125
126 gint prealloc = 0;
127
128
129
130 gboolean use_m4 = FALSE; /* preprocess sources with m4 */
131 gboolean use_m4_clean = FALSE; /* preprocess sources with m4, no m4 flags */
132 char *m4_commandline = NULL;
133 #define M4_INCLUDE_DIR  PKGDATADIR "/m4"
134 #define M4_BASE_FILENAME "gobm4.m4"
135 #define M4_FLAGS "-P -s -I" M4_INCLUDE_DIR  " -DGOBM4_GOB_VERSION=" VERSION " " M4_BASE_FILENAME
136 #define M4_COMMANDLINE "m4"
137
138 int method_unique_id = 1;
139
140 static void
141 make_bases (void)
142 {
143         filebase = replace_sep (((Class *)class)->otype, file_sep);
144         gob_strdown (filebase);
145
146         if (output_dir != NULL &&
147             output_dir[0] != '\0') {
148                 fullfilebase = g_build_filename (output_dir, filebase, NULL);
149         } else {
150                 fullfilebase = g_strdup (filebase);
151         }
152
153         funcbase = replace_sep (((Class *)class)->otype, '_');
154         gob_strdown (funcbase);
155
156         pfuncbase = replace_sep (((Class *)class)->ptype, '_');
157         gob_strdown (pfuncbase);
158
159         macrobase = replace_sep (((Class *)class)->otype, '_');
160         gob_strup (macrobase);
161         
162         macrois = make_pre_macro (((Class *)class)->otype, "IS");
163         pmacrois = make_pre_macro (((Class *)class)->ptype, "IS");
164
165         macrotype = make_pre_macro (((Class *)class)->otype, "TYPE");
166         pmacrotype = make_pre_macro (((Class *)class)->ptype, "TYPE");
167
168         typebase = remove_sep (((Class *)class)->otype);
169
170         ptypebase = remove_sep (((Class *)class)->ptype);
171 }
172
173 static char *
174 get_gtk_doc (const char *id)
175 {
176         char *val;
177
178         if(!gtk_doc_hash)
179                 return NULL;
180
181         val = g_hash_table_lookup(gtk_doc_hash, id);
182         if(val)
183                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
184                                        funcbase, id, val);
185         val = g_hash_table_lookup(gtk_doc_hash, id);
186         if(val)
187                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
188                                        funcbase, id, val);
189         return NULL;
190 }
191
192 static void
193 print_type(FILE *fp, const Type *t, gboolean postfix_to_stars)
194 {
195         char *s;
196
197         s = get_type(t, postfix_to_stars);
198         out_printf(fp, "%s", s); 
199         g_free(s);
200 }
201
202
203 static void
204 print_method (FILE *fp,
205               const char *typeprefix,
206               const char *nameprefix,
207               const char *subnameprefix,
208               const char *namepostfix,
209               const char *afterargs,
210               const char *postfix,
211               const Method *m,
212               gboolean print_funcattrs,
213               gboolean one_arg_per_line,
214               gboolean no_funcbase,
215               gboolean kill_underscore,
216               gboolean first_unused,
217               gboolean fake_names)
218 {
219         GList *li;
220         const char *id;
221
222         out_printf(fp, "%s", typeprefix); 
223         print_type(fp, m->mtype, TRUE);
224
225         id = m->id;
226
227         if(no_funcbase)
228                 out_printf(fp, "%s%s%s%s(",
229                            nameprefix, subnameprefix, id, namepostfix); 
230         else
231                 out_printf(fp, "%s%s_%s%s%s(",
232                            nameprefix, funcbase, subnameprefix, id,
233                            namepostfix); 
234         
235         if(m->args) {
236                 for(li=m->args; li; li=g_list_next(li)) {
237                         FuncArg *arg = li->data;
238                         const char *unused = "";
239
240                         if ( ! no_gnu &&
241                              ! for_cpp && /* g++ has a cow with this */
242                             li == m->args &&
243                             first_unused) {
244                                 unused = " G_GNUC_UNUSED";
245                         }
246
247                         print_type(fp, arg->atype, FALSE);
248                         if (fake_names)
249                                 out_printf (fp, "___fake___");
250                         if(li->next)
251                                 out_printf(fp, "%s%s%s,%s", arg->name,
252                                            arg->atype->postfix ?
253                                            arg->atype->postfix : "",
254                                            unused,
255                                            one_arg_per_line ? "\n\t\t\t\t\t" : " ");
256                         else
257                                 out_printf(fp, "%s%s%s", arg->name,
258                                            arg->atype->postfix ?
259                                            arg->atype->postfix : "",
260                                            unused); 
261                 }
262                 if(m->vararg)
263                         out_printf(fp, ",%s...",
264                                    one_arg_per_line ? "\n\t\t\t\t\t" : " "); 
265         } else {
266                 out_printf(fp, "void"); 
267         }
268         /* Slightly icky: sometimes we are called st m->funcattrs
269            hasn't been set, but if so it should be NULL since its been
270            zero-initialized.  */
271         if(print_funcattrs && m->funcattrs != NULL
272            && strlen(m->funcattrs) > 0) {
273                 /* To keep the output neat, we trim off the trailing '\n'
274                    from the end of funcattrs for a moment.  */
275                 size_t funcattrs_len = strlen(m->funcattrs);
276                 gboolean funcattrs_chomped = FALSE;
277                 if((m->funcattrs)[funcattrs_len - 1] == '\n') {
278                         m->funcattrs[funcattrs_len - 1] = '\0';
279                         funcattrs_chomped = TRUE;
280                 } 
281                 out_printf(fp, "%s)\n%s%s", afterargs, m->funcattrs, postfix);
282                 /* Put it back like it was (though it shouldn't matter).  */
283                 if (funcattrs_chomped) {
284                         (m->funcattrs)[funcattrs_len - 1] = '\n';
285                 }
286         }
287         else {
288                 out_printf(fp, "%s)%s", afterargs, postfix); 
289         }
290 }
291
292 static gboolean
293 any_method_to_alias(Class *c)
294 {
295         GList *li;
296         
297         for(li=c->nodes;li;li=g_list_next(li)) {
298                 Node *node = li->data;
299                 if(node->type == METHOD_NODE) {
300                         Method *m = (Method *)node;
301                         
302                         if(m->method == INIT_METHOD ||
303                            m->method == CLASS_INIT_METHOD ||
304                            m->method == CONSTRUCTOR_METHOD ||
305                            m->method == DISPOSE_METHOD ||
306                            m->method == FINALIZE_METHOD ||
307                            m->method == OVERRIDE_METHOD)
308                                 continue;
309
310                         return TRUE;
311                 }
312         }
313         return FALSE;
314 }
315
316
317 static void
318 make_method_aliases (Class *c)
319 {
320         GList *li;
321         
322         for(li = c->nodes; li != NULL; li = li->next) {
323                 Node *node = li->data;
324                 if(node->type == METHOD_NODE) {
325                         Method *m = (Method *)node;
326                         
327                         if(m->method == INIT_METHOD ||
328                            m->method == CLASS_INIT_METHOD ||
329                            m->method == CONSTRUCTOR_METHOD ||
330                            m->method == DISPOSE_METHOD ||
331                            m->method == FINALIZE_METHOD ||
332                            m->method == OVERRIDE_METHOD)
333                                 continue;
334
335                         out_printf (out, "#define self_%s %s_%s\n",
336                                     m->id,
337                                     funcbase,
338                                     m->id);
339                 }
340         }
341 }
342
343 static void
344 add_bad_hack_to_avoid_unused_warnings(const Class *c)
345 {
346         GList *li;
347
348         /* if we haven't had any methods, just return */
349         if( ! made_aliases)
350                 return;
351         
352         if( ! no_gnu)
353                 out_printf(out, "\n\n#if (!defined __GNUC__) || (defined __GNUC__ && defined __STRICT_ANSI__)\n");
354         out_printf(out,
355                    "/*REALLY BAD HACK\n"
356                    "  This is to avoid unused warnings if you don't call\n"
357                    "  some method.  I need to find a better way to do\n"
358                    "  this, not needed in GCC since we use some gcc\n"
359                    "  extentions to make saner, faster code */\n"
360                    "static void\n"
361                    "___%s_really_bad_hack_to_avoid_warnings(void)\n"
362                    "{\n", funcbase);
363         out_printf(out, "\t((void (*)(void))GET_NEW_VARG)();\n");
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 == CONSTRUCTOR_METHOD ||
372                            m->method == DISPOSE_METHOD ||
373                            m->method == FINALIZE_METHOD ||
374                            m->method == OVERRIDE_METHOD)
375                                 continue;
376
377                         /* in C++ mode we don't alias new */
378                         if(for_cpp && strcmp(m->id, "new")==0)
379                                 continue;
380
381                         out_printf(out, "\t((void (*)(void))self_%s)();\n", m->id);
382                 }
383         }
384         out_printf(out, "\t___%s_really_bad_hack_to_avoid_warnings();\n",
385                    funcbase);
386         if(!no_gnu)
387                 out_printf(out, "}\n#endif /* !__GNUC__ || (__GNUC__ && __STRICT_ANSI__) */\n\n");
388         else
389                 out_printf(out, "}\n\n");
390 }
391
392 static void
393 put_variable(const Variable *v, FILE *fp)
394 {
395         out_printf(fp, "\t");
396         print_type(fp, v->vtype, FALSE);
397         out_printf(fp, "%s%s;", v->id,
398                    v->vtype->postfix?
399                    v->vtype->postfix:""); 
400         if(v->scope == PROTECTED_SCOPE)
401                 out_printf(fp, " /* protected */");
402         out_printf(fp, "\n");
403 }
404
405 static void
406 put_vs_method(const Method *m)
407 {
408         if(m->method != SIGNAL_LAST_METHOD &&
409            m->method != SIGNAL_FIRST_METHOD &&
410            m->method != VIRTUAL_METHOD)
411                 return;
412
413         /* if a signal mark it as such */
414         if(m->method != VIRTUAL_METHOD)
415                 print_method(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
416                              m, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE);
417         else
418                 print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
419                              m, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE);
420
421 }
422
423 static void
424 put_pub_method(const Method *m)
425 {
426         if(m->scope != PUBLIC_SCOPE)
427                 return;
428
429         out_addline_infile(outh, m->line_no);
430         print_method(outh, "", "\t", "", "\t", "", ";\n", m,
431                      TRUE, TRUE, FALSE, TRUE, FALSE, FALSE);
432         out_addline_outfile(outh);
433 }
434
435 static void
436 put_signal_macro (const Method *m, gboolean gnu)
437 {
438         if(m->method != SIGNAL_LAST_METHOD &&
439            m->method != SIGNAL_FIRST_METHOD)
440                 return;
441
442         if ( ! gnu) {
443                 /* connect */
444                 out_printf (outh, "#define %s_connect__%s(object,func,data)\t"
445                             "g_signal_connect(%s(object),\"%s\","
446                             "(GCallback)(func),(data))\n",
447                             funcbase, m->id, macrobase, m->id);
448
449                 /* connect_after */
450                 out_printf (outh, "#define %s_connect_after__%s(object,func,data)\t"
451                             "g_signal_connect_after(%s(object),\"%s\","
452                             "(GCallback)(func),(data))\n",
453                             funcbase, m->id, macrobase, m->id);
454
455                 /* connect_data */
456                 out_printf (outh, "#define %s_connect_data__%s"
457                             "(object,func,data,destroy_data,flags)\t"
458                             "g_signal_connect_data(%s(object),\"%s\","
459                             "(GCallback)(func),(data),(destroy_data),(GConnectFlags)(flags))\n",
460                             funcbase, m->id, macrobase, m->id);
461         } else {
462                 /* connect */
463                 out_printf (outh, "#define %s_connect__%s(object,func,data)\t"
464                             "g_signal_connect("
465                             "%s(__extension__ ({%s *___object = (object); ___object; })),"
466                             "\"%s\","
467                             "(GCallback) __extension__ ({",
468                             funcbase, m->id, macrobase, typebase, m->id);
469                 print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
470                               " = (func); ", m, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE);
471                 out_printf (outh, "___%s; }), (data))\n", m->id);
472
473                 /* connect_after */
474                 out_printf (outh, "#define %s_connect_after__%s(object,func,data)\t"
475                             "g_signal_connect_after("
476                             "%s(__extension__ ({%s *___object = (object); ___object; })),"
477                             "\"%s\","
478                             "(GCallback) __extension__ ({",
479                             funcbase, m->id, macrobase, typebase, m->id);
480                 print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
481                               " = (func); ", m, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE);
482                 out_printf (outh, "___%s; }), (data))\n", m->id);
483
484                 /* connect_data */
485                 out_printf (outh, "#define %s_connect_data__%s"
486                             "(object,func,data,destroy_data,flags)\t"
487                             "g_signal_connect_data("
488                             "%s(__extension__ ({%s *___object = (object); ___object; })),"
489                             "\"%s\","
490                             "(GCallback) __extension__ ({",
491                             funcbase, m->id, macrobase, typebase, m->id);
492                 print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
493                               " = (func); ", m, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE);
494                 out_printf (outh, "___%s; }), (data), (destroy_data), (GConnectFlags)(flags))\n", m->id);
495         }
496 }
497
498 static void
499 put_signal_macros (const Class *c, gboolean gnu)
500 {
501         const GList *li;
502
503         if (signals < 0)
504                 return;
505
506         for (li = c->nodes; li != NULL; li = li->next) {
507                 const Node *n = li->data;
508                 if (n->type == METHOD_NODE)
509                         put_signal_macro ((Method *)n, gnu);
510         }
511 }
512
513 static void
514 put_local_signal_macro (const Method *m)
515 {
516         if(m->method != SIGNAL_LAST_METHOD &&
517            m->method != SIGNAL_FIRST_METHOD)
518                 return;
519
520         /* connect */
521         out_printf (out, "#define self_connect__%s(object,func,data)\t"
522                     "%s_connect__%s((object),(func),(data))\n",
523                     m->id, funcbase, m->id);
524
525         /* connect_after */
526         out_printf (out, "#define self_connect_after__%s(object,func,data)\t"
527                     "%s_connect_after__%s((object),(func),(data))\n",
528                     m->id, funcbase, m->id);
529
530         /* connect_data */
531         out_printf (out, "#define self_connect_data__%s(object,func,data,destroy_data,flags)\t"
532                     "%s_connect_data__%s((object),(func),(data),(destroy_data),(flags))\n",
533                     m->id, funcbase, m->id);
534 }
535
536 static void
537 put_local_signal_macros (const Class *c)
538 {
539         const GList *li;
540
541         if (signals < 0)
542                 return;
543
544         for (li = c->nodes; li != NULL; li = li->next) {
545                 const Node *n = li->data;
546                 if (n->type == METHOD_NODE)
547                         put_local_signal_macro ((Method *)n);
548         }
549 }
550
551
552 static void
553 put_prot_method(const Method *m)
554 {
555         FILE *f;
556
557         if(m->scope != PROTECTED_SCOPE)
558                 return;
559  
560         f = outph ? outph : out;
561
562         out_addline_infile(f, m->line_no);
563         print_method(f, "", "\t", "", "\t", "", ";\n",
564                      m, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE);
565         out_addline_outfile(f);
566 }
567
568 static void
569 put_priv_method_prot(const Method *m)
570 {
571         if(m->method == SIGNAL_LAST_METHOD ||
572            m->method == SIGNAL_FIRST_METHOD ||
573            m->method == VIRTUAL_METHOD) {
574                 if(m->cbuf)
575                         print_method(out,
576                                      "static ", "___real_", "", " ", "", ";\n",
577                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
578         }
579         /* no else, here, it might still have a private prototype, it's not
580          * exclusive */
581
582         if((m->method == OVERRIDE_METHOD &&
583             m->cbuf)) {
584                 /* add unique ID */
585                 char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
586                 if (m->line_no > 0)
587                         out_addline_infile(out, m->line_no);
588                 print_method(out, "static ", s, "", " ", "",
589                              no_gnu?";\n":" G_GNUC_UNUSED;\n",
590                              m, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE);
591                 if (m->line_no > 0)
592                         out_addline_outfile(out);
593                 g_free(s);
594         } else if(m->scope == PRIVATE_SCOPE ||
595                   m->method == INIT_METHOD ||
596                   m->method == CLASS_INIT_METHOD ||
597                   m->method == CONSTRUCTOR_METHOD ||
598                   m->method == DISPOSE_METHOD ||
599                   m->method == FINALIZE_METHOD) {
600                 if (m->line_no > 0)
601                         out_addline_infile(out, m->line_no);
602                 print_method(out, "static ", "", "", " ", "",
603                              no_gnu?";\n":" G_GNUC_UNUSED;\n",
604                              m, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE);
605                 if (m->line_no > 0)
606                         out_addline_outfile(out);
607         }
608 }
609
610 static GList *
611 make_func_arg (const char *typename, gboolean is_class, const char *name)
612 {
613         Node *node;
614         Node *type;
615         char *tn;
616         
617         if (is_class)
618                 tn = g_strconcat (typename, ":Class", NULL);
619         else
620                 tn = g_strdup (typename);
621
622         type = node_new (TYPE_NODE,
623                          "name:steal", tn,
624                          "pointer", "*",
625                          NULL);
626         node = node_new (FUNCARG_NODE,
627                          "atype:steal", (Type *)type,
628                          "name", name,
629                          NULL);
630         return g_list_prepend (NULL, node);
631 }
632
633 static void
634 make_inits(Class *cl)
635 {
636         int got_class_init = FALSE;
637         int got_init = FALSE;
638         GList *li;
639         Node *node;
640         for(li=cl->nodes;li;li=g_list_next(li)) {
641                 Node *n = li->data;
642                 if(n->type == METHOD_NODE) {
643                         Method *m = (Method *)n;
644                         if(m->method == INIT_METHOD) {
645                                 if(got_init)
646                                         error_print(GOB_ERROR, m->line_no, "init defined more then once");
647                                 got_init = TRUE;
648                         } else if(m->method == CLASS_INIT_METHOD) {
649                                 if(got_class_init)
650                                         error_print(GOB_ERROR, m->line_no, "class_init defined more then once");
651                                 got_class_init = TRUE;
652                         }
653                 }
654         }
655         if(!got_class_init) {
656                 Type *type = (Type *)node_new (TYPE_NODE,
657                                                "name", "void",
658                                                NULL);
659                 node = node_new (METHOD_NODE,
660                                  "scope", NO_SCOPE,
661                                  "method", CLASS_INIT_METHOD,
662                                  "mtype:steal", type,
663                                  "id", "class_init",
664                                  "args:steal", make_func_arg (cl->otype,
665                                                               TRUE /* is_class */,
666                                                               "c" /* name */),
667                                  "unique_id", method_unique_id++,
668                                  NULL);
669                 cl->nodes = g_list_prepend(cl->nodes, node);
670         }
671         if(!got_init) {
672                 Type *type = (Type *)node_new (TYPE_NODE,
673                                                "name", "void",
674                                                NULL);
675                 node = node_new (METHOD_NODE,
676                                  "scope", NO_SCOPE,
677                                  "method", INIT_METHOD,
678                                  "mtype:steal", type,
679                                  "id", "init",
680                                  "args:steal", make_func_arg (cl->otype,
681                                                               FALSE /* is_class */,
682                                                               "o" /* name */),
683                                  "unique_id", method_unique_id++,
684                                  NULL);
685                 cl->nodes = g_list_prepend(cl->nodes, node);
686         }
687 }
688
689 static Method *
690 find_method(const Class *cl, int method, const char *id)
691 {
692         GList *li;
693
694         for(li=cl->nodes;li;li=g_list_next(li)) {
695                 Node *n = li->data;
696                 if(n->type == METHOD_NODE) {
697                         Method *m = (Method *)n;
698                         if (m->method == method
699                             && (id == NULL || strcmp(m->id, id)==0))
700                                 return m;
701                 }
702         }
703
704         return NULL;
705 }
706
707 static void
708 find_constructor(const Class *cl)
709 {
710         user_constructor = find_method(cl, CONSTRUCTOR_METHOD, NULL);
711 }
712
713 static void
714 find_dispose(const Class *cl)
715 {
716         dispose_handler = find_method(cl, OVERRIDE_METHOD, "dispose");
717         if (dispose_handler != NULL) {
718                 if(strcmp(dispose_handler->otype, "G:Object") != 0)
719                         error_print(GOB_ERROR, dispose_handler->line_no,
720                                     "dispose method override "
721                                     "of class other then "
722                                     "G:Object");
723                 if(g_list_length(dispose_handler->args) != 1)
724                         error_print(GOB_ERROR, dispose_handler->line_no,
725                                     "dispose method override "
726                                     "with more then one "
727                                     "parameter");
728         }
729
730         user_dispose_method = find_method(cl, DISPOSE_METHOD, NULL);
731 }
732
733 static void
734 find_finalize(const Class *cl)
735 {
736         finalize_handler = find_method(cl, OVERRIDE_METHOD, "finalize");
737         if (finalize_handler != NULL) {
738                 if(strcmp(finalize_handler->otype, "G:Object") != 0)
739                         error_print(GOB_ERROR, finalize_handler->line_no,
740                                     "finalize method override "
741                                     "of class other then "
742                                     "G:Object");
743                 if(g_list_length(finalize_handler->args) != 1)
744                         error_print(GOB_ERROR, finalize_handler->line_no,
745                                     "finalize method override "
746                                     "with more then one "
747                                     "parameter");
748         }
749
750         user_finalize_method = find_method(cl, FINALIZE_METHOD, NULL);
751 }
752
753
754 /* hash of method -> name of signal prototype */
755 static GHashTable *marsh = NULL;
756
757 /* list of methods with different signal prototypes,
758    we check this list if we can use a signal prototype of a
759    previous signal method, there are only uniques here */
760 static GList *eq_signal_methods = NULL;
761
762 /* compare a list of strings */
763 static gboolean
764 is_list_equal(const GList *a, const GList *b)
765 {
766         for(;a && b; a=a->next, b=b->next) {
767                 if(strcmp(a->data, b->data)!=0) {
768                         return FALSE;
769                 }
770         }
771         /* the the lists were different length */
772         if(a || b)
773                 return FALSE;
774         return TRUE;
775 }
776
777 static Method *
778 find_same_type_signal(const Method *m)
779 {
780         GList *li;
781         for(li=eq_signal_methods;li;li=li->next) {
782                 Method *mm = li->data;
783                 if(is_list_equal(mm->gtktypes, m->gtktypes))
784                         return mm;
785         }
786         return NULL;
787 }
788
789 static void
790 print_signal_marsal_args (const Method *m)
791 {
792         if (strcmp (m->gtktypes->next->data, "NONE") != 0) {
793                 GList *li;
794                 int i;
795                 for (i = 0, li = m->gtktypes->next;
796                      li != NULL;
797                      i++, li = li->next) {
798                         char *get_func;
799
800                         if (strcmp (li->data, "UNICHAR") == 0)
801                                 /* hack because glib is braindamaged */
802                                 get_func = g_strdup ("g_value_get_uint");
803                         else if (strncmp(li->data, "BOXED_", 6) == 0)
804                                 get_func = g_strdup ("g_value_get_boxed");
805                         else
806                                 get_func = g_strdup_printf
807                                         ("g_value_get_%s", (char *)li->data);
808
809                         gob_strdown (get_func);
810                         out_printf (out, ",\n\t\t(%s) "
811                                     "%s (param_values + %d)",
812                                     get_cast (li->data, FALSE),
813                                     get_func, i + 1);
814                         g_free (get_func);
815                 }
816         }
817         out_printf (out, ",\n\t\tdata2);\n");
818 }
819
820
821 static void
822 add_signal_prots(Method *m)
823 {
824         GList *li;
825         static int sig = 1;
826         char *s;
827         Method *mm;
828         gboolean ret_none = FALSE;
829         gboolean arglist_none = FALSE;
830         const char *retcast;
831         const char *unused = "";
832
833         if ( ! no_gnu && ! for_cpp /* g++ has a cow with this */) {
834                 unused = " G_GNUC_UNUSED";
835         }
836         
837         if (m->method != SIGNAL_LAST_METHOD &&
838             m->method != SIGNAL_FIRST_METHOD)
839                 return;
840
841         if (marsh == NULL)
842                 marsh = g_hash_table_new(NULL, NULL);
843
844         g_assert (m->gtktypes->next != NULL);
845
846         ret_none = strcmp(m->gtktypes->data, "NONE") == 0;
847         arglist_none = strcmp(m->gtktypes->next->data, "NONE") == 0;
848         
849         if (ret_none && arglist_none)
850                 return;
851
852         /* if we already did a signal prototype just use that */
853         mm = find_same_type_signal (m);
854         if (mm != NULL) {
855                 s = g_hash_table_lookup (marsh, mm);
856                 g_hash_table_insert (marsh, m, s);
857                 return;
858         }
859
860         if (ret_none)
861                 retcast = NULL;
862         else
863                 retcast = get_cast (m->gtktypes->data, FALSE);
864         
865         s = g_strdup_printf("Sig%d", sig++);
866         
867         g_hash_table_insert(marsh, m, s);
868         eq_signal_methods = g_list_prepend(eq_signal_methods, m);
869         
870         /* we know that we'll know all the gtktypes (so get_cast can't fail) */
871         out_printf(out, "\ntypedef %s (*___%s) (%s *, ",
872                    get_cast(m->gtktypes->data, FALSE), s, typebase);
873         
874         if ( ! arglist_none) {
875                 for (li = m->gtktypes->next; li != NULL; li = li->next)
876                         out_printf (out, "%s, ", get_cast (li->data, FALSE));
877         }
878         out_printf (out, "gpointer);\n"); 
879         
880         out_printf (out, "\nstatic void\n"
881                     "___marshal_%s (GClosure *closure,\n"
882                     "\tGValue *return_value%s,\n"
883                     "\tguint n_param_values,\n"
884                     "\tconst GValue *param_values,\n"
885                     "\tgpointer invocation_hint%s,\n"
886                     "\tgpointer marshal_data)\n"
887                     "{\n",
888                     s,
889                     unused,
890                     unused);
891
892         if ( ! ret_none)
893                 out_printf (out, "\t%s v_return;\n", retcast);
894
895         out_printf (out, "\tregister ___%s callback;\n"
896                     "\tregister GCClosure *cc = (GCClosure*) closure;\n"
897                     "\tregister gpointer data1, data2;\n\n",
898                     s);
899
900         out_printf (out, "\tg_return_if_fail (n_param_values == %d);\n\n",
901                     arglist_none ? 1 : g_list_length (m->gtktypes));
902
903         out_printf (out,
904                     "\tif (G_CCLOSURE_SWAP_DATA (closure)) {\n"
905                     "\t\tdata1 = closure->data;\n"
906                     "\t\tdata2 = g_value_peek_pointer (param_values + 0);\n"
907                     "\t} else {\n"
908                     "\t\tdata1 = g_value_peek_pointer (param_values + 0);\n"
909                     "\t\tdata2 = closure->data;\n"
910                     "\t}\n\n");
911
912         out_printf (out, "\tcallback = (___%s) "
913                     "(marshal_data != NULL ? marshal_data : cc->callback);"
914                     "\n\n", s);
915         
916         if (ret_none) {
917                 out_printf (out, "\tcallback ((%s *)data1", typebase);
918         } else {
919                 out_printf (out, "\tv_return = callback ((%s *)data1",
920                             typebase);
921         }
922
923         print_signal_marsal_args (m);
924
925         if ( ! ret_none) {
926                 /* FIXME: This code is so fucking ugly it hurts */
927                 gboolean take_ownership = 
928                         (strcmp ((char *)m->gtktypes->data, "STRING") == 0 ||
929                          strcmp ((char *)m->gtktypes->data, "BOXED") == 0);
930                 char *set_func;
931
932
933                 if (strcmp (m->gtktypes->data, "UNICHAR") == 0)
934                         /* hack because glib is braindamaged */
935                         set_func = g_strdup ("g_value_set_uint");
936                 else
937                         set_func = g_strdup_printf ("g_value_%s_%s",
938                                                     take_ownership ?
939                                                     "take" : "set",
940                                                     (char *)m->gtktypes->data);
941                 gob_strdown (set_func);
942
943                 out_printf (out, "\n\t%s (return_value, v_return);\n",
944                             set_func);
945
946                 g_free (set_func);
947         }
948         if (no_gnu || for_cpp /* g++ has a cow with G_GNUC_UNUSED */) {
949                 if (ret_none)
950                         out_printf (out, "\n\treturn_value = NULL;\n");
951                 out_printf (out, "\tinvocation_hint = NULL;\n");
952
953         }
954         out_printf (out, "}\n\n");
955 }
956
957 static char *
958 interface_type(const char *if_name)
959 {
960         char *rawtype = remove_sep(if_name);
961         char *end = "", *typename;
962
963         if (!gtk3_ok) {
964                 /*
965                  * EEEK! evil, we should have some sort of option
966                  * to force this for arbitrary interfaces, since
967                  * some are Class and some are Iface.  Glib is shite
968                  * in consistency.
969                  */
970
971                 if (strcmp (rawtype, "GtkEditable") == 0
972                     || strcmp (rawtype, "GTypePlugin") == 0)
973                 {
974                         end = "Class";
975                 } else {
976                         /* We'll assume Iface is the standard ending */
977                         end = "Iface";
978                 }
979         } else {
980                 /* GTK3 doesn't need Iface end */
981                 end = "Interface";
982         }
983
984         typename = g_strconcat(rawtype, end, (char *)NULL);
985         g_free(rawtype);
986
987         return typename;
988 }
989
990 static void
991 define_parent_interface_refs(Class *c)
992 {
993         GList *li;
994
995         if (!c->interfaces)
996                 return;
997
998         out_printf(out, "\n/* parent class interface implementations */\n");
999         for (li = c->interfaces; li != NULL; li = li->next) {
1000                 char *name = replace_sep(li->data, '_');
1001                 char *type = interface_type(li->data);
1002
1003                 out_printf (out, "static %s *%s_parent_iface;\n", type, name);
1004
1005                 g_free(name);
1006                 g_free(type);
1007         }
1008 }
1009
1010 static void
1011 add_enums(Class *c)
1012 {
1013         GList *li;
1014         out_printf(out, "\n");
1015         if(signals>0) {
1016                 out_printf(out, "enum {\n");
1017                 for(li=c->nodes;li;li=g_list_next(li)) {
1018                         Node *n = li->data;
1019                         if(n->type == METHOD_NODE) {
1020                                 Method *m = (Method *)n;
1021                                 if(m->method == SIGNAL_LAST_METHOD ||
1022                                    m->method == SIGNAL_FIRST_METHOD) {
1023                                         char *s = g_strdup(m->id);
1024                                         gob_strup(s);
1025                                         out_printf(out, "\t%s_SIGNAL,\n", s);
1026                                         g_free(s);
1027                                 }
1028                         }
1029                 }
1030                 out_printf(out, "\tLAST_SIGNAL\n};\n\n");
1031         }
1032         if (set_properties > 0 ||
1033             get_properties > 0) {
1034                 out_printf(out, "enum {\n\tPROP_0");
1035                 for(li=c->nodes;li;li=g_list_next(li)) {
1036                         Node *n = li->data;
1037                         if (n->type == PROPERTY_NODE) {
1038                                 Property *p = (Property *)n;
1039                                 char *s = g_strdup (p->name);
1040                                 gob_strup (s);
1041                                 out_printf (out, ",\n\tPROP_%s", s);
1042                                 g_free(s);
1043                         } else if (n->type == ARGUMENT_NODE) {
1044                                 Argument *a = (Argument *)n;
1045                                 char *s = g_strdup(a->name);
1046                                 gob_strup (s);
1047                                 out_printf(out, ",\n\tPROP_%s", s);
1048                                 g_free(s);
1049                         }
1050                 }
1051                 out_printf(out, "\n};\n\n");
1052         }
1053
1054         if (signals > 0)
1055                 out_printf(out,
1056                            "static guint object_signals[LAST_SIGNAL] = {0};\n\n");
1057
1058         out_printf(out, "/* pointer to the class of our parent */\n");
1059         out_printf(out, "static %sClass *parent_class = NULL;\n", ptypebase);
1060         define_parent_interface_refs(c);
1061         out_printf(out, "\n");
1062 }
1063
1064 static void
1065 add_interface_methods (Class *c, const char *interface)
1066 {
1067         GList *li;
1068         gboolean added_line = FALSE;
1069
1070         for (li = c->nodes; li != NULL; li = li->next) {
1071                 Node *n = li->data;
1072                 Method *m = (Method *)n;
1073                 if (n->type != METHOD_NODE ||
1074                     m->method == OVERRIDE_METHOD ||
1075                     m->interface == NULL ||
1076                     strcmp (m->interface, interface) != 0)
1077                         continue;
1078
1079                 if (m->line_no > 0) {
1080                         out_addline_infile (out, m->line_no);
1081                         added_line = TRUE;
1082                 } else if (m->line_no == 0 &&
1083                            added_line) {
1084                         out_addline_outfile (out);
1085                         added_line = FALSE;
1086                 }
1087                 out_printf (out, "\tiface->%s = self_%s;\n",
1088                             m->id, m->id);
1089         }
1090         if (added_line)
1091                 out_addline_outfile (out);
1092 }
1093
1094 static void
1095 add_interface_inits(Class *c)
1096 {
1097         GList *li;
1098
1099         if (c->interfaces == NULL)
1100                 return;
1101
1102         out_printf(out, "\n");
1103
1104         for (li = c->interfaces; li != NULL; li = li->next) {
1105                 char *name = replace_sep(li->data, '_');
1106                 char *type = interface_type(li->data);
1107
1108                 out_printf(out, "static void\n"
1109                                 "___%s_init (%s *iface)\n"
1110                                 "{\n", name, type);
1111
1112                 add_interface_methods(c, li->data);
1113
1114                 out_printf(out, "\t%s_parent_iface\n", name);
1115                 out_printf(out, for_cpp ? "\t\t= (%s *)" : "\t\t= ", type);
1116                 out_printf(out, "g_type_interface_peek_parent(iface);\n"
1117                                 "}\n\n");
1118
1119                 g_free (name);
1120                 g_free (type);
1121         }
1122 }
1123
1124 static void
1125 add_interface_infos(Class *c, gboolean static_storage)
1126 {
1127         GList *li;
1128
1129         for (li = c->interfaces; li; li = li->next) {
1130                 char *name = replace_sep(li->data, '_');
1131                 out_printf(out, "\t%sconst GInterfaceInfo %s_info = {\n"
1132                                 "\t\t(GInterfaceInitFunc) ___%s_init,\n"
1133                                 "\t\tNULL,\n"
1134                                 "\t\tNULL\n"
1135                                 "\t};\n",
1136                                 static_storage ? "static " : "",
1137                                 name, name);
1138                 g_free(name);
1139         }
1140
1141         out_printf(out, "\n");
1142 }
1143
1144 static void
1145 define_add_interfaces(Class *c)
1146 {
1147         GList *li;
1148
1149         if (!c->interfaces)
1150                 return;
1151
1152         out_printf(out, "static void ___add_interfaces(GType type)\n{\n");
1153         add_interface_infos(c, TRUE);
1154
1155         for (li = c->interfaces; li; li = li->next) {
1156                 char *type = make_pre_macro(li->data, "TYPE");
1157                 char *name = replace_sep(li->data, '_');
1158
1159                 out_printf(out, "\tg_type_add_interface_static\n"
1160                                 "\t\t( type\n"
1161                                 "\t\t, %s\n"
1162                                 "\t\t, &%s_info\n"
1163                                 "\t\t);\n",
1164                                 type, name);
1165
1166                 g_free(name);
1167                 g_free(type);
1168         }
1169
1170         out_printf(out, "}\n\n");
1171 }
1172
1173 static void
1174 define_dynamic_add_interfaces(Class *c)
1175 {
1176         GList *li;
1177
1178         if (!c->interfaces)
1179                 return;
1180
1181         out_printf(out, "static void ___add_interfaces"
1182                             "(GTypeModule *type_module, GType type)\n"
1183                         "{\n");
1184         add_interface_infos(c, FALSE);
1185
1186         /*
1187          * Hack to work around bug in g_type_module_add_interface,
1188          * which will fail to add an interface to types that derive
1189          * from something that also implements the same interface.
1190          *
1191          * The actual GType system does not have any such problem,
1192          * and the GTypeModule implementation details relied upon
1193          * here have not changed once since the feature was first
1194          * implemented almost 20 years ago.
1195          */
1196         out_printf(out, "\tstruct _ModuleInterfaceInfo {\n"
1197                         "\t\tgboolean loaded;\n"
1198                         "\t\tGType instance_type;\n"
1199                         "\t\tGType interface_type;\n"
1200                         "\t\tGInterfaceInfo info;\n"
1201                         "\t} *modinfo;\n");
1202
1203         for (li = c->interfaces; li; li = li->next) {
1204                 char *type = make_pre_macro(li->data, "TYPE");
1205                 char *name = replace_sep(li->data, '_');
1206
1207                 out_printf(out, "\n"
1208                                 "\tmodinfo = g_malloc(sizeof *modinfo);\n"
1209                                 "\tmodinfo->loaded = TRUE;\n"
1210                                 "\tmodinfo->instance_type = type;\n"
1211                                 "\tmodinfo->interface_type = %s;\n"
1212                                 "\tmodinfo->info = %s_info;\n"
1213                                 "\tg_type_add_interface_dynamic\n"
1214                                 "\t\t( modinfo->instance_type\n"
1215                                 "\t\t, modinfo->interface_type\n"
1216                                 "\t\t, G_TYPE_PLUGIN(type_module)\n"
1217                                 "\t\t);\n"
1218                                 "\ttype_module->interface_infos = g_slist_prepend\n"
1219                                 "\t\t( type_module->interface_infos\n"
1220                                 "\t\t, modinfo\n"
1221                                 "\t\t);\n",
1222                                 type, name);
1223
1224                 g_free(name);
1225                 g_free(type);
1226         }
1227
1228         out_printf(out, "}\n\n");
1229 }
1230
1231 static void add_type_info(void)
1232 {
1233         out_printf(out, "\tstatic const GTypeInfo info = {\n"
1234                         "\t\tsizeof (%sClass),\n"
1235                         "\t\t(GBaseInitFunc) NULL,\n"
1236                         "\t\t(GBaseFinalizeFunc) NULL,\n"
1237                         "\t\t(GClassInitFunc) %s_class_init,\n"
1238                         "\t\t(GClassFinalizeFunc) NULL,\n"
1239                         "\t\tNULL /* class_data */,\n"
1240                         "\t\tsizeof (%s),\n"
1241                         "\t\t%d /* n_preallocs */,\n"
1242                         "\t\t(GInstanceInitFunc) %s_init,\n"
1243                         "\t\tNULL\n"
1244                         "\t};\n\n",
1245                         typebase, funcbase, typebase, prealloc, funcbase);
1246 }
1247
1248 static void
1249 add_get_type(void)
1250 {
1251         Class *c = (Class *)class;
1252
1253         define_add_interfaces(c);
1254
1255         out_printf(out, "GType %s_get_type(void)\n"
1256                         "{\n"
1257                         "\tstatic GType type = 0;\n",
1258                         funcbase);
1259
1260         add_type_info();
1261
1262         out_printf(out, "\tif ___GOB_UNLIKELY(type == 0) {\n"
1263                         "\t\ttype = g_type_register_static\n"
1264                         "\t\t\t( %s\n"
1265                         "\t\t\t, \"%s\"\n"
1266                         "\t\t\t, &info\n"
1267                         "\t\t\t, (GTypeFlags)%s\n"
1268                         "\t\t\t);\n",
1269                         pmacrotype, typebase,
1270                         c->abstract ? "G_TYPE_FLAG_ABSTRACT" : "0");
1271
1272         if (c->interfaces)
1273                 out_printf(out, "\t\t___add_interfaces(type);\n");
1274
1275         out_printf(out, "\t}\n\n"
1276                         "\treturn type;\n"
1277                         "}\n\n");
1278 }
1279
1280 static void
1281 add_dynamic_get_type(void)
1282 {
1283         Class *c = (Class *)class;
1284
1285         define_dynamic_add_interfaces(c);
1286
1287         out_printf(out, "static GType %s_type_id;\n\n"
1288                         "GType %s_get_type(void)\n"
1289                         "{\n"
1290                         "\treturn %s_type_id;\n"
1291                         "}\n\n",
1292                         funcbase, funcbase, funcbase);
1293
1294         out_printf(out, "void %s_register_type(GTypeModule *type_module)\n"
1295                         "{\n",
1296                         funcbase);
1297
1298         add_type_info();
1299
1300         out_printf(out, "\t%s_type_id = g_type_module_register_type\n"
1301                         "\t\t( type_module\n"
1302                         "\t\t, %s\n"
1303                         "\t\t, \"%s\"\n"
1304                         "\t\t, &info\n"
1305                         "\t\t, (GTypeFlags)%s\n"
1306                         "\t\t);\n",
1307                         funcbase, pmacrotype, typebase,
1308                         c->abstract ? "G_TYPE_FLAG_ABSTRACT" : "0");
1309
1310         if (c->interfaces) {
1311                 out_printf(out, "\t___add_interfaces"
1312                                     "(type_module, %s_type_id);\n",
1313                                 funcbase);
1314         }
1315
1316         out_printf(out, "}\n\n");
1317 }
1318
1319 static void
1320 add_bonobo_object_get_type(void)
1321 {
1322         Class *c = (Class *)class;
1323
1324         define_add_interfaces(c);
1325
1326         out_printf (out, "GType %s_get_type(void)\n"
1327                          "{\n"
1328                          "\tstatic GType type = 0;\n",
1329                          funcbase);
1330
1331         add_type_info();
1332
1333         out_printf (out, "\tif ___GOB_UNLIKELY(type == 0) {\n"
1334                          "\t\ttype = bonobo_type_unique\n"
1335                          "\t\t\t( BONOBO_OBJECT_TYPE\n"
1336                          "\t\t\t, POA_%s__init, NULL\n"
1337                          "\t\t\t, G_STRUCT_OFFSET (%sClass, _epv)\n"
1338                          "\t\t\t, &info\n"
1339                          "\t\t\t, \"%s\"\n"
1340                          "\t\t\t);\n",
1341                          c->bonobo_object_class, typebase, typebase);
1342
1343         if (((Class *)class)->interfaces)
1344                 out_printf(out, "\t\t___add_interfaces(type);\n");
1345
1346         out_printf(out, "\t}\n\n"
1347                         "\treturn type;\n"
1348                         "}\n\n");
1349 }
1350
1351 static void
1352 add_overrides(Class *c, const char *oname,
1353               gboolean did_base_obj)
1354 {
1355         GList *li;
1356         GHashTable *done;
1357         char *s;
1358         
1359         done = g_hash_table_new (g_str_hash, g_str_equal);
1360         if (did_base_obj) {
1361                 s = g_strdup ("GObject");
1362                 g_hash_table_insert (done, s, s);
1363         }
1364         for (li = c->nodes; li != NULL; li = li->next) {
1365                 Node *n = li->data;
1366                 char *f;
1367                 Method *m = (Method *)n;
1368                 if(n->type != METHOD_NODE ||
1369                    m->method != OVERRIDE_METHOD)
1370                         continue;
1371
1372                 s = remove_sep(m->otype);
1373                 
1374                 if(g_hash_table_lookup(done, s)) {
1375                         g_free(s);
1376                         continue;
1377                 }
1378                 g_hash_table_insert(done, s, s);
1379
1380                 f = replace_sep(m->otype, '_');
1381                 gob_strdown(f);
1382
1383                 out_printf(out, "\t%sClass *%s_class = (%sClass *)%s;\n",
1384                            s, f, s, oname);
1385                 
1386                 g_free(f);
1387         }
1388         g_hash_table_foreach (done, (GHFunc)g_free, NULL);
1389         g_hash_table_destroy (done);
1390 }
1391
1392 static char *
1393 make_run_signal_flags(Method *m, gboolean last)
1394 {
1395         GList *li;
1396         GString *gs;
1397         char *flags[] = {
1398                 "RUN_FIRST",
1399                 "RUN_LAST",
1400                 "RUN_CLEANUP",
1401                 "NO_RECURSE",
1402                 "DETAILED",
1403                 "ACTION",
1404                 "NO_HOOKS",
1405                 NULL
1406         };
1407
1408         gs = g_string_new(NULL);
1409
1410         if(last)
1411                 g_string_assign(gs, "G_SIGNAL_RUN_LAST");
1412         else
1413                 g_string_assign(gs, "G_SIGNAL_RUN_FIRST");
1414
1415         if(m->scope == PUBLIC_SCOPE)
1416                 g_string_append(gs, " | G_SIGNAL_ACTION");
1417
1418         for(li = m->flags; li; li = li->next) {
1419                 char *flag = li->data;
1420                 int i;
1421                 for(i=0;flags[i];i++) {
1422                         if(strcmp(flags[i], flag)==0)
1423                                 break;
1424                 }
1425                 /* if we haven't found it in our list */
1426                 if( ! flags[i]) {
1427                         error_printf(GOB_WARN, m->line_no,
1428                                      "Unknown flag '%s' used, "
1429                                      "perhaps it was misspelled",
1430                                      flag);
1431                 }
1432                 g_string_sprintfa(gs, " | G_SIGNAL_%s", flag);
1433         }
1434
1435         {
1436                 char *ret = gs->str;
1437                 g_string_free(gs, FALSE);
1438                 return ret;
1439         }
1440 }
1441                 
1442
1443 static void
1444 add_signals(Class *c)
1445 {
1446         GList *li;
1447
1448         out_printf(out, "\n");
1449         for(li=c->nodes;li;li=g_list_next(li)) {
1450                 Node *n = li->data;
1451                 char *mar, *sig, *flags;
1452                 gboolean is_none, last = FALSE;
1453                 Method *m = (Method *)n;
1454
1455                 if(n->type != METHOD_NODE ||
1456                    (m->method != SIGNAL_FIRST_METHOD &&
1457                     m->method != SIGNAL_LAST_METHOD))
1458                         continue;
1459
1460                 if(m->method == SIGNAL_FIRST_METHOD)
1461                         last = FALSE;
1462                 else
1463                         last = TRUE;
1464
1465                 if(g_hash_table_lookup(marsh, m))
1466                         mar = g_strconcat("___marshal_",
1467                                           (char *)g_hash_table_lookup(marsh, m),
1468                                           NULL);
1469                 else
1470                         mar = g_strdup("g_cclosure_marshal_VOID__VOID");
1471                 
1472                 is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
1473
1474                 sig = g_strdup (m->id);
1475                 gob_strup (sig);
1476                 flags = make_run_signal_flags (m, last);
1477                 out_printf (out, "\tobject_signals[%s_SIGNAL] =\n"
1478                             "\t\tg_signal_new (%s,\n"
1479                             "\t\t\tG_TYPE_FROM_CLASS (g_object_class),\n"
1480                             "\t\t\t(GSignalFlags)(%s),\n"
1481                             "\t\t\tG_STRUCT_OFFSET (%sClass, %s),\n"
1482                             "\t\t\tNULL, NULL,\n"
1483                             "\t\t\t%s,\n"
1484                             "\t\t\tG_TYPE_%s, %d",
1485                             sig, m->signal_name /*m->id* if not given signal_name*/,
1486                             flags,
1487                             typebase, m->id, mar,
1488                             (char *)m->gtktypes->data,
1489                             is_none ? 0 : g_list_length(m->gtktypes->next));
1490                 g_free(mar);
1491                 g_free(sig);
1492                 g_free(flags);
1493                 
1494                 if( ! is_none) {
1495                         GList *l;
1496                         char  *t;
1497                         for(l = m->gtktypes->next; l != NULL; l = l->next) {
1498                                 char *str = l->data;
1499                                 if (strncmp (str, "BOXED_", 6) == 0)
1500                                         t = g_strdup (&(str[6]));
1501                                 else
1502                                         t = g_strconcat ("G_TYPE_", str, NULL);
1503                                 out_printf (out, ",\n\t\t\t%s", t);
1504                                 g_free (t);
1505                         }
1506                 }
1507
1508                 out_printf(out, ");\n");
1509
1510                 if(strcmp(m->gtktypes->data, "NONE") != 0 ||
1511                    ! is_none) {
1512                         GList *gl, *al;
1513                         out_printf(out, "\tif ___GOB_UNLIKELY(");
1514                         if(strcmp(m->gtktypes->data, "NONE") != 0) {
1515                                 out_printf(out, "sizeof(");
1516                                 print_type(out, m->mtype, FALSE);
1517                                 out_printf(out, "%s",
1518                                            m->mtype->postfix ?
1519                                            m->mtype->postfix : ""); 
1520                                 out_printf(out, ") != sizeof(%s) || ",
1521                                            get_cast(m->gtktypes->data, FALSE));
1522                         }
1523
1524                         for(al = m->args->next, gl = m->gtktypes->next;
1525                             al != NULL && gl != NULL;
1526                             al = al->next, gl = gl->next) {
1527                                 FuncArg *arg = al->data;
1528                                 char *gtkarg = gl->data;
1529
1530                                 out_printf(out, "sizeof(");
1531                                 print_type(out, arg->atype, FALSE);
1532                                 out_printf(out, "%s",
1533                                            arg->atype->postfix ?
1534                                            arg->atype->postfix : ""); 
1535                                 out_printf(out, ") != sizeof(%s) || ",
1536                                            get_cast(gtkarg, FALSE));
1537                         }
1538
1539                         out_printf (out,
1540                                     "parent_class == NULL /* avoid warning */");
1541
1542                         out_printf(out, ") {\n"
1543                                    "\t\tg_error(\"%s line %d: Type mismatch "
1544                                    "of \\\"%s\\\" signal signature\");\n"
1545                                    "\t}\n",
1546                                    filename, m->line_no, m->id);
1547
1548                 }
1549         }
1550 }
1551
1552 static void
1553 set_def_handlers(Class *c, const char *oname)
1554 {
1555         GList *li;
1556         gboolean set_line = FALSE;
1557
1558         out_printf(out, "\n");
1559         for(li = c->nodes; li; li = g_list_next(li)) {
1560                 Node *n = li->data;
1561                 Method *m = (Method *)n;
1562
1563                 if(n->type != METHOD_NODE ||
1564                    (m->method != SIGNAL_FIRST_METHOD &&
1565                     m->method != SIGNAL_LAST_METHOD &&
1566                     m->method != VIRTUAL_METHOD &&
1567                     m->method != OVERRIDE_METHOD))
1568                         continue;
1569
1570                 if(m->line_no > 0 && m->cbuf) {
1571                         out_addline_infile(out, m->line_no);
1572                         set_line = TRUE;
1573                 } else if(set_line) {
1574                         out_addline_outfile(out);
1575                         set_line = FALSE;
1576                 }
1577
1578
1579                 if (m->method == OVERRIDE_METHOD) {
1580                         char *s;
1581                         s = replace_sep (m->otype, '_');
1582                         gob_strdown (s);
1583
1584                         if (need_dispose &&
1585                             dispose_handler != NULL &&
1586                             strcmp (m->id, "dispose") == 0)
1587                                 out_printf (out, "\tg_object_class->dispose "
1588                                             "= ___dispose;\n");
1589                         else if (need_finalize &&
1590                                 finalize_handler &&
1591                                 strcmp(m->id, "finalize") == 0)
1592                                 out_printf(out,
1593                                            "\tg_object_class->finalize = ___finalize;\n");
1594                         else if (m->cbuf != NULL)
1595                                 out_printf(out,
1596                                            "\t%s_class->%s = ___%x_%s_%s;\n",
1597                                            s, m->id, (guint)m->unique_id,
1598                                            funcbase, m->id);
1599                         else
1600                                 out_printf(out, "\t%s_class->%s = NULL;\n",
1601                                            s, m->id);
1602                 } else {
1603                         if(m->cbuf)
1604                                 out_printf(out, "\t%s->%s = ___real_%s_%s;\n",
1605                                            oname, m->id,
1606                                            funcbase, m->id);
1607                         else
1608                                 out_printf(out, "\t%s->%s = NULL;\n",
1609                                            oname, m->id);
1610                 }
1611         }
1612         if(set_line)
1613                 out_addline_outfile(out);
1614 }
1615
1616 static void
1617 make_argument (Argument *a)
1618 {
1619         GString *flags;
1620         GList *l;
1621         char *s;
1622         char *argflags[] = {
1623                 "CONSTRUCT",
1624                 "CONSTRUCT_ONLY",
1625                 "LAX_VALIDATION",
1626                 "PRIVATE",
1627                 NULL
1628         };
1629
1630         flags = g_string_new ("(GParamFlags)(");
1631
1632         if(a->get && a->set)
1633                 g_string_append (flags, "G_PARAM_READABLE | G_PARAM_WRITABLE");
1634         else if(a->get)
1635                 g_string_append (flags, "G_PARAM_READABLE");
1636         else
1637                 g_string_append (flags, "G_PARAM_WRITABLE");
1638
1639         g_assert(a->get || a->set);
1640
1641         for (l = a->flags; l != NULL; l = l->next) {
1642                 char *flag = l->data;
1643                 int i;
1644                 if(strcmp (flag, "READABLE") == 0 ||
1645                    strcmp (flag, "WRITABLE") == 0) {
1646                         error_print(GOB_WARN, a->line_no,
1647                                     "READABLE and "
1648                                     "WRITABLE argument flags are "
1649                                     "set automatically");
1650                         continue;
1651                 }
1652                 for(i = 0; argflags[i]; i++) {
1653                         if(strcmp(argflags[i], flag)==0)
1654                                 break;
1655                 }
1656                 g_string_sprintfa(flags, " | %s%s", argflags[i] ? "G_PARAM_" : "", flag);
1657         }
1658
1659         g_string_append (flags, ")");
1660
1661         s = g_strdup(a->name);
1662         gob_strup (s);
1663         if (!strcmp (a->gtktype, "ENUM"))
1664                 out_printf(out, "\tparam_spec = g_param_spec_enum (\"%s\", NULL, NULL,\n"
1665                            "\t\tG_TYPE_ENUM, 0,\n"
1666                            "\t\t%s);\n",
1667                            a->name, flags->str);
1668         if (!strcmp (a->gtktype, "FLAGS"))
1669                 out_printf(out, "\tparam_spec = g_param_spec_flags (\"%s\", NULL, NULL,\n"
1670                            "\t\tG_TYPE_FLAGS, 0,\n"
1671                            "\t\t%s);\n",
1672                            a->name, flags->str);
1673         else if (!strcmp (a->gtktype, "OBJECT"))
1674                 out_printf(out, "\tparam_spec = g_param_spec_object (\"%s\", NULL, NULL,\n"
1675                            "\t\tG_TYPE_OBJECT,\n"
1676                            "\t\t%s);\n",
1677                            a->name, flags->str);
1678         else if (!strcmp (a->gtktype, "STRING"))
1679                 out_printf(out, "\tparam_spec = g_param_spec_string (\"%s\", NULL, NULL,\n"
1680                            "\t\tNULL,\n"
1681                            "\t\t%s);\n",
1682                            a->name, flags->str);
1683         else if (!strcmp (a->gtktype, "INT"))
1684                 out_printf(out, "\tparam_spec = g_param_spec_int (\"%s\", NULL, NULL,\n"
1685                            "\t\tG_MININT, G_MAXINT,\n"
1686                            "\t\t0,\n"
1687                            "\t\t%s);\n",
1688                            a->name, flags->str);
1689         else if (!strcmp (a->gtktype, "UINT"))
1690                 out_printf(out, "\tparam_spec = g_param_spec_uint (\"%s\", NULL, NULL,\n"
1691                            "\t\t0, G_MAXUINT,\n"
1692                            "\t\t0,\n"
1693                            "\t\t%s);\n",
1694                            a->name, flags->str);
1695         else if (!strcmp (a->gtktype, "INT"))
1696                 out_printf(out, "\tparam_spec = g_param_spec_int (\"%s\", NULL, NULL,\n"
1697                            "\t\tG_MININT, G_MAXINT,\n"
1698                            "\t\t0,\n"
1699                            "\t\t%s);\n",
1700                            a->name, flags->str);
1701         else if (!strcmp (a->gtktype, "CHAR"))
1702                 out_printf(out, "\tparam_spec = g_param_spec_char (\"%s\", NULL, NULL,\n"
1703                            "\t\t-128, 127,\n"
1704                            "\t\t0,\n"
1705                            "\t\t%s);\n",
1706                            a->name, flags->str);
1707         else if (!strcmp (a->gtktype, "UCHAR"))
1708                 out_printf(out, "\tparam_spec = g_param_spec_uchar (\"%s\", NULL, NULL,\n"
1709                            "\t\t0, 0xFF,\n"
1710                            "\t\t0,\n"
1711                            "\t\t%s);\n",
1712                            a->name, flags->str);
1713         else if (!strcmp (a->gtktype, "BOOL") ||
1714                  !strcmp (a->gtktype, "BOOLEAN"))
1715                 out_printf(out, "\tparam_spec = g_param_spec_boolean (\"%s\", NULL, NULL,\n"
1716                            "\t\tFALSE,\n"
1717                            "\t\t%s);\n",
1718                            a->name, flags->str);
1719         else if (!strcmp (a->gtktype, "LONG"))
1720                 out_printf(out, "\tparam_spec = g_param_spec_long (\"%s\", NULL, NULL,\n"
1721                            "\t\tG_MINLONG, G_MAXLONG,\n"
1722                            "\t\t0,\n"
1723                            "\t\t%s);\n",
1724                            a->name, flags->str);
1725         else if (!strcmp (a->gtktype, "ULONG"))
1726                 out_printf(out, "\tparam_spec = g_param_spec_ulong (\"%s\", NULL, NULL,\n"
1727                            "\t\t0, G_MAXULONG,\n"
1728                            "\t\t0,\n"
1729                            "\t\t%s);\n",
1730                            a->name, flags->str);
1731         else if (!strcmp (a->gtktype, "INT64"))
1732                 out_printf(out, "\tparam_spec = g_param_spec_int64 (\"%s\", NULL, NULL,\n"
1733                            "\t\tG_MININT64, G_MAXINT64,\n"
1734                            "\t\t0,\n"
1735                            "\t\t%s);\n",
1736                            a->name, flags->str);
1737         else if (!strcmp (a->gtktype, "UINT64"))
1738                 out_printf(out, "\tparam_spec = g_param_spec_uint64 (\"%s\", NULL, NULL,\n"
1739                            "\t\t0, G_MAXUINT64,\n"
1740                            "\t\t0,\n"
1741                            "\t\t%s);\n",
1742                            a->name, flags->str);
1743         else if (!strcmp (a->gtktype, "FLOAT"))
1744                 out_printf(out, "\tparam_spec = g_param_spec_float (\"%s\", NULL, NULL,\n"
1745                            "\t\t-G_MAXFLOAT, G_MAXFLOAT,\n"
1746                            "\t\t0,\n"
1747                            "\t\t%s);\n",
1748                            a->name, flags->str);
1749         else if (!strcmp (a->gtktype, "DOUBLE"))
1750                 out_printf(out, "\tparam_spec = g_param_spec_double (\"%s\", NULL, NULL,\n"
1751                            "\t\t-G_MAXDOUBLE, G_MAXDOUBLE,\n"
1752                            "\t\t0,\n"
1753                            "\t\t%s);\n",
1754                            a->name, flags->str);
1755         else if (!strcmp (a->gtktype, "POINTER"))
1756                 out_printf(out, "\tparam_spec = g_param_spec_pointer (\"%s\", NULL, NULL,\n"
1757                            "\t\t%s);\n",
1758                            a->name, flags->str);
1759         else
1760                 error_printf (GOB_ERROR, a->line_no,
1761                               "%s type is not supported for arguments, try using properties",
1762                               a->gtktype);
1763
1764         out_printf(out, "\tg_object_class_install_property (g_object_class,\n"
1765                    "\t\tPROP_%s, param_spec);\n", s);
1766
1767
1768         g_free(s);
1769         g_string_free(flags, TRUE);
1770 }
1771
1772 #define value_for_print(str, alt) (str != NULL ? str : alt)
1773
1774 static void
1775 make_property (Property *p)
1776 {
1777         char *s;
1778
1779         if (p->get == NULL && p->set == NULL) {
1780                 error_print (GOB_ERROR, p->line_no,
1781                              "Property has no getter nor setter");
1782         }
1783
1784         if (p->override) {
1785                 if (p->flags != NULL)
1786                         error_print (GOB_WARN, p->line_no,
1787                                      "Overridden property, flags ignored");
1788                 if (p->nick != NULL)
1789                         error_print (GOB_WARN, p->line_no,
1790                                      "Overridden property, nick ignored");
1791                 if (p->blurb != NULL)
1792                         error_print (GOB_WARN, p->line_no,
1793                                      "Overridden property, blurb ignored");
1794                 if (p->minimum != NULL)
1795                         error_print (GOB_WARN, p->line_no,
1796                                      "Overridden property, minimum ignored");
1797                 if (p->maximum != NULL)
1798                         error_print (GOB_WARN, p->line_no,
1799                                      "Overridden property, maximum ignored");
1800                 if (p->default_value != NULL)
1801                         error_print (GOB_WARN, p->line_no,
1802                                      "Overridden property, default_value ignored");
1803
1804                 s = g_strdup (p->name);
1805                 gob_strup (s);
1806                 out_printf (out, "\tg_object_class_override_property (g_object_class,\n"
1807                             "\t\tPROP_%s,\n"
1808                             "\t\t\"%s\");\n", s, value_for_print (p->canonical_name, p->name) );
1809                 g_free (s);
1810         } else {
1811                 GString *flags;
1812                 GList *l;
1813                 char *argflags[] = {
1814                         "CONSTRUCT",
1815                         "CONSTRUCT_ONLY",
1816                         "LAX_VALIDATION",
1817                         "PRIVATE",
1818                         NULL
1819                 };
1820
1821                 flags = g_string_new ("(GParamFlags)(");
1822
1823                 if (p->get != NULL && p->set != NULL)
1824                         g_string_append (flags, "G_PARAM_READABLE | G_PARAM_WRITABLE");
1825                 else if (p->get != NULL)
1826                         g_string_append (flags, "G_PARAM_READABLE");
1827                 else
1828                         g_string_append (flags, "G_PARAM_WRITABLE");
1829
1830
1831                 for (l = p->flags; l != NULL; l = l->next) {
1832                         char *flag = l->data;
1833                         int i;
1834                         if(strcmp (flag, "READABLE") == 0 ||
1835                            strcmp (flag, "WRITABLE") == 0) {
1836                                 error_print(GOB_WARN, p->line_no,
1837                                             "READABLE and "
1838                                             "WRITABLE argument flags are "
1839                                             "set automatically");
1840                                 continue;
1841                         }
1842                         for(i = 0; argflags[i]; i++) {
1843                                 if(strcmp(argflags[i], flag)==0)
1844                                         break;
1845                         }
1846                         g_string_sprintfa(flags, " | %s%s", argflags[i] ? "G_PARAM_" : "", flag);
1847                 }
1848
1849                 g_string_append (flags, ")");
1850
1851                 if (strcmp (p->gtktype, "CHAR") == 0) {
1852                         out_printf (out, "\tparam_spec = g_param_spec_char\n"
1853                                     "\t\t(\"%s\" /* name */,\n"
1854                                     "\t\t %s /* nick */,\n"
1855                                     "\t\t %s /* blurb */,\n"
1856                                     "\t\t %s /* minimum */,\n"
1857                                     "\t\t %s /* maximum */,\n"
1858                                     "\t\t %s /* default_value */,\n"
1859                                     "\t\t %s);\n",
1860                                     value_for_print (p->canonical_name, p->name),
1861                                     value_for_print (p->nick, "NULL"),
1862                                     value_for_print (p->blurb, "NULL"),
1863                                     value_for_print (p->minimum, "-128"),
1864                                     value_for_print (p->maximum, "127"),
1865                                     value_for_print (p->default_value, "0"),
1866                                     flags->str);
1867                 } else if (strcmp (p->gtktype, "UCHAR") == 0) {
1868                         out_printf (out, "\tparam_spec = g_param_spec_uchar\n"
1869                                     "\t\t(\"%s\" /* name */,\n"
1870                                     "\t\t %s /* nick */,\n"
1871                                     "\t\t %s /* blurb */,\n"
1872                                     "\t\t %s /* minimum */,\n"
1873                                     "\t\t %s /* maximum */,\n"
1874                                     "\t\t %s /* default_value */,\n"
1875                                     "\t\t %s);\n",
1876                                     value_for_print (p->canonical_name, p->name),
1877                                     value_for_print (p->nick, "NULL"),
1878                                     value_for_print (p->blurb, "NULL"),
1879                                     value_for_print (p->minimum, "0"),
1880                                     value_for_print (p->maximum, "0xFF"),
1881                                     value_for_print (p->default_value, "0"),
1882                                     flags->str);
1883                 } else if (strcmp (p->gtktype, "BOOLEAN") == 0) {
1884                         out_printf (out, "\tparam_spec = g_param_spec_boolean\n"
1885                                     "\t\t(\"%s\" /* name */,\n"
1886                                     "\t\t %s /* nick */,\n"
1887                                     "\t\t %s /* blurb */,\n"
1888                                     "\t\t %s /* default_value */,\n"
1889                                     "\t\t %s);\n",
1890                                     value_for_print (p->canonical_name, p->name),
1891                                     value_for_print (p->nick, "NULL"),
1892                                     value_for_print (p->blurb, "NULL"),
1893                                     value_for_print (p->default_value, "FALSE"),
1894                                     flags->str);
1895                 } else if (strcmp (p->gtktype, "INT") == 0) {
1896                         out_printf (out, "\tparam_spec = g_param_spec_int\n"
1897                                     "\t\t(\"%s\" /* name */,\n"
1898                                     "\t\t %s /* nick */,\n"
1899                                     "\t\t %s /* blurb */,\n"
1900                                     "\t\t %s /* minimum */,\n"
1901                                     "\t\t %s /* maximum */,\n"
1902                                     "\t\t %s /* default_value */,\n"
1903                                     "\t\t %s);\n",
1904                                     value_for_print (p->canonical_name, p->name),
1905                                     value_for_print (p->nick, "NULL"),
1906                                     value_for_print (p->blurb, "NULL"),
1907                                     value_for_print (p->minimum, "G_MININT"),
1908                                     value_for_print (p->maximum, "G_MAXINT"),
1909                                     value_for_print (p->default_value, "0"),
1910                                     flags->str);
1911                 } else if (strcmp (p->gtktype, "UINT") == 0) {
1912                         out_printf (out, "\tparam_spec = g_param_spec_uint\n"
1913                                     "\t\t(\"%s\" /* name */,\n"
1914                                     "\t\t %s /* nick */,\n"
1915                                     "\t\t %s /* blurb */,\n"
1916                                     "\t\t %s /* minimum */,\n"
1917                                     "\t\t %s /* maximum */,\n"
1918                                     "\t\t %s /* default_value */,\n"
1919                                     "\t\t %s);\n",
1920                                     value_for_print (p->canonical_name, p->name),
1921                                     value_for_print (p->nick, "NULL"),
1922                                     value_for_print (p->blurb, "NULL"),
1923                                     value_for_print (p->minimum, "0"),
1924                                     value_for_print (p->maximum, "G_MAXUINT"),
1925                                     value_for_print (p->default_value, "0"),
1926                                     flags->str);
1927                 } else if (strcmp (p->gtktype, "LONG") == 0) {
1928                         out_printf (out, "\tparam_spec = g_param_spec_long\n"
1929                                     "\t\t(\"%s\" /* name */,\n"
1930                                     "\t\t %s /* nick */,\n"
1931                                     "\t\t %s /* blurb */,\n"
1932                                     "\t\t %s /* minimum */,\n"
1933                                     "\t\t %s /* maximum */,\n"
1934                                     "\t\t %s /* default_value */,\n"
1935                                     "\t\t %s);\n",
1936                                     value_for_print (p->canonical_name, p->name),
1937                                     value_for_print (p->nick, "NULL"),
1938                                     value_for_print (p->blurb, "NULL"),
1939                                     value_for_print (p->minimum, "G_MINLONG"),
1940                                     value_for_print (p->maximum, "G_MAXLONG"),
1941                                     value_for_print (p->default_value, "0"),
1942                                     flags->str);
1943                 } else if (strcmp (p->gtktype, "ULONG") == 0) {
1944                         out_printf (out, "\tparam_spec = g_param_spec_ulong\n"
1945                                     "\t\t(\"%s\" /* name */,\n"
1946                                     "\t\t %s /* nick */,\n"
1947                                     "\t\t %s /* blurb */,\n"
1948                                     "\t\t %s /* minimum */,\n"
1949                                     "\t\t %s /* maximum */,\n"
1950                                     "\t\t %s /* default_value */,\n"
1951                                     "\t\t %s);\n",
1952                                     value_for_print (p->canonical_name, p->name),
1953                                     value_for_print (p->nick, "NULL"),
1954                                     value_for_print (p->blurb, "NULL"),
1955                                     value_for_print (p->minimum, "0"),
1956                                     value_for_print (p->maximum, "G_MAXULONG"),
1957                                     value_for_print (p->default_value, "0"),
1958                                     flags->str);
1959                 } else if (strcmp (p->gtktype, "INT64") == 0) {
1960                         out_printf (out, "\tparam_spec = g_param_spec_int64\n"
1961                                     "\t\t(\"%s\" /* name */,\n"
1962                                     "\t\t %s /* nick */,\n"
1963                                     "\t\t %s /* blurb */,\n"
1964                                     "\t\t %s /* minimum */,\n"
1965                                     "\t\t %s /* maximum */,\n"
1966                                     "\t\t %s /* default_value */,\n"
1967                                     "\t\t %s);\n",
1968                                     value_for_print (p->canonical_name, p->name),
1969                                     value_for_print (p->nick, "NULL"),
1970                                     value_for_print (p->blurb, "NULL"),
1971                                     value_for_print (p->minimum, "G_MININT64"),
1972                                     value_for_print (p->maximum, "G_MAXINT64"),
1973                                     value_for_print (p->default_value, "0"),
1974                                     flags->str);
1975                 } else if (strcmp (p->gtktype, "UINT64") == 0) {
1976                         out_printf (out, "\tparam_spec = g_param_spec_uint64\n"
1977                                     "\t\t(\"%s\" /* name */,\n"
1978                                     "\t\t %s /* nick */,\n"
1979                                     "\t\t %s /* blurb */,\n"
1980                                     "\t\t %s /* minimum */,\n"
1981                                     "\t\t %s /* maximum */,\n"
1982                                     "\t\t %s /* default_value */,\n"
1983                                     "\t\t %s);\n",
1984                                     value_for_print (p->canonical_name, p->name),
1985                                     value_for_print (p->nick, "NULL"),
1986                                     value_for_print (p->blurb, "NULL"),
1987                                     value_for_print (p->minimum, "0"),
1988                                     value_for_print (p->maximum, "G_MAXUINT64"),
1989                                     value_for_print (p->default_value, "0"),
1990                                     flags->str);
1991                 } else if (strcmp (p->gtktype, "UNICHAR") == 0) {
1992                         out_printf (out, "\tparam_spec = g_param_spec_unichar\n"
1993                                     "\t\t(\"%s\" /* name */,\n"
1994                                     "\t\t %s /* nick */,\n"
1995                                     "\t\t %s /* blurb */,\n"
1996                                     "\t\t %s /* default_value */,\n"
1997                                     "\t\t %s);\n",
1998                                     value_for_print (p->canonical_name, p->name),
1999                                     value_for_print (p->nick, "NULL"),
2000                                     value_for_print (p->blurb, "NULL"),
2001                                     value_for_print (p->default_value, "0"),
2002                                     flags->str);
2003                 } else if (strcmp (p->gtktype, "ENUM") == 0) {
2004                         char *type = make_me_type (p->extra_gtktype,
2005                                                    "G_TYPE_ENUM");
2006                         out_printf (out, "\tparam_spec = g_param_spec_enum\n"
2007                                     "\t\t(\"%s\" /* name */,\n"
2008                                     "\t\t %s /* nick */,\n"
2009                                     "\t\t %s /* blurb */,\n"
2010                                     "\t\t %s /* enum_type */,\n"
2011                                     "\t\t %s /* default_value */,\n"
2012                                     "\t\t %s);\n",
2013                                     value_for_print (p->canonical_name, p->name),
2014                                     value_for_print (p->nick, "NULL"),
2015                                     value_for_print (p->blurb, "NULL"),
2016                                     type,
2017                                     value_for_print (p->default_value, "0"),
2018                                     flags->str);
2019                         g_free (type);
2020                 } else if (strcmp (p->gtktype, "FLAGS") == 0) {
2021                         char *type = make_me_type (p->extra_gtktype,
2022                                                    "G_TYPE_FLAGS");
2023                         out_printf (out, "\tparam_spec = g_param_spec_flags\n"
2024                                     "\t\t(\"%s\" /* name */,\n"
2025                                     "\t\t %s /* nick */,\n"
2026                                     "\t\t %s /* blurb */,\n"
2027                                     "\t\t %s /* flags_type */,\n"
2028                                     "\t\t %s /* default_value */,\n"
2029                                     "\t\t %s);\n",
2030                                     value_for_print (p->canonical_name, p->name),
2031                                     value_for_print (p->nick, "NULL"),
2032                                     value_for_print (p->blurb, "NULL"),
2033                                     type,
2034                                     value_for_print (p->default_value, "0"),
2035                                     flags->str);
2036                         g_free (type);
2037                 } else if (strcmp (p->gtktype, "FLOAT") == 0) {
2038                         out_printf (out, "\tparam_spec = g_param_spec_float\n"
2039                                     "\t\t(\"%s\" /* name */,\n"
2040                                     "\t\t %s /* nick */,\n"
2041                                     "\t\t %s /* blurb */,\n"
2042                                     "\t\t %s /* minimum */,\n"
2043                                     "\t\t %s /* maximum */,\n"
2044                                     "\t\t %s /* default_value */,\n"
2045                                     "\t\t %s);\n",
2046                                     value_for_print (p->canonical_name, p->name),
2047                                     value_for_print (p->nick, "NULL"),
2048                                     value_for_print (p->blurb, "NULL"),
2049                                     value_for_print (p->minimum, "-G_MAXFLOAT"),
2050                                     value_for_print (p->maximum, "G_MAXFLOAT"),
2051                                     value_for_print (p->default_value, "0.0"),
2052                                     flags->str);
2053                 } else if (strcmp (p->gtktype, "DOUBLE") == 0) {
2054                         out_printf (out, "\tparam_spec = g_param_spec_double\n"
2055                                     "\t\t(\"%s\" /* name */,\n"
2056                                     "\t\t %s /* nick */,\n"
2057                                     "\t\t %s /* blurb */,\n"
2058                                     "\t\t %s /* minimum */,\n"
2059                                     "\t\t %s /* maximum */,\n"
2060                                     "\t\t %s /* default_value */,\n"
2061                                     "\t\t %s);\n",
2062                                     value_for_print (p->canonical_name, p->name),
2063                                     value_for_print (p->nick, "NULL"),
2064                                     value_for_print (p->blurb, "NULL"),
2065                                     value_for_print (p->minimum, "-G_MAXDOUBLE"),
2066                                     value_for_print (p->maximum, "G_MAXDOUBLE"),
2067                                     value_for_print (p->default_value, "0.0"),
2068                                     flags->str);
2069                 } else if (strcmp (p->gtktype, "STRING") == 0) {
2070                         out_printf (out, "\tparam_spec = g_param_spec_string\n"
2071                                     "\t\t(\"%s\" /* name */,\n"
2072                                     "\t\t %s /* nick */,\n"
2073                                     "\t\t %s /* blurb */,\n"
2074                                     "\t\t %s /* default_value */,\n"
2075                                     "\t\t %s);\n",
2076                                     value_for_print (p->canonical_name, p->name),
2077                                     value_for_print (p->nick, "NULL"),
2078                                     value_for_print (p->blurb, "NULL"),
2079                                     value_for_print (p->default_value, "NULL"),
2080                                     flags->str);
2081                 } else if (strcmp (p->gtktype, "PARAM") == 0) {
2082                         char *type = make_me_type (p->extra_gtktype,
2083                                                    "G_TYPE_PARAM");
2084                         out_printf (out, "\tparam_spec = g_param_spec_param\n"
2085                                     "\t\t(\"%s\" /* name */,\n"
2086                                     "\t\t %s /* nick */,\n"
2087                                     "\t\t %s /* blurb */,\n"
2088                                     "\t\t %s /* param_type */,\n"
2089                                     "\t\t %s);\n",
2090                                     value_for_print (p->canonical_name, p->name),
2091                                     value_for_print (p->nick, "NULL"),
2092                                     value_for_print (p->blurb, "NULL"),
2093                                     type,
2094                                     flags->str);
2095                         g_free (type);
2096                 } else if (strcmp (p->gtktype, "BOXED") == 0) {
2097                         char *type = make_me_type (p->extra_gtktype,
2098                                                    "G_TYPE_BOXED");
2099                         out_printf (out, "\tparam_spec = g_param_spec_boxed\n"
2100                                     "\t\t(\"%s\" /* name */,\n"
2101                                     "\t\t %s /* nick */,\n"
2102                                     "\t\t %s /* blurb */,\n"
2103                                     "\t\t %s /* boxed_type */,\n"
2104                                     "\t\t %s);\n",
2105                                     value_for_print (p->canonical_name, p->name),
2106                                     value_for_print (p->nick, "NULL"),
2107                                     value_for_print (p->blurb, "NULL"),
2108                                     type,
2109                                     flags->str);
2110                         g_free (type);
2111                 } else if (strcmp (p->gtktype, "POINTER") == 0) {
2112                         out_printf (out, "\tparam_spec = g_param_spec_pointer\n"
2113                                     "\t\t(\"%s\" /* name */,\n"
2114                                     "\t\t %s /* nick */,\n"
2115                                     "\t\t %s /* blurb */,\n"
2116                                     "\t\t %s);\n",
2117                                     value_for_print (p->canonical_name, p->name),
2118                                     value_for_print (p->nick, "NULL"),
2119                                     value_for_print (p->blurb, "NULL"),
2120                                     flags->str);
2121                 /* FIXME: VALUE_ARRAY */
2122                 } else if (strcmp (p->gtktype, "CLOSURE") == 0) {
2123                         out_printf (out, "\tparam_spec = g_param_spec_pointer\n"
2124                                     "\t\t(\"%s\" /* name */,\n"
2125                                     "\t\t %s /* nick */,\n"
2126                                     "\t\t %s /* blurb */,\n"
2127                                     "\t\t %s);\n",
2128                                     value_for_print (p->canonical_name, p->name),
2129                                     value_for_print (p->nick, "NULL"),
2130                                     value_for_print (p->blurb, "NULL"),
2131                                     flags->str);
2132                 } else if (strcmp (p->gtktype, "OBJECT") == 0) {
2133                         char *type = make_me_type (p->extra_gtktype,
2134                                                    "G_TYPE_BOXED");
2135                         out_printf (out, "\tparam_spec = g_param_spec_object\n"
2136                                     "\t\t(\"%s\" /* name */,\n"
2137                                     "\t\t %s /* nick */,\n"
2138                                     "\t\t %s /* blurb */,\n"
2139                                     "\t\t %s /* object_type */,\n"
2140                                     "\t\t %s);\n",
2141                                     value_for_print (p->canonical_name, p->name),
2142                                     value_for_print (p->nick, "NULL"),
2143                                     value_for_print (p->blurb, "NULL"),
2144                                     type,
2145                                     flags->str);
2146                         g_free (type);
2147                 } else {
2148                         error_printf (GOB_ERROR, p->line_no,
2149                                       "%s type is not supported by properties",
2150                                       p->gtktype);
2151                 }
2152
2153                 s = g_strdup (p->name);
2154                 gob_strup (s);
2155                 out_printf (out, "\tg_object_class_install_property (g_object_class,\n"
2156                             "\t\tPROP_%s,\n"
2157                             "\t\tparam_spec);\n", s);
2158                 g_free (s);
2159
2160                 g_string_free (flags, TRUE);
2161         }
2162 }
2163
2164 static void
2165 make_arguments(Class *c)
2166 {
2167         GList *li;
2168         if (get_properties > 0)
2169                 out_printf(out, "\tg_object_class->get_property = ___object_get_property;\n");
2170         if (set_properties > 0)
2171                 out_printf(out, "\tg_object_class->set_property = ___object_set_property;\n");
2172         out_printf (out, "    {\n");
2173         for (li = c->nodes; li != NULL; li = li->next) {
2174                 Node *n = li->data;
2175                 if ((n->type == PROPERTY_NODE && ! ((Property *) n)->override)
2176                     || n->type == ARGUMENT_NODE) {
2177                         out_printf(out, "\tGParamSpec   *param_spec;\n\n");
2178                         break;
2179                 }
2180         }
2181
2182         for (li = c->nodes; li != NULL; li = li->next) {
2183                 Node *n = li->data;
2184                 if (n->type == PROPERTY_NODE)
2185                         make_property ((Property *)n);
2186                 else if (n->type == ARGUMENT_NODE)
2187                         make_argument ((Argument *)n);
2188         }
2189         out_printf(out, "    }\n");
2190 }
2191
2192 static void
2193 print_initializer(Method *m, Variable *v)
2194 {
2195         char *root;
2196         
2197         if(v->glade_widget)
2198                 return;
2199
2200         if(v->initializer == NULL)
2201                 return;
2202
2203         if(v->scope == PRIVATE_SCOPE)
2204                 root = g_strconcat(((FuncArg *)m->args->data)->name,
2205                                    "->_priv", NULL);
2206         else
2207                 root = g_strdup(((FuncArg *)m->args->data)->name);
2208
2209         if(v->initializer_line > 0)
2210                 out_addline_infile(out, v->initializer_line);
2211
2212         if (v->initializer_simple)
2213                 out_printf(out, "\t%s->%s = %s;\n",
2214                    root, v->id, v->initializer);
2215         else if (strcmp(v->id, "_glade_xml") == 0)
2216                 /* This is OK, this v->initializer string is set internally
2217                    and it will eat exactly one string! */
2218                 out_printf(out,v->initializer, ((FuncArg *)m->args->data)->name);
2219         else
2220                 out_printf(out, "%s", v->initializer);
2221
2222         if(v->initializer_line > 0)
2223                 out_addline_outfile(out);
2224
2225         g_free(root);
2226 }
2227
2228 static void
2229 print_glade_widget(Method *m, Variable *v)
2230 {
2231         char *root;
2232   char *cast;
2233         
2234         if(!v->glade_widget)
2235                 return;
2236
2237         if(v->scope == PRIVATE_SCOPE)
2238                 root = g_strconcat(((FuncArg *)m->args->data)->name,
2239                                    "->_priv", NULL);
2240         else
2241                 root = g_strdup(((FuncArg *)m->args->data)->name);
2242
2243         cast = get_type(v->vtype, FALSE);
2244         out_printf(out, "\t%s->%s = (%s)glade_xml_get_widget(%s->_glade_xml, \"%s\");\n",
2245                    root, v->id, cast, root, v->id);
2246
2247         g_free(root);
2248 }
2249         
2250 static void
2251 print_destructor (Variable *v)
2252 {
2253         const char *root;
2254
2255         if(v->destructor == NULL)
2256                 return;
2257
2258         if(v->scope == PRIVATE_SCOPE)
2259                 root = "self->_priv";
2260         else
2261                 root = "self";
2262
2263         if(v->destructor_simple) {
2264                 if(v->destructor_line > 0)
2265                         out_addline_infile(out, v->destructor_line);
2266
2267                 if (for_cpp) {
2268                         out_printf(out, "\tif(%s->%s) { "
2269                                    "(reinterpret_cast<void (*)(void *)>(%s)) ((gpointer)%s->%s); "
2270                                    "%s->%s = NULL; }\n",
2271                                    root, v->id, v->destructor, root, v->id,
2272                                    root, v->id);
2273                 } else {
2274                         out_printf(out, "\tif(%s->%s) { "
2275                                    "%s ((gpointer) %s->%s); "
2276                                    "%s->%s = NULL; }\n",
2277                                    root, v->id, v->destructor, root, v->id,
2278                                    root, v->id);
2279                 }
2280
2281                 if(v->destructor_line > 0)
2282                         out_addline_outfile(out);
2283         } else {
2284                 out_printf(out, "#define %s (%s->%s)\n", v->id, root, v->id);
2285                 out_printf(out, "#define VAR %s\n", v->id);
2286                 out_printf(out, "\t{\n");
2287                 if(v->destructor_line > 0)
2288                         out_addline_infile(out, v->destructor_line);
2289
2290                 out_printf(out, "\t%s}\n", v->destructor);
2291
2292                 if(v->destructor_line > 0)
2293                         out_addline_outfile(out);
2294                 out_printf(out, "\tmemset(&(%s), 0, sizeof(%s));\n",
2295                            v->id, v->id);
2296                 out_printf(out, "#undef VAR\n");
2297                 out_printf(out, "#undef %s\n", v->id);
2298         }
2299 }
2300
2301 static void
2302 add_constructor (Class *c)
2303 {
2304         out_printf(out, "\nstatic GObject *\n"
2305                    "___constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties)\n"
2306                    "{\n");
2307         out_printf(out,
2308                    "#define __GOB_FUNCTION__ \"%s::constructor\"\n",
2309                    c->otype);
2310
2311         out_printf(out, "\tGObject *obj_self;\n");
2312         out_printf(out, "\t%s *self;\n", typebase);
2313
2314         out_printf(out, "\tobj_self = G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_properties, construct_properties);\n");
2315         out_printf(out, "\tself = %s (obj_self);\n", macrobase);
2316
2317         if (user_constructor->line_no > 0)
2318                 out_addline_infile (out, user_constructor->line_no);
2319         out_printf (out, "\t%s_constructor (self);\n", funcbase);
2320         if (user_constructor->line_no > 0)
2321                 out_addline_outfile (out);
2322
2323         out_printf(out, "\treturn obj_self;\n");
2324         out_printf(out, "}\n"
2325                    "#undef __GOB_FUNCTION__\n\n");
2326 }
2327
2328 static void
2329 print_unreftors (Class *c)
2330 {
2331         GList *li;
2332         for(li = ((Class *)class)->nodes;
2333             li != NULL;
2334             li = li->next) {
2335                 Node *n = li->data;
2336                 Variable *v = (Variable *)n;
2337                 if (n->type == VARIABLE_NODE &&
2338                     v->scope != CLASS_SCOPE &&
2339                     v->destructor_unref)
2340                         print_destructor (v);
2341         }
2342 }
2343
2344 static void
2345 add_dispose (Class *c)
2346 {
2347         out_printf(out, "\nstatic void\n"
2348                    "___dispose (GObject *obj_self)\n"
2349                    "{\n");
2350         out_printf(out,
2351                    "#define __GOB_FUNCTION__ \"%s::dispose\"\n",
2352                    c->otype);
2353
2354         if (unreftors > 0 || user_dispose_method != NULL) {
2355                 out_printf (out, "\t%s *self%s = %s (obj_self);\n",
2356                             typebase,
2357                             ! no_gnu ? " G_GNUC_UNUSED" : "",
2358                             macrobase);
2359         }
2360
2361         if (dispose_handler != NULL) {
2362                 if (unreftors > 0) {
2363                         print_unreftors (c);
2364                 }
2365
2366                 /* so we get possible bad argument warning */
2367                 if (dispose_handler->line_no > 0)
2368                         out_addline_infile (out, dispose_handler->line_no);
2369                 out_printf (out, "\t___%x_%s_dispose(obj_self);\n",
2370                             (guint)dispose_handler->unique_id, funcbase);
2371                 if (dispose_handler->line_no > 0)
2372                         out_addline_outfile (out);
2373         } else {
2374                 if (user_dispose_method != NULL) {
2375                         if (user_dispose_method->line_no > 0)
2376                                 out_addline_infile (out, user_dispose_method->line_no);
2377                         out_printf (out, "\t%s_dispose (self);\n", funcbase);
2378                         if (user_dispose_method->line_no > 0)
2379                                 out_addline_outfile (out);
2380                 }
2381
2382                 if (unreftors > 0) {
2383                         print_unreftors (c);
2384                 }
2385
2386                 out_printf (out,
2387                             "\tif (G_OBJECT_CLASS (parent_class)->dispose) \\\n"
2388                             "\t\t(* G_OBJECT_CLASS (parent_class)->dispose) (obj_self);\n");
2389         }
2390
2391         out_printf(out, "}\n"
2392                    "#undef __GOB_FUNCTION__\n\n");
2393 }
2394
2395 static void
2396 print_destructors (Class *c)
2397 {
2398         GList *li;
2399         for (li = ((Class *)class)->nodes;
2400              li != NULL;
2401              li = li->next) {
2402                 Node *n = li->data;
2403                 Variable *v = (Variable *)n;
2404                 if (n->type == VARIABLE_NODE &&
2405                     v->scope != CLASS_SCOPE &&
2406                     ! v->destructor_unref)
2407                         print_destructor (v);
2408         }
2409 }
2410
2411 static void
2412 add_finalize (Class *c)
2413 {
2414         out_printf(out,
2415                    "\nstatic void\n"
2416                    "___finalize(GObject *obj_self)\n"
2417                    "{\n");
2418         out_printf(out,
2419                    "#define __GOB_FUNCTION__ \"%s::finalize\"\n",
2420                    c->otype);
2421
2422         if (privates > 0 ||
2423             destructors > 0 ||
2424             user_finalize_method != NULL) {
2425                 const char *unused = "";
2426                 if ( ! no_gnu)
2427                         unused = " G_GNUC_UNUSED";
2428                 out_printf(out, "\t%s *self%s = %s (obj_self);\n",
2429                            typebase, unused, macrobase);
2430         }
2431         if (privates > 0) {
2432                 const char *unused = "";
2433                 if ( ! no_gnu)
2434                         unused = " G_GNUC_UNUSED";
2435                 out_printf(out, "\tgpointer priv%s = self->_priv;\n",
2436                            unused);
2437         }
2438
2439         if(finalize_handler) {
2440                 if (destructors > 0) {
2441                         print_destructors (c);
2442                 }
2443
2444                 /* so we get possible bad argument warning */
2445                 if(finalize_handler->line_no > 0)
2446                         out_addline_infile(out, finalize_handler->line_no);
2447                 out_printf(out, "\t___%x_%s_finalize(obj_self);\n",
2448                            (guint)finalize_handler->unique_id, funcbase);
2449                 if(finalize_handler->line_no > 0)
2450                         out_addline_outfile(out);
2451         } else {
2452                 if (user_finalize_method != NULL) {
2453                         if (user_finalize_method->line_no > 0)
2454                                 out_addline_infile (out, user_finalize_method->line_no);
2455                         out_printf (out, "\t%s_finalize (self);\n", funcbase);
2456                         if (user_finalize_method->line_no > 0)
2457                                 out_addline_outfile (out);
2458                 }
2459
2460                 if (destructors > 0) {
2461                         print_destructors (c);
2462                 }
2463
2464                 out_printf(out,
2465                            "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
2466                            "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n");
2467         }
2468
2469         out_printf(out, "}\n"
2470                    "#undef __GOB_FUNCTION__\n\n");
2471 }
2472
2473 static void
2474 make_bonobo_object_epv (Class *c, const char *classname)
2475 {
2476         GList *li;
2477         gboolean added_line = FALSE;
2478
2479         for (li = c->nodes; li != NULL; li = li->next) {
2480                 Node *n = li->data;
2481                 Method *m = (Method *)n;
2482                 if(n->type != METHOD_NODE ||
2483                    m->method == OVERRIDE_METHOD)
2484                         continue;
2485
2486                 if (m->bonobo_object_func) {
2487                         if(m->line_no > 0) {
2488                                 out_addline_infile(out, m->line_no);
2489                                 added_line = TRUE;
2490                         } else if (m->line_no == 0 &&
2491                                    added_line) {
2492                                 out_addline_outfile(out);
2493                                 added_line = FALSE;
2494                         }
2495                         out_printf (out, "\t%s->_epv.%s = self_%s;\n",
2496                                     classname, m->id, m->id);
2497                 }
2498         }
2499         if (added_line)
2500                 out_addline_outfile(out);
2501 }
2502
2503 static void
2504 add_inits(Class *c)
2505 {
2506         const char *unused = "";
2507         GList *li;
2508
2509         if ( ! no_gnu)
2510                 unused = " G_GNUC_UNUSED";
2511
2512         for(li=c->nodes;li;li=g_list_next(li)) {
2513                 Node *n = li->data;
2514                 Method *m;
2515
2516                 if(n->type != METHOD_NODE)
2517                         continue;
2518                 m = (Method *)n;
2519                 if(m->method == INIT_METHOD) {
2520                         if(m->line_no > 0)
2521                                 out_addline_infile(out, m->line_no);
2522                         print_method(out, "static ", "\n", "", " ", "", "\n",
2523                                      m, FALSE, FALSE, FALSE, TRUE, TRUE,
2524                                      FALSE);
2525                         out_printf(out, "{\n");
2526                         if(m->line_no > 0)
2527                                 out_addline_outfile(out);
2528                         out_printf(out,
2529                                    "#define __GOB_FUNCTION__ \"%s::init\"\n",
2530                                    c->otype);
2531                         if (privates > 0) {
2532                                 out_printf(out, "\t%s->_priv = "
2533                                                 "G_TYPE_INSTANCE_GET_PRIVATE(%s,%s,%sPrivate);\n",
2534                                                 ((FuncArg *)m->args->data)->name,
2535                                                 ((FuncArg *)m->args->data)->name,
2536                                                 macrotype,
2537                                                 typebase);
2538                         } else if(always_private_struct) {
2539                                 out_printf(out, "\t%s->_priv = NULL;\n",
2540                                            ((FuncArg *)m->args->data)->name);
2541                         }
2542                         if(initializers > 0) {
2543                                 GList *li;
2544                                 for(li = ((Class *)class)->nodes;
2545                                     li != NULL;
2546                                     li = li->next) {
2547                                         Node *n = li->data;
2548                                         Variable *v = (Variable *)n;
2549                                         if(n->type != VARIABLE_NODE ||
2550                                            v->scope == CLASS_SCOPE)
2551                                                 continue;
2552                                         print_initializer(m, v);
2553                                 }
2554                         }
2555                         if(glade_widgets > 0) {
2556                                 GList *li;
2557                                 for(li = ((Class *)class)->nodes;
2558                                     li != NULL;
2559                                     li = li->next) {
2560                                         Node *n = li->data;
2561                                         Variable *v = (Variable *)n;
2562                                         if(n->type != VARIABLE_NODE ||
2563                                            v->scope == CLASS_SCOPE)
2564                                                 continue;
2565                                         print_glade_widget(m, v);
2566                                 }
2567                         }
2568                 } else if(m->method == CLASS_INIT_METHOD) {
2569                         gboolean did_base_obj = FALSE;
2570
2571                         if(m->line_no > 0)
2572                                 out_addline_infile(out, m->line_no);
2573                         print_method(out, "static ", "\n", "", " ", "", "\n",
2574                                      m, FALSE, FALSE, FALSE, TRUE, TRUE,
2575                                      FALSE);
2576                         out_printf(out, "{\n");
2577                         if(m->line_no > 0)
2578                                 out_addline_outfile(out);
2579                         out_printf(out,
2580                                    "#define __GOB_FUNCTION__ \"%s::class_init\"\n",
2581                                    c->otype);
2582                         if (set_properties > 0 ||
2583                             get_properties > 0 ||
2584                             signals > 0 ||
2585                             need_constructor ||
2586                             need_dispose ||
2587                             need_finalize) {
2588                                 out_printf(out,
2589                                            "\tGObjectClass *"
2590                                            "g_object_class%s = "
2591                                            "(GObjectClass*) %s;\n",
2592                                            unused,
2593                                            ((FuncArg *)m->args->data)->name);
2594                                 did_base_obj = TRUE;
2595                         }
2596
2597                         if (overrides > 0)
2598                                 add_overrides (c,
2599                                                ((FuncArg *)m->args->data)->name,
2600                                                did_base_obj);
2601
2602                         if (privates > 0)
2603                                 out_printf (out,
2604                                             "\n\tg_type_class_add_private(%s,sizeof(%sPrivate));\n",
2605                                             ((FuncArg *)m->args->data)->name,
2606                                             typebase);
2607
2608                         if (initializers > 0) {
2609                                 GList *li;
2610                                 for(li = ((Class *)class)->nodes;
2611                                     li != NULL;
2612                                     li = li->next) {
2613                                         Node *n = li->data;
2614                                         Variable *v = (Variable *)n;
2615                                         if(n->type == VARIABLE_NODE &&
2616                                            v->scope == CLASS_SCOPE)
2617                                                 print_initializer(m, v);
2618                                 }
2619                         }
2620                         
2621                         out_printf(out, "\n\tparent_class = ");
2622                         if(for_cpp)
2623                                 out_printf(out, "(%sClass *)", ptypebase);
2624                         out_printf(out, "g_type_class_ref (%s);\n",
2625                                    pmacrotype);
2626
2627                         if(signals > 0)
2628                                 add_signals(c);
2629
2630                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
2631
2632                         /* if there are no handlers for these things, we
2633                          * need to set them up here */
2634                         if(need_constructor)
2635                                 out_printf(out, "\tg_object_class->constructor "
2636                                            "= ___constructor;\n");
2637                         if(need_dispose && !dispose_handler)
2638                                 out_printf(out, "\tg_object_class->dispose "
2639                                            "= ___dispose;\n");
2640                         if(need_finalize && !finalize_handler)
2641                                 out_printf(out, "\tg_object_class->finalize = "
2642                                            "___finalize;\n");
2643                         
2644                         if(get_properties > 0 || set_properties > 0)
2645                                 make_arguments(c);
2646
2647                         if (c->bonobo_object_class != NULL) {
2648                                 make_bonobo_object_epv (c, ((FuncArg *)m->args->data)->name);
2649                         }
2650                 } else
2651                         continue;
2652
2653                 if(m->cbuf) {
2654                         out_printf(out, " {\n");
2655                         out_addline_infile(out, m->ccode_line);
2656                         out_printf(out, "%s\n", m->cbuf);
2657                         out_addline_outfile(out);
2658                         out_printf(out, " }\n");
2659                 }
2660                 out_printf(out, "}\n"
2661                            "#undef __GOB_FUNCTION__\n");
2662         }
2663 }
2664
2665 static void
2666 add_argument (Argument *a, gboolean is_set)
2667 {
2668         char *s;
2669         char *cbuf;
2670         char *the_type_lower;
2671         int line_no;
2672
2673         if(is_set) {
2674                 cbuf = a->set;
2675                 line_no = a->set_line;
2676         } else {
2677                 cbuf = a->get;
2678                 line_no = a->get_line;
2679         }
2680         if (cbuf == NULL)
2681                 return;
2682         s = g_strdup(a->name);
2683         gob_strup (s);
2684         out_printf(out, "\tcase PROP_%s:\n\t{", s);
2685
2686         the_type_lower = g_strdup (a->gtktype);
2687         gob_strdown (the_type_lower);
2688
2689         /* HACK because there is no g_value_set/get for unichar */
2690         if (strcmp (the_type_lower, "unichar") == 0) {
2691                 g_free (the_type_lower);
2692                 the_type_lower = g_strdup ("uint");
2693         }
2694
2695         if (is_set) {
2696                 char *cast;
2697                 const char *unused = "";
2698
2699                 if ( ! no_gnu && ! for_cpp /* g++ has a cow with this */) {
2700                         unused = " G_GNUC_UNUSED";
2701                 }
2702
2703                 if (a->atype != NULL &&
2704                     /* gcc -Wbad-function-cast is wanking stupid, moronic
2705                        and otherwise evil so we should just use a (gint)
2706                        or (guint) cast, not the specific type cast */
2707                     (for_cpp ||
2708                      (strcmp (a->gtktype, "ENUM") != 0 &&
2709                      strcmp (a->gtktype, "FLAGS") != 0)))
2710                         cast = get_type (a->atype, TRUE);
2711                 else
2712                         cast = g_strdup (get_cast (a->gtktype, FALSE));
2713
2714                 out_printf (out, "\t%s ARG%s = (%s) g_value_get_%s (VAL);\n",
2715                             cast, unused, cast, the_type_lower);
2716
2717                 g_free (cast);
2718         } else if ( ! is_set) {
2719                 char *cast;
2720
2721                 if (a->atype != NULL)
2722                         cast = get_type (a->atype, TRUE);
2723                 else
2724                         cast = g_strdup (get_cast (a->gtktype, FALSE));
2725                 out_printf (out, "\t%s ARG;\n"
2726                             "\tmemset (&ARG, 0, sizeof (%s));\n",
2727                             cast, cast);
2728
2729                 g_free(cast);
2730         }
2731         g_free (s);
2732         out_printf(out, "\t\t{\n");
2733         if (line_no > 0)
2734                 out_addline_infile (out, line_no);
2735         out_printf (out, "%s\n", cbuf);
2736         if (line_no > 0)
2737                 out_addline_outfile (out);
2738         out_printf (out, "\t\t}\n");
2739         if ( ! is_set) {
2740                 if (strcmp (a->gtktype, "OBJECT") == 0)
2741                         out_printf (out, "\t\tg_value_set_%s (VAL, G_OBJECT (ARG));\n",
2742                                     the_type_lower);
2743                 else
2744                         out_printf (out, "\t\t"
2745                                     "g_value_set_%s (VAL, ARG);\n",
2746                                     the_type_lower);
2747         }
2748         g_free (the_type_lower);
2749
2750         if (is_set &&
2751             (no_gnu || for_cpp /* g++ has a cow with G_GNUC_UNUSED */)) {
2752                 out_printf (out, "\t\tif (&ARG) break;\n");
2753         }
2754
2755         out_printf (out, "\t\tbreak;\n");
2756
2757         out_printf (out, "\t}\n");
2758 }
2759
2760 static void
2761 add_property (Property *p, gboolean is_set)
2762 {
2763         const char *cbuf;
2764         char *the_type_lower;
2765         char *name_upper;
2766         int line_no;
2767
2768         if (is_set) {
2769                 cbuf = p->set;
2770                 line_no = p->set_line;
2771         } else {
2772                 cbuf = p->get;
2773                 line_no = p->get_line;
2774         }
2775         if (cbuf == NULL)
2776                 return;
2777
2778         name_upper = g_strdup (p->name);
2779         gob_strup (name_upper);
2780         the_type_lower = g_strdup (p->gtktype);
2781         gob_strdown (the_type_lower);
2782
2783         out_printf (out, "\tcase PROP_%s:\n", name_upper);
2784
2785         out_printf(out, "\t\t{\n");
2786         if (line_no > 0)
2787                 out_addline_infile (out, line_no);
2788         out_printf (out, "%s\n", cbuf);
2789         if (line_no > 0)
2790                 out_addline_outfile (out);
2791         out_printf (out, "\t\t}\n");
2792
2793         g_free (name_upper);
2794         g_free (the_type_lower);
2795
2796         out_printf (out, "\t\tbreak;\n");
2797 }
2798
2799 static void
2800 add_getset_arg(Class *c, gboolean is_set)
2801 {
2802         GList *li;
2803         const char *unused = "";
2804         const char *hack_unused = "";
2805
2806         if ( ! no_gnu && ! for_cpp /* g++ has a cow with this */) {
2807                 unused = " G_GNUC_UNUSED";
2808         } else {
2809                 hack_unused = "if (&VAL || &pspec) break;\n\t\t";
2810         }
2811
2812         out_printf(out, "\nstatic void\n"
2813                    "___object_%s_property (GObject *object,\n"
2814                    "\tguint property_id,\n"
2815                    "\t%sGValue *VAL%s,\n"
2816                    "\tGParamSpec *pspec%s)\n"
2817                    "#define __GOB_FUNCTION__ \"%s::%s_property\"\n"
2818                    "{\n"
2819                    "\t%s *self%s;\n\n"
2820                    "\tself = %s (object);\n\n"
2821                    "\tswitch (property_id) {\n",
2822                    is_set ? "set" : "get",
2823                    is_set ? "const " : "",
2824                    unused,
2825                    unused,
2826                    c->otype,
2827                    is_set ? "set" : "get",
2828                    typebase,
2829                    unused,
2830                    macrobase);
2831
2832         for (li = c->nodes; li != NULL; li = li->next) {
2833                 Node *n = li->data;
2834                 if (n->type == PROPERTY_NODE)
2835                         add_property ((Property *)n, is_set);
2836                 else if (n->type == ARGUMENT_NODE)
2837                         add_argument ((Argument *)n, is_set);
2838         }
2839         out_printf (out, "\tdefault:\n"
2840                     "/* Apparently in g++ this is needed, glib is b0rk */\n"
2841                     "#ifndef __PRETTY_FUNCTION__\n"
2842                     "#  undef G_STRLOC\n"
2843                     "#  define G_STRLOC __FILE__ \":\" G_STRINGIFY (__LINE__)\n"
2844                     "#endif\n"
2845                     "\t\tG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);\n"
2846                     "\t\t%sbreak;\n\t}\n"
2847                     "}\n"
2848                     "#undef __GOB_FUNCTION__\n", hack_unused);
2849 }
2850
2851 static void
2852 print_checks (Method *m, FuncArg *fa)
2853 {
2854         GList *li;
2855         gboolean is_void;
2856         gboolean checked_null = FALSE;
2857         is_void = (strcmp(m->mtype->name, "void")==0 &&
2858                    m->mtype->pointer == NULL);
2859         
2860         for(li = fa->checks; li != NULL; li = li->next) {
2861                 Check *ch = li->data;
2862                 char *s;
2863                 /* point to the method prot in .gob for failed checks */
2864                 if(m->line_no > 0)
2865                         out_addline_infile(out, m->line_no);
2866                 if(is_void)
2867                         out_printf(out, "\tg_return_if_fail (");
2868                 else
2869                         out_printf(out, "\tg_return_val_if_fail (");
2870                 switch(ch->chtype) {
2871                 case NULL_CHECK:
2872                         out_printf(out, "%s != NULL", fa->name);
2873                         checked_null = TRUE;
2874                         break;
2875                 case TYPE_CHECK:
2876                         s = make_pre_macro(fa->atype->name, "IS");
2877                         if(checked_null)
2878                                 out_printf(out, "%s (%s)", s, fa->name);
2879                         else
2880                                 /* if not check null, null may be valid */
2881                                 out_printf(out, "!(%s) || %s (%s)", fa->name,
2882                                            s, fa->name);
2883                         g_free(s);
2884                         break;
2885                 case LT_CHECK:
2886                         out_printf(out, "%s < %s", fa->name, ch->number);
2887                         break;
2888                 case GT_CHECK:
2889                         out_printf(out, "%s > %s", fa->name, ch->number);
2890                         break;
2891                 case LE_CHECK:
2892                         out_printf(out, "%s <= %s", fa->name, ch->number);
2893                         break;
2894                 case GE_CHECK:
2895                         out_printf(out, "%s >= %s", fa->name, ch->number);
2896                         break;
2897                 case EQ_CHECK:
2898                         out_printf(out, "%s == %s", fa->name, ch->number);
2899                         break;
2900                 case NE_CHECK:
2901                         out_printf(out, "%s != %s", fa->name, ch->number);
2902                         break;
2903                 }
2904                 if(is_void)
2905                         out_printf(out, ");\n");
2906                 else {
2907                         out_printf(out, ", (");
2908                         print_type(out, m->mtype, TRUE);
2909                         out_printf(out, ")%s);\n",
2910                                 m->onerror?m->onerror:"0");
2911                 }
2912         }
2913 }
2914
2915 static void
2916 print_preconditions(Method *m)
2917 {
2918         GList *li;
2919         
2920         for(li=m->args;li;li=g_list_next(li)) {
2921                 FuncArg *fa = li->data;
2922                 if(fa->checks)
2923                         print_checks(m, fa);
2924         }
2925         if(m->line_no>0)
2926                 out_addline_outfile(out);
2927 }
2928
2929 static void
2930 print_method_body (Method *m, gboolean pre, gboolean unused_self)
2931 {
2932         out_printf(out, "{\n");
2933         if (m->line_no > 0)
2934                 out_addline_outfile(out);
2935         out_printf(out, "#define __GOB_FUNCTION__ \"%s::%s\"\n",
2936                    ((Class *)class)->otype,
2937                    m->id);
2938         if (pre)
2939                 print_preconditions(m);
2940
2941         if ( ! pre &&
2942              unused_self &&
2943             (no_gnu || for_cpp) &&
2944             m->args != NULL &&
2945             ((FuncArg *)(m->args->data))->name != NULL &&
2946             strcmp (((FuncArg *)(m->args->data))->name, "self") == 0) {
2947                 out_printf (out, "\tif (&self) { ; }\n");
2948         }
2949
2950         /* Note: the trailing }'s are on one line, this is so
2951            that we get the no return warning correctly and point to
2952            the correct line in the .gob file, yes this is slightly
2953            ugly in the .c file, but that is not supposed to be
2954            human readable anyway. */
2955         if(m->cbuf) {
2956                 out_printf(out, "{\n");
2957                 if(m->ccode_line>0)
2958                         out_addline_infile(out, m->ccode_line);
2959                 out_printf(out, "\t%s}", m->cbuf);
2960         }
2961
2962         /* Note, there is no \n between the last } and this } so that
2963          * errors/warnings reported on the end of the body get pointed to the
2964          * right line in the .gob source */
2965         out_printf(out, "}\n");
2966
2967         if(m->cbuf)
2968                 out_addline_outfile(out);
2969         out_printf(out, "#undef __GOB_FUNCTION__\n");
2970 }
2971
2972 static void
2973 put_signal_args (Method *m)
2974 {
2975         GList *li;
2976         GList *ali;
2977         int i;
2978
2979         if (m->args->next == NULL)
2980                 return;
2981
2982         for (ali = m->gtktypes->next, li = m->args->next, i = 1;
2983              li != NULL && ali != NULL;
2984              li = li->next, ali = ali->next, i++) {
2985                 FuncArg *fa = li->data;
2986                 char *str = ali->data;
2987                 char *cast = g_strdup (get_cast (str, FALSE));
2988                 /* FIXME: This code is so fucking ugly it hurts */
2989                 gboolean do_static = 
2990                         (strcmp  (str, "STRING") == 0 ||
2991                          strcmp  (str, "BOXED") == 0 ||
2992                          strncmp (str, "BOXED_", 6) == 0);
2993                 char *set_func;
2994                 char *t;
2995
2996                 if (cast == NULL) {
2997                         cast = get_type (fa->atype, TRUE);
2998                 }
2999                 /* we should have already proved before that
3000                    the we know all the types */
3001                 g_assert (cast != NULL);
3002
3003                 if (strncmp (str, "BOXED_", 6) == 0)
3004                         t = g_strdup (&(str[6]));
3005                 else
3006                         t = g_strconcat ("G_TYPE_", str, NULL);
3007
3008                 out_printf (out,
3009                             "\t___param_values[%d].g_type = 0;\n"
3010                             "\tg_value_init (&___param_values[%d], %s);\n",
3011                             i, i, t);
3012                 g_free (t);
3013
3014                 if (strcmp (str, "UNICHAR") == 0)
3015                         /* hack because glib is braindamaged */
3016                         set_func = g_strdup ("g_value_set_uint");
3017                 else if (strncmp (str, "BOXED_", 6) == 0)
3018                         set_func = g_strdup ("g_value_set_static_boxed");
3019                 else
3020                         set_func = g_strdup_printf ("g_value_set%s_%s",
3021                                                     do_static ? "_static" : "",
3022                                                     str);
3023                 gob_strdown (set_func);
3024
3025                 out_printf (out, "\t%s (&___param_values[%d], (%s) %s);\n\n",
3026                             set_func, i, cast, fa->name);
3027
3028                 g_free (set_func);
3029                 g_free (cast);
3030         }
3031 }
3032
3033 static void
3034 clear_signal_args (Method *m)
3035 {
3036         GList *li;
3037         int i;
3038
3039         out_printf (out, "\n\tg_value_unset (&___param_values[0]);\n");
3040
3041         if (m->args->next == NULL)
3042                 return;
3043
3044         for (li = m->args->next, i = 1;
3045              li != NULL;
3046              li = li->next, i++) {
3047                 out_printf (out,
3048                             "\tg_value_unset (&___param_values[%d]);\n", i);
3049         }
3050 }
3051
3052 static char *
3053 get_arg_names_for_macro (Method *m)
3054 {
3055         const char *sep;
3056         GList *li;
3057         GString *gs = g_string_new(NULL);
3058         sep = "";
3059         for(li=m->args;li;li=g_list_next(li)) {
3060                 FuncArg *arg = li->data;
3061                 g_string_sprintfa (gs, "%s___%s", sep, arg->name);
3062                 sep = ",";
3063         }
3064         return g_string_free (gs, FALSE);
3065 }
3066
3067 static gboolean method_is_void(Method *m)
3068 {
3069         return !strcmp(m->mtype->name, "void") && !m->mtype->pointer;
3070 }
3071
3072 static const char *method_err_retval(Method *m)
3073 {
3074         if (method_is_void(m))
3075                 return "(void)0";
3076         if (m->onerror)
3077                 return m->onerror;
3078         return "0";
3079 }
3080
3081 static void
3082 put_interface_parent_handler(Method *m)
3083 {
3084         const char *errval = method_err_retval(m);
3085         char *name = replace_sep(m->interface, '_');
3086         char *args = get_arg_names_for_macro(m);
3087
3088         out_printf(out, "#define PARENT_HANDLER(%s) (%s_parent_iface \\\n"
3089                         "\t? %s_parent_iface->%s(%s) \\\n"
3090                         "\t: %s)\n", args, name, name, m->id, args, errval);
3091
3092         g_free(name);
3093         g_free(args);
3094 }
3095
3096 static void
3097 put_method(Method *m)
3098 {
3099         char *s, *args, *doc;
3100         gboolean is_void;
3101         is_void = (strcmp(m->mtype->name, "void")==0 &&
3102                    m->mtype->pointer == NULL);
3103         out_printf(out, "\n");
3104         if(m->method != OVERRIDE_METHOD) {
3105                 doc = get_gtk_doc(m->id);
3106                 if(doc) {
3107                         out_printf(out, "%s", doc);
3108                         g_free(doc);
3109                 }
3110         }
3111
3112         switch(m->method) {
3113         case REGULAR_METHOD:
3114                 if(m->line_no > 0)
3115                         out_addline_infile(out, m->line_no);
3116                 if(m->scope == PRIVATE_SCOPE)
3117                         print_method(out, "static ", "\n", "", " ", "", "\n",
3118                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3119                 else /* PUBLIC, PROTECTED */
3120                         print_method(out, "", "\n", "", " ", "", "\n",
3121                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3122
3123                 if (m->interface) {
3124                         out_addline_outfile(out);
3125                         put_interface_parent_handler(m);
3126                 }
3127
3128                 print_method_body(m, TRUE, TRUE);
3129
3130                 if (m->interface) {
3131                         out_printf(out, "#undef PARENT_HANDLER\n");
3132                 }
3133
3134                 /* the outfile line was added above */
3135                 break;
3136         case SIGNAL_FIRST_METHOD:
3137         case SIGNAL_LAST_METHOD:
3138                 if(m->line_no > 0)
3139                         out_addline_infile(out, m->line_no);
3140                 if(m->scope == PRIVATE_SCOPE)
3141                         print_method(out, "static ", "\n", "", " ", "", "\n",
3142                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3143                 else /* PUBLIC, PROTECTED */
3144                         print_method(out, "", "\n", "", " ", "", "\n",
3145                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3146                 out_printf (out, "{\n");
3147
3148                 out_addline_outfile (out);
3149
3150                 out_printf (out,
3151                             "\tGValue ___param_values[%d];\n"
3152                             "\tGValue ___return_val;\n\n"
3153                             "memset (&___return_val, 0, "
3154                               "sizeof (___return_val));\n"
3155                             "memset (&___param_values, 0, "
3156                               "sizeof (___param_values));\n\n",
3157                             g_list_length (m->args));
3158
3159                 print_preconditions (m);
3160
3161                 out_printf (out,
3162                             "\n\t___param_values[0].g_type = 0;\n"
3163                             "\tg_value_init (&___param_values[0], G_TYPE_FROM_INSTANCE (%s));\n"
3164                             "\tg_value_set_instance (&___param_values[0], (gpointer) %s);\n\n",
3165                             ((FuncArg *)m->args->data)->name,
3166                             ((FuncArg *)m->args->data)->name);
3167
3168                 put_signal_args (m);
3169
3170                 if (strcmp (m->gtktypes->data, "NONE") != 0) {
3171                         const char *defret = NULL;
3172
3173                         out_printf (out, "\tg_value_init (&___return_val, G_TYPE_%s);\n",
3174                                     (char *)m->gtktypes->data);
3175
3176                         if (m->defreturn != NULL)
3177                                 defret = m->defreturn;
3178                         else if (m->onerror != NULL)
3179                                 defret = m->onerror;
3180
3181                         if (defret != NULL) {
3182                                 char *set_func;
3183                                 /* FIXME: This code is so fucking ugly it hurts */
3184                                 gboolean do_static = 
3185                                         (strcmp ((char *)m->gtktypes->data, "STRING") == 0 ||
3186                                          strcmp ((char *)m->gtktypes->data, "BOXED") == 0);
3187                                 char *cast = g_strdup (get_cast (m->gtktypes->data, FALSE));
3188                                 if (cast == NULL)
3189                                         cast = get_type (m->mtype, TRUE);
3190
3191                                 if (strcmp (m->gtktypes->data, "UNICHAR") == 0)
3192                                         /* hack because glib is braindamaged */
3193                                         set_func = g_strdup ("g_value_set_uint");
3194                                 else
3195                                         set_func = g_strdup_printf ("g_value_set%s_%s",
3196                                                                     do_static ? "_static" : "",
3197                                                                     (char *)m->gtktypes->data);
3198                                 gob_strdown (set_func);
3199
3200                                 out_printf (out, "\t%s (&___return_val, (%s) (%s));\n",
3201                                             set_func, cast, defret);
3202
3203                                 g_free (set_func);
3204                                 g_free (cast);
3205                         }
3206                         out_printf (out, "\n");
3207                 }
3208
3209                 s = g_strdup (m->id);
3210                 gob_strup (s);
3211
3212                 out_printf(out, "\tg_signal_emitv (___param_values,\n"
3213                            "\t\tobject_signals[%s_SIGNAL],\n"
3214                            "\t\t0 /* detail */,\n"
3215                            "\t\t&___return_val);\n", s);
3216
3217                 g_free (s);
3218
3219                 clear_signal_args (m);
3220
3221                 if (strcmp (m->gtktypes->data, "NONE") != 0) {
3222                         char *cast = g_strdup (get_cast (m->gtktypes->data, FALSE));
3223                         char *getfunc;
3224                         /* Hack because glib is very very braindead */
3225                         gboolean do_dup = 
3226                                 (strcmp ((char *)m->gtktypes->data, "STRING") == 0 ||
3227                                  strcmp ((char *)m->gtktypes->data, "BOXED") == 0 ||
3228                                  strcmp ((char *)m->gtktypes->data, "OBJECT") == 0 ||
3229                                  strcmp ((char *)m->gtktypes->data, "PARAM") == 0);
3230
3231                         if (strcmp (m->gtktypes->data, "UNICHAR") == 0)
3232                                 /* hack because glib is braindamaged */
3233                                 getfunc = g_strdup ("g_value_get_uint");
3234                         else
3235                                 getfunc = g_strdup_printf ("g_value_%s_%s",
3236                                                            do_dup ? "dup" : "get",
3237                                                            (char *)m->gtktypes->data);
3238                         gob_strdown (getfunc);
3239
3240                         if (cast == NULL)
3241                                 cast = get_type (m->mtype, TRUE);
3242
3243                         out_printf (out,
3244                                     "\n\t{\n"
3245                                     "\t\t");
3246                         print_type (out, m->mtype, TRUE);
3247                         out_printf (out,
3248                                     " ___ret = (%s) %s (&___return_val);\n"
3249                                     "\t\tg_value_unset (&___return_val);\n"
3250                                     "\t\treturn ___ret;\n"
3251                                     "\t}\n",
3252                                     cast, getfunc);
3253
3254                         g_free (cast);
3255                         g_free (getfunc);
3256                 }
3257                 out_printf(out, "}\n");
3258
3259                 if(!m->cbuf)
3260                         break;
3261                 if(m->line_no > 0)
3262                         out_addline_infile(out, m->line_no);
3263                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
3264                              m, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE);
3265                 print_method_body(m, FALSE, TRUE);
3266                 /* the outfile line was added above */
3267                 break;
3268         case VIRTUAL_METHOD:
3269                 if(m->line_no > 0)
3270                         out_addline_infile(out, m->line_no);
3271                 if(m->scope==PRIVATE_SCOPE)
3272                         print_method(out, "static ", "\n", "", " ", "", "\n",
3273                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3274                 else /* PUBLIC, PROTECTED */
3275                         print_method(out, "", "\n", "", " ", "", "\n",
3276                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3277                 out_printf(out, "{\n");
3278                 out_addline_outfile(out);
3279                 out_printf(out, "\t%sClass *klass;\n", typebase);
3280                 print_preconditions(m);
3281                 out_printf(out, "\tklass = %s_GET_CLASS(%s);\n\n"
3282                         "\tif(klass->%s)\n",
3283                         macrobase, ((FuncArg *)m->args->data)->name,
3284                         m->id);
3285                 if(strcmp(m->mtype->name, "void") == 0 &&
3286                    m->mtype->pointer == NULL) {
3287                         GList *li;
3288                         out_printf(out, "\t\t(*klass->%s)(%s",
3289                                    m->id,
3290                                    ((FuncArg *)m->args->data)->name);
3291                         for(li=m->args->next;li;li=g_list_next(li)) {
3292                                 FuncArg *fa = li->data;
3293                                 out_printf(out, ",%s", fa->name);
3294                         }
3295                         out_printf(out, ");\n}\n");
3296                 } else {
3297                         GList *li;
3298                         out_printf(out, "\t\treturn (*klass->%s)(%s",
3299                                    m->id,
3300                                    ((FuncArg *)m->args->data)->name);
3301                         for(li=m->args->next;li;li=g_list_next(li)) {
3302                                 FuncArg *fa = li->data;
3303                                 out_printf(out, ",%s", fa->name);
3304                         }
3305                         out_printf(out, ");\n"
3306                                 "\telse\n"
3307                                 "\t\treturn (");
3308                         print_type(out, m->mtype, TRUE);
3309                         if(m->defreturn)
3310                                 out_printf(out, ")(%s);\n}\n", m->defreturn);
3311                         else if(m->onerror)
3312                                 out_printf(out, ")(%s);\n}\n", m->onerror);
3313                         else
3314                                 out_printf(out, ")(0);\n}\n");
3315                 }
3316
3317                 if(!m->cbuf)
3318                         break;
3319                 if(m->line_no > 0)
3320                         out_addline_infile(out, m->line_no);
3321                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
3322                              m, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE);
3323                 print_method_body(m, FALSE, TRUE);
3324                 /* the outfile line was added above */
3325                 break;
3326         case OVERRIDE_METHOD:
3327                 if(!m->cbuf)
3328                         break;
3329                 if(m->line_no > 0)
3330                         out_addline_infile(out, m->line_no);
3331                 s = g_strdup_printf("\n___%x_", (guint)m->unique_id);
3332                 print_method(out, "static ", s, "", " ", "", "\n",
3333                              m, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE);
3334                 g_free(s);
3335                 out_addline_outfile(out);
3336                 s = replace_sep(m->otype, '_');
3337                 gob_strup (s);
3338                 args = get_arg_names_for_macro(m);
3339                 if(is_void) {
3340                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
3341                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
3342                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n",
3343                                    args, s, m->id, s, m->id, args);
3344                 } else {
3345                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
3346                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
3347                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n"
3348                                    "\t\t(",
3349                                    args, s, m->id, s, m->id, args);
3350                         out_printf(out, "(");
3351                         print_type(out, m->mtype, TRUE);
3352                         out_printf(out, ")%s))\n",
3353                                    m->onerror?m->onerror:"0");
3354                 }
3355                 g_free(args);
3356                 g_free(s);
3357                 print_method_body(m, TRUE, TRUE);
3358                 /* the outfile line was added above */
3359                 out_printf(out, "#undef PARENT_HANDLER\n");
3360                 break;
3361         case CONSTRUCTOR_METHOD:
3362         case DISPOSE_METHOD:
3363         case FINALIZE_METHOD:
3364                 if(m->line_no > 0)
3365                         out_addline_infile(out, m->line_no);
3366                 print_method(out, "static ", "\n", "", " ", "", "\n",
3367                              m, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE);
3368                 print_method_body(m, TRUE, TRUE);
3369                 /* the outfile line was added above */
3370         default:
3371                 break;
3372         }
3373 }
3374
3375 static void
3376 open_files(void)
3377 {
3378         char *outfile, *outfileh, *outfileph;
3379
3380         outfilebase = g_strconcat (fullfilebase, for_cpp ? ".cc" : ".c", NULL);
3381         outfile = g_strconcat(outfilebase, no_touch ? "#gob#" : "", NULL);
3382
3383         outfilehbase = g_strconcat (fullfilebase, ".h", NULL);
3384         outfileh = g_strconcat(outfilehbase, no_touch_headers ? "#gob#" : "", NULL);
3385
3386         if ((privates > 0 || protecteds > 0 ||
3387              private_header == PRIVATE_HEADER_ALWAYS) &&
3388             private_header != PRIVATE_HEADER_NEVER) {
3389                 char sep[2] = {0,0};
3390                 if (file_sep != 0)
3391                         sep[0] = file_sep;
3392                 outfilephbase = g_strconcat (fullfilebase, sep, "private.h", NULL);
3393                 outfileph = g_strconcat (outfilephbase, no_touch ? "#gob#" : "", NULL);
3394         } else {
3395                 outfilephbase = NULL;
3396                 outfileph = NULL;
3397         }
3398
3399         
3400         if ( ! no_write) {
3401                 out = fopen (outfile, "w");
3402                 if (out == NULL) {
3403                         error_printf (GOB_ERROR, 0,
3404                                       "Cannot open outfile: %s", outfile);
3405                 }
3406                 outh = fopen (outfileh, "w");
3407                 if (outh == NULL) {
3408                         error_printf (GOB_ERROR, 0,
3409                                       "Cannot open outfile: %s", outfileh);
3410                 }
3411                 if (outfileph != NULL) {
3412                         outph = fopen (outfileph, "w");
3413                         if (outph == NULL) {
3414                                 error_printf (GOB_ERROR, 0,
3415                                               "Cannot open outfile: %s",
3416                                               outfileph);
3417                         }
3418                 }
3419         }
3420 }
3421
3422 static void
3423 put_argument_nongnu_wrappers (Class *c)
3424 {
3425         GList *li;
3426
3427         if (get_properties < 0 && set_properties < 0)
3428                 return;
3429
3430         for (li = c->nodes; li != NULL; li = li->next) {
3431                 Node *n = li->data;
3432                 const char *name, *gtktype;
3433                 gboolean get, set;
3434                 Type *atype;
3435                 char *aname;
3436                 char *cast;
3437
3438                 if (n->type == ARGUMENT_NODE) {
3439                         Argument *a = (Argument *)n;
3440                         name = a->name;
3441                         gtktype = a->gtktype;
3442                         atype = a->atype;
3443                         get = a->get != NULL;
3444                         set = a->set != NULL;
3445                 } else if (n->type == PROPERTY_NODE) {
3446                         Property *p = (Property *)n;
3447                         name = p->name;
3448                         gtktype = p->gtktype;
3449                         atype = p->ptype;
3450                         get = p->get != NULL;
3451                         set = p->set != NULL;
3452                 } else {
3453                         continue;
3454                 }
3455
3456                 aname = g_strdup (name);
3457                 gob_strup (aname);
3458
3459                 if (atype != NULL)
3460                         cast = get_type (atype, TRUE);
3461                 else
3462                         cast = g_strdup (get_cast (gtktype, TRUE));
3463
3464                 if (cast != NULL) {
3465                         if (set)
3466                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3467                                             "\"%s\",(%s)(arg)\n",
3468                                             macrobase, aname, name, cast);
3469                         if (get)
3470                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3471                                             "\"%s\",(%s*)(arg)\n",
3472                                             macrobase, aname, name, cast);
3473                 } else {
3474                         if(set)
3475                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3476                                             "\"%s\",(arg)\n",
3477                                             macrobase, aname, name);
3478                         if(get)
3479                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3480                                             "\"%s\",(arg)\n",
3481                                             macrobase, aname, name);
3482                 }
3483                 g_free (cast);
3484                 g_free (aname);
3485         }
3486 }
3487
3488 static void
3489 put_argument_gnu_wrappers(Class *c)
3490 {
3491         GList *li;
3492
3493         if(get_properties < 0 && set_properties < 0)
3494                 return;
3495
3496         for (li = c->nodes; li != NULL; li = li->next) {
3497                 Node *n = li->data;
3498                 const char *name, *gtktype;
3499                 gboolean get, set;
3500                 Type *atype;
3501                 char *aname;
3502                 char *cast;
3503
3504                 if (n->type == ARGUMENT_NODE) {
3505                         Argument *a = (Argument *)n;
3506                         name = a->name;
3507                         gtktype = a->gtktype;
3508                         atype = a->atype;
3509                         get = a->get != NULL;
3510                         set = a->set != NULL;
3511                 } else if (n->type == PROPERTY_NODE) {
3512                         Property *p = (Property *)n;
3513                         name = p->name;
3514                         gtktype = p->gtktype;
3515                         atype = p->ptype;
3516                         get = p->get != NULL;
3517                         set = p->set != NULL;
3518                 } else {
3519                         continue;
3520                 }
3521
3522                 aname = g_strdup (name);
3523                 gob_strup (aname);
3524
3525                 if (atype != NULL)
3526                         cast = get_type (atype, TRUE);
3527                 else
3528                         cast = g_strdup (get_cast (gtktype, TRUE));
3529
3530                 if (cast != NULL) {
3531                         if (set)
3532                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3533                                            "\"%s\", __extension__ ({%sz = (arg); z;})\n",
3534                                            macrobase, aname, name, cast);
3535                         if (get)
3536                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3537                                            "\"%s\", __extension__ ({%s*z = (arg); z;})\n",
3538                                            macrobase, aname, name, cast);
3539                 } else {
3540                         if (set)
3541                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3542                                            "\"%s\",(arg)\n",
3543                                            macrobase, aname, name);
3544                         if (get)
3545                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3546                                            "\"%s\",(arg)\n",
3547                                            macrobase, aname, name);
3548                 }
3549                 g_free (cast);
3550                 g_free (aname);
3551         }
3552 }
3553
3554 static void
3555 print_ccode_block(CCode *cc)
3556 {
3557         FILE *fp;
3558         switch(cc->cctype) {
3559         case HT_CCODE:
3560                 /* HT code is printed exactly like normal header
3561                    code but is printed before */
3562         case H_CCODE:
3563                 fp = outh;
3564                 out_printf(fp, "\n");
3565                 break;
3566         case AT_CCODE:
3567                 /* AT code is printed exactly like normal 'all'
3568                    code but is printed before */
3569         case A_CCODE:
3570                 if(outph) {
3571                         out_printf(outph, "\n");
3572                         out_printf(outph, "%s\n", cc->cbuf);
3573                         out_addline_infile(outph, cc->line_no);
3574                         out_addline_outfile(outph);
3575                 }
3576                 out_printf(outh, "\n");
3577                 out_printf(outh, "%s\n", cc->cbuf);
3578                 fp = out;
3579                 out_printf(fp, "\n");
3580                 out_addline_infile(fp, cc->line_no);
3581                 break;
3582         default:
3583         case CT_CCODE:
3584         case C_CCODE:
3585                 fp = out;
3586                 out_printf(fp, "\n");
3587                 out_addline_infile(fp, cc->line_no);
3588                 break;
3589         case PH_CCODE:
3590                 if(outph)
3591                         fp = outph;
3592                 else
3593                         fp = out;
3594                 out_printf(fp, "\n");
3595                 out_addline_infile(fp, cc->line_no);
3596                 break;
3597         }
3598         out_printf(fp, "%s\n", cc->cbuf);
3599         if(cc->cctype == C_CCODE ||
3600            cc->cctype == AD_CCODE ||
3601            cc->cctype == A_CCODE ||
3602            cc->cctype == AT_CCODE ||
3603            cc->cctype == PH_CCODE)
3604                 out_addline_outfile(fp);
3605 }
3606
3607 static void
3608 print_class_block(Class *c)
3609 {
3610         GList *li;
3611         char *s;
3612         gboolean printed_private = FALSE;
3613
3614         if (c->glade_xml)
3615         {
3616                 out_printf(outph ? outph : outh, "#include <gtk/gtk.h>\n");
3617                 out_printf(outph ? outph : outh, "#include <glade/glade-xml.h>\n\n");
3618         }
3619         
3620         if(any_special) {
3621                 out_printf(out, "/* utility types we may need */\n");
3622                 if(special_array[SPECIAL_2POINTER])
3623                         out_printf(out, "typedef struct { "
3624                                    "gpointer a; gpointer b; "
3625                                    "} ___twopointertype;\n");
3626                 if(special_array[SPECIAL_3POINTER])
3627                         out_printf(out, "typedef struct { "
3628                                    "gpointer a; gpointer b; "
3629                                    "gpointer c; "
3630                                    "} ___threepointertype;\n");
3631                 if(special_array[SPECIAL_INT_POINTER])
3632                         out_printf(out, "typedef struct { "
3633                                    "gint a; gpointer b; "
3634                                    "} ___intpointertype;\n");
3635                 out_printf(out, "\n");
3636         }
3637
3638         out_printf(outh, "\n/*\n"
3639                    " * Type checking and casting macros\n"
3640                    " */\n");
3641         out_printf(outh, "#define %s\t"
3642                    "(%s_get_type())\n",
3643                    macrotype, funcbase);
3644         out_printf(outh, "#define %s(obj)\t"
3645                    "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s)\n",
3646                    macrobase, funcbase, typebase);
3647         out_printf(outh, "#define %s_CONST(obj)\t"
3648                    "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s const)\n",
3649                    macrobase, funcbase, typebase); 
3650         out_printf(outh, "#define %s_CLASS(klass)\t"
3651                    "G_TYPE_CHECK_CLASS_CAST((klass), %s_get_type(), %sClass)\n",
3652                    macrobase, funcbase, typebase);
3653         out_printf(outh, "#define %s(obj)\t"
3654                    "G_TYPE_CHECK_INSTANCE_TYPE((obj), %s_get_type ())\n\n",
3655                    macrois, funcbase);
3656         out_printf(outh,
3657                    "#define %s_GET_CLASS(obj)\t"
3658                    "G_TYPE_INSTANCE_GET_CLASS((obj), %s_get_type(), %sClass)\n",
3659                    macrobase, funcbase, typebase);
3660
3661         if ( ! no_self_alias) {
3662                 out_printf(out, "/* self casting macros */\n");
3663                 out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
3664                 out_printf(out, "#define SELF_CONST(x) %s_CONST(x)\n", macrobase);
3665                 out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
3666                 out_printf(out, "#define TYPE_SELF %s\n", macrotype);
3667                 out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n",
3668                            macrobase);
3669                 out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n",
3670                            macrobase);
3671
3672                 out_printf(out, "/* self typedefs */\n");
3673                 out_printf(out, "typedef %s Self;\n", typebase);
3674                 out_printf(out, "typedef %sClass SelfClass;\n\n", typebase);
3675         }
3676
3677         if (privates > 0 ||
3678             always_private_struct) {
3679                 out_printf (outh, "\n/* Private structure type */\n");
3680                 out_printf (outh, "typedef struct _%sPrivate %sPrivate;\n",
3681                            typebase, typebase);
3682                 if (privates == 0)
3683                         out_printf (outh, "/* There are no privates, this "
3684                                     "structure is thus never defined */\n");
3685         }
3686
3687         out_printf (outh, "\n/*\n"
3688                     " * Main object structure\n"
3689                     " */\n");
3690         s = replace_sep (c->otype, '_');
3691         gob_strup (s);
3692         out_printf (outh, "#ifndef __TYPEDEF_%s__\n"
3693                     "#define __TYPEDEF_%s__\n", s, s);
3694         g_free (s);
3695         out_printf (outh, "typedef struct _%s %s;\n"
3696                     "#endif\n", typebase, typebase);
3697         out_printf (outh, "struct _%s {\n\t%s __parent__;\n",
3698                     typebase, ptypebase);
3699         for (li = c->nodes; li; li=li->next) {
3700                 static gboolean printed_public = FALSE;
3701                 Node *n = li->data;
3702                 Variable *v = (Variable *)n;
3703                 if(n->type == VARIABLE_NODE &&
3704                    v->scope == PUBLIC_SCOPE) {
3705                         if( ! printed_public) {
3706                                 out_printf(outh, "\t/*< public >*/\n");
3707                                 printed_public = TRUE;
3708                         }
3709                         put_variable((Variable *)n, outh);
3710                 }
3711         }
3712         /* put protecteds always AFTER publics */
3713         for (li = c->nodes; li != NULL; li = li->next) {
3714                 Node *n = li->data;
3715                 Variable *v = (Variable *)n;
3716                 if (n->type == VARIABLE_NODE &&
3717                     v->scope == PROTECTED_SCOPE) {
3718                         if ( ! printed_private) {
3719                                 out_printf (outh, "\t/*< private >*/\n");
3720                                 printed_private = TRUE;
3721                         }
3722                         put_variable ((Variable *)n, outh);
3723                 }
3724         }
3725         if (privates > 0 ||
3726             always_private_struct) {
3727                 if ( ! printed_private)
3728                         out_printf (outh, "\t/*< private >*/\n");
3729                 out_printf (outh, "\t%sPrivate *_priv;\n", typebase);
3730         }
3731         out_printf (outh, "};\n");
3732
3733         if (privates > 0) {
3734                 FILE *outfp;
3735
3736                 /* if we are to stick this into the private
3737                    header, if not stick it directly into the
3738                    C file */
3739                 if (outph != NULL) 
3740                         outfp = outph;
3741                 else
3742                         outfp = out;
3743
3744                 out_printf (outfp, "struct _%sPrivate {\n",
3745                             typebase);
3746                 if (privates > 0)
3747                 {
3748                  for(li=c->nodes; li; li=li->next) {
3749                          Node *n = li->data;
3750                          Variable *v = (Variable *)n;
3751                          if(n->type == VARIABLE_NODE &&
3752                                         v->scope == PRIVATE_SCOPE) {
3753                                  out_addline_infile(outfp, v->line_no);
3754                                  put_variable(v, outfp);
3755                          }
3756                         }
3757                         out_addline_outfile(outfp);
3758                 }
3759                 out_printf(outfp, "};\n");
3760         }
3761
3762         out_printf(outh, "\n/*\n"
3763                    " * Class definition\n"
3764                    " */\n");
3765         out_printf(outh, "typedef struct _%sClass %sClass;\n",
3766                    typebase, typebase);
3767         out_printf(outh,
3768                    "struct _%sClass {\n\t%sClass __parent__;\n",
3769                    typebase, ptypebase);
3770         for(li = c->nodes; li != NULL; li = li->next) {
3771                 Node *n = li->data;
3772                 if(n->type == METHOD_NODE)
3773                         put_vs_method((Method *)n);
3774         }
3775         /* If BonoboX type class put down the epv */
3776         if (c->bonobo_object_class != NULL) {
3777                 out_printf (outh,
3778                             "\t/* Bonobo object epv */\n"
3779                             "\tPOA_%s__epv _epv;\n",
3780                             c->bonobo_object_class);
3781         }
3782         /* put class scope variables */
3783         for (li = c->nodes; li != NULL; li = li->next) {
3784                 Node *n = li->data;
3785                 Variable *v = (Variable *)n;
3786                 if (n->type == VARIABLE_NODE &&
3787                     v->scope == CLASS_SCOPE)
3788                         put_variable ((Variable *)n, outh);
3789         }
3790         out_printf (outh, "};\n\n");
3791
3792         out_printf (out, "/* here are local prototypes */\n");
3793         if (set_properties > 0) {
3794                 out_printf (out, "static void ___object_set_property "
3795                             "(GObject *object, guint property_id, "
3796                             "const GValue *value, GParamSpec *pspec);\n");
3797         }
3798         if (get_properties > 0) {
3799                 out_printf (out, "static void ___object_get_property "
3800                             "(GObject *object, guint property_id, "
3801                             "GValue *value, GParamSpec *pspec);\n");
3802         }
3803
3804         out_printf (outh, "\n/*\n"
3805                     " * Public methods\n"
3806                     " */\n");
3807
3808         if (!overrode_get_type) {
3809                 /*
3810                  * For ordinary "static" types it should be safe to mark the
3811                  * get_type implementation as const, since the get_type
3812                  * function return really is constant at the call boundary
3813                  * (even though there is an initial setup on the first call).
3814                  * But for dynamic types, since the registration is explicitly
3815                  * separated, we need to settle for "pure" as the results of
3816                  * get_type differ before and after type registration.
3817                  */
3818                 out_printf(outh, "GType\t%s_get_type\t(void) %s;\n", funcbase,
3819                                  c->dynamic ? "G_GNUC_PURE" : "G_GNUC_CONST");
3820         }
3821
3822         if (c->dynamic) {
3823                 out_printf(outh, "void\t%s_register_type\t(GTypeModule *);\n",
3824                                  funcbase);
3825         }
3826
3827         for(li = c->nodes; li != NULL; li = li->next) {
3828                 Node *n = li->data;
3829                 if(n->type == METHOD_NODE) {
3830                         put_pub_method((Method *)n);
3831                         put_prot_method((Method *)n);
3832                         put_priv_method_prot((Method *)n);
3833                 }
3834         }
3835
3836         /* this idea is less and less apealing to me */
3837         if (signals > 0) {
3838                 out_printf (outh, "\n/*\n"
3839                             " * Signal connection wrapper macros\n"
3840                             " */\n");
3841                 if( ! no_gnu) {
3842                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
3843                         put_signal_macros (c, TRUE);
3844                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
3845                         put_signal_macros (c, FALSE);
3846                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n");
3847                 } else {
3848                         put_signal_macros (c, FALSE);
3849                         out_printf(outh, "\n");
3850                 }
3851
3852                 out_printf (out, "\n/*\n"
3853                             " * Signal connection wrapper macro shortcuts\n"
3854                             " */\n");
3855                 put_local_signal_macros (c);
3856                 out_printf(outh, "\n");
3857         }
3858
3859         /* argument wrapping macros */
3860         if(get_properties > 0 || set_properties > 0) {
3861                 out_printf(outh, "\n/*\n"
3862                            " * Argument wrapping macros\n"
3863                            " */\n");
3864                 if( ! no_gnu) {
3865                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
3866                         put_argument_gnu_wrappers(c);
3867                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
3868                         put_argument_nongnu_wrappers(c);
3869                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
3870                 } else {
3871                         put_argument_nongnu_wrappers(c);
3872                 }
3873         }
3874
3875         if(signals > 0) {
3876                 for(li = c->nodes; li != NULL; li = li->next) {
3877                         Node *n = li->data;
3878                         if(n->type == METHOD_NODE)
3879                                 add_signal_prots((Method *)n);
3880                 }
3881         }
3882
3883         add_enums (c);
3884
3885         if(any_method_to_alias(c)) {
3886                 out_printf (out, "/* Short form macros */\n");
3887                 make_method_aliases (c);
3888         }
3889
3890         add_interface_inits (c);
3891
3892         if (!overrode_get_type) {
3893                 if (c->bonobo_object_class != NULL)
3894                         add_bonobo_object_get_type();
3895                 else if (c->dynamic)
3896                         add_dynamic_get_type();
3897                 else
3898                         add_get_type();
3899         }
3900
3901         out_printf (out, "/* a macro for creating a new object of our type */\n");
3902         out_printf (out,
3903                     "#define GET_NEW ((%s *)g_object_new(%s_get_type(), NULL))\n\n",
3904                     typebase, funcbase);
3905
3906         out_printf (out, "/* a function for creating a new object of our type */\n");
3907         out_printf (out, "#include <stdarg.h>\n");
3908         out_printf (out,
3909                     "static %s * GET_NEW_VARG (const char *first, ...)%s;\n"
3910                     "static %s *\nGET_NEW_VARG (const char *first, ...)\n"
3911                     "{\n\t%s *ret;\n\tva_list ap;\n"
3912                     "\tva_start (ap, first);\n"
3913                     "\tret = (%s *)g_object_new_valist (%s_get_type (), "
3914                     "first, ap);\n"
3915                     "\tva_end (ap);\n"
3916                     "\treturn ret;\n}\n\n",
3917                     typebase,
3918                     no_gnu ? "" : " G_GNUC_UNUSED",
3919                     typebase, typebase, typebase, funcbase);
3920
3921         if (c->glade_xml)
3922         {
3923                 out_printf (out, "/* a function to connect glade callback */\n");
3924                 out_printf (out,"static void\n"
3925                             "___glade_xml_connect_foreach(const gchar *handler_name,\n"
3926                             "GObject *object,\n"
3927                             "const gchar *signal_name,\n"
3928                             "const gchar *signal_data,\n"
3929                             "GObject *connect_object,\n"
3930                             "gboolean after,\n"
3931                             "gpointer user_data)\n"
3932                             "{\n"
3933                             "\tstatic GModule * allsymbols = NULL;\n"
3934                             "   \n"
3935                             "\tif (!allsymbols) allsymbols = g_module_open(NULL, 0);\n"
3936                             "\tif (allsymbols) {\n"
3937                             "\t\tgchar * func_name = g_strdup_printf(\"%s_%%s\", handler_name);\n"
3938                             "\t\tGCallback func;\n"
3939                             "\n"
3940                             "\t\tif (!g_module_symbol(allsymbols, func_name, (gpointer)&func)){\n"
3941                             "\t\t\tif (!g_module_symbol(allsymbols, handler_name, (gpointer)&func)) {\n"
3942                             "\t\t\t\tg_warning(\"could not find signal handler '%%s'.\", func_name);\n"
3943                             "\t\t\t\tg_free(func_name);\n"
3944                             "\t\t\t\treturn;\n"
3945                             "\t\t\t}\n"
3946                             "\t\t}\n"
3947                             "\t\tif (after)\n"
3948                             "\t\t\tg_signal_connect_data(object, signal_name, func, user_data, NULL, G_CONNECT_AFTER | G_CONNECT_SWAPPED);\n"
3949                             "\t\telse\n"
3950                             "\t\t\tg_signal_connect_data(object, signal_name, func, user_data, NULL, G_CONNECT_SWAPPED);\n"
3951                             "\t\tg_free(func_name);\n"
3952                             "\t}\n"
3953                             "}\n"
3954                             "\n",
3955                             funcbase);
3956         }
3957
3958         for (li = nodes; li != NULL; li = li->next) {
3959                 Node *node = li->data;
3960                 if (node->type == CCODE_NODE) {
3961                         CCode *cc = (CCode *)node;
3962                         if (cc->cctype == AD_CCODE)
3963                                 print_ccode_block (cc);
3964                 }
3965         }
3966
3967         if (need_constructor)
3968                 add_constructor (c);
3969
3970         if (need_dispose)
3971                 add_dispose (c);
3972
3973         if (need_finalize)
3974                 add_finalize (c);
3975
3976         add_inits(c);
3977
3978         if(set_properties > 0) {
3979                 add_getset_arg(c, TRUE);
3980         }
3981
3982         if(get_properties > 0) {
3983                 add_getset_arg(c, FALSE);
3984         }
3985
3986         for(li = c->nodes; li != NULL; li = li->next) {
3987                 Node *n = li->data;
3988                 if(n->type == METHOD_NODE)
3989                         put_method((Method *)n);
3990         }
3991
3992         add_bad_hack_to_avoid_unused_warnings(c);
3993 }
3994
3995 static void
3996 print_useful_macros(void)
3997 {
3998         int major = 0, minor = 0, pl = 0;
3999
4000         /* Version stuff */
4001         sscanf (VERSION, "%d.%d.%d", &major, &minor, &pl);
4002         out_printf (out, "#define GOB_VERSION_MAJOR %d\n", major);
4003         out_printf (out, "#define GOB_VERSION_MINOR %d\n", minor);
4004         out_printf (out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
4005
4006         /* Useful priv macro thingie */
4007         /* FIXME: this should be done the same way that priv is, as a var,
4008          * not a define */
4009         out_printf (out, "#define selfp (self->_priv)\n\n");
4010 }
4011
4012 static void
4013 print_more_useful_macros (void)
4014 {
4015         if (no_gnu) {
4016                 out_printf (out, "#define ___GOB_LIKELY(expr) (expr)\n");
4017                 out_printf (out, "#define ___GOB_UNLIKELY(expr) (expr)\n");
4018         } else {
4019                 out_printf (out, "#ifdef G_LIKELY\n");
4020                 out_printf (out, "#define ___GOB_LIKELY(expr) G_LIKELY(expr)\n");
4021                 out_printf (out, "#define ___GOB_UNLIKELY(expr) G_UNLIKELY(expr)\n");
4022                 out_printf (out, "#else /* ! G_LIKELY */\n");
4023                 out_printf (out, "#define ___GOB_LIKELY(expr) (expr)\n");
4024                 out_printf (out, "#define ___GOB_UNLIKELY(expr) (expr)\n");
4025                 out_printf (out, "#endif /* G_LIKELY */\n");
4026         }
4027 }
4028
4029 static void
4030 print_file_comments(void)
4031 {
4032         out_printf(outh, "/* Generated by GOB (v%s)"
4033                    "   (do not edit directly) */\n\n", VERSION);
4034         if(outph)
4035                 out_printf(outph, "/* Generated by GOB (v%s)"
4036                            "   (do not edit directly) */\n\n", VERSION);
4037         out_printf(out, "/* Generated by GOB (v%s)"
4038                    "   (do not edit directly) */\n\n", VERSION);
4039
4040         out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
4041 }
4042
4043 static void
4044 print_includes(void)
4045 {
4046         gboolean found_header;
4047         char *p;
4048
4049         /* We may need string.h for memset */
4050         if ( ! g_list_find_custom(include_files, "string.h", (GCompareFunc)strcmp)) {
4051                 out_printf(out, "#include <string.h> /* memset() */\n\n");
4052         }
4053
4054         p = g_strconcat(filebase, ".h", NULL);
4055         found_header = TRUE;
4056         if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
4057                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
4058                 found_header = FALSE;
4059         }
4060         g_free(p);
4061
4062         /* if we are creating a private header see if it was included */
4063         if(outph) {
4064                 char sep[2] = {0,0};
4065                 if (file_sep != 0)
4066                         sep[0] = file_sep;
4067                 p = g_strconcat(filebase, sep, "private.h", NULL);
4068                 if( ! g_list_find_custom(include_files, p,
4069                                          (GCompareFunc)strcmp)) {
4070                         out_printf(out, "#include \"%s%sprivate.h\"\n\n",
4071                                    filebase,
4072                                    sep);
4073                         if(found_header)
4074                                 error_printf(GOB_WARN, 0,
4075                                             "Implicit private header include "
4076                                             "added to top of\n"
4077                                             "\tsource file, while public "
4078                                             "header is at a custom location, "
4079                                             "you should\n"
4080                                             "\texplicitly include "
4081                                             "the private header below the "
4082                                             "public one.");
4083                 }
4084                 g_free(p);
4085         }
4086 }
4087
4088 static void
4089 print_header_prefixes(void)
4090 {
4091         char *p;
4092
4093         p = replace_sep(((Class *)class)->otype, '_');
4094         gob_strup (p);
4095         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
4096         if(outph)
4097                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
4098                            "#define __%s_PRIVATE_H__\n\n"
4099                            "#include \"%s.h\"\n\n", p, p, filebase);
4100         g_free(p);
4101
4102         if( ! no_extern_c) {
4103                 out_printf(outh, "#ifdef __cplusplus\n"
4104                            "extern \"C\" {\n"
4105                            "#endif /* __cplusplus */\n\n");
4106                 if(outph)
4107                         out_printf(outph, "#ifdef __cplusplus\n"
4108                                    "extern \"C\" {\n"
4109                                    "#endif /* __cplusplus */\n\n");
4110         }
4111 }
4112
4113 static void
4114 print_header_postfixes(void)
4115 {
4116         if( ! no_extern_c)
4117                 out_printf(outh, "\n#ifdef __cplusplus\n"
4118                            "}\n"
4119                            "#endif /* __cplusplus */\n");
4120         out_printf(outh, "\n#endif\n");
4121         if(outph) {
4122                 if( ! no_extern_c)
4123                         out_printf(outph, "\n#ifdef __cplusplus\n"
4124                                    "}\n"
4125                                    "#endif /* __cplusplus */\n");
4126                 out_printf(outph, "\n#endif\n");
4127         }
4128 }
4129
4130 static void
4131 print_all_top(void)
4132 {
4133         GList *li;
4134
4135         /* print the AT_CCODE and CT_CCODE blocks */
4136         for(li = nodes; li != NULL; li = li->next) {
4137                 Node *node = li->data;
4138                 if(node->type == CCODE_NODE) {
4139                         CCode *cc = (CCode *)node;
4140                         if (cc->cctype == AT_CCODE ||
4141                             cc->cctype == CT_CCODE)
4142                                 print_ccode_block((CCode *)node);
4143                 }
4144         }
4145 }
4146
4147 static void
4148 print_header_top(void)
4149 {
4150         GList *li;
4151
4152         /* mandatory includes */
4153         out_printf (outh, "#include <glib.h>\n");
4154         out_printf (outh, "#include <glib-object.h>\n");
4155
4156         /* print the HT_CCODE blocks */
4157         for (li = nodes; li != NULL; li = li->next) {
4158                 Node *node = li->data;
4159                 if (node->type == CCODE_NODE) {
4160                         CCode *cc = (CCode *)node;
4161                         if (cc->cctype == HT_CCODE)
4162                                 print_ccode_block ((CCode *)node);
4163                 }
4164         }
4165 }
4166
4167 static void
4168 print_enum (EnumDef *enode)
4169 {
4170         GList *li;
4171         char *funcprefix;
4172         char *type;
4173         char *str;
4174
4175         funcprefix = replace_sep (enode->etype, '_');
4176         gob_strdown (funcprefix);
4177         out_printf (out, "static const GEnumValue _%s_values[] = {\n",
4178                     funcprefix);
4179         type = remove_sep (enode->etype);
4180
4181         out_printf (outh, "\ntypedef enum {\n");
4182
4183         for (li = enode->values; li != NULL; li = li->next) {
4184                 EnumValue *value = li->data; 
4185                 char *p;
4186                 char *sname = gob_strdown (g_strdup (value->name));
4187
4188                 while ((p = strchr (sname, '_')) != NULL)
4189                         *p = '-';
4190
4191                 out_printf (outh, "\t%s_%s", enode->prefix, value->name);
4192                 if (value->value != NULL)
4193                         out_printf (outh, " = %s", value->value);
4194                 if (li->next != NULL)
4195                         out_printf (outh, ",\n");
4196                 else
4197                         out_printf (outh, "\n");
4198
4199                 out_printf (out, "\t{ %s_%s, (char *)\"%s_%s\", (char *)\"%s\" },\n",
4200                             enode->prefix, value->name,
4201                             enode->prefix, value->name,
4202                             sname);
4203
4204                 g_free (sname);
4205         }
4206
4207         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
4208
4209         out_printf (outh, "} %s;\n", type);
4210
4211         str = make_pre_macro (enode->etype, "TYPE");
4212         out_printf (outh, "#define %s ", str);
4213         g_free (str);
4214
4215         out_printf (outh, "%s_get_type()\n", funcprefix);
4216         out_printf (outh, "GType %s_get_type (void) G_GNUC_CONST;\n\n", funcprefix);
4217
4218         out_printf (out,
4219                     "GType\n%s_get_type (void)\n"
4220                     "{\n"
4221                     "\tstatic GType type = 0;\n"
4222                     "\tif ___GOB_UNLIKELY(type == 0)\n"
4223                     "\t\ttype = g_enum_register_static (\"%s\", _%s_values);\n"
4224                     "\treturn type;\n"
4225                     "}\n\n",
4226                     funcprefix, type, funcprefix);
4227
4228         g_free (funcprefix);
4229         g_free (type);
4230 }
4231
4232 static void
4233 print_flags (Flags *fnode)
4234 {
4235         GList *li;
4236         char *funcprefix;
4237         char *type;
4238         char *str;
4239         int i;
4240
4241         funcprefix = replace_sep (fnode->ftype, '_');
4242         gob_strdown (funcprefix);
4243         out_printf (out, "static const GFlagsValue _%s_values[] = {\n",
4244                     funcprefix);
4245         type = remove_sep (fnode->ftype);
4246
4247         out_printf (outh, "\ntypedef enum {\n");
4248
4249         for (i = 0, li = fnode->values; li != NULL; i++, li = li->next) {
4250                 const char *name = li->data; 
4251                 char *p;
4252                 char *sname = gob_strdown (g_strdup (name));
4253
4254                 while ((p = strchr (sname, '_')) != NULL)
4255                         *p = '-';
4256
4257                 out_printf (outh, "\t%s_%s = 1<<%d",
4258                             fnode->prefix, name, i);
4259                 if (li->next != NULL)
4260                         out_printf (outh, ",\n");
4261                 else
4262                         out_printf (outh, "\n");
4263
4264                 out_printf (out, "\t{ %s_%s, (char *)\"%s_%s\", (char *)\"%s\" },\n",
4265                             fnode->prefix, name,
4266                             fnode->prefix, name,
4267                             sname);
4268
4269                 g_free (sname);
4270         }
4271
4272         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
4273
4274         out_printf (outh, "} %s;\n", type);
4275
4276         str = make_pre_macro (fnode->ftype, "TYPE");
4277         out_printf (outh, "#define %s ", str);
4278         g_free (str);
4279
4280         out_printf (outh, "%s_get_type()\n", funcprefix);
4281         out_printf (outh, "GType %s_get_type (void) G_GNUC_CONST;\n\n", funcprefix);
4282
4283         out_printf (out,
4284                     "GType\n%s_get_type (void)\n"
4285                     "{\n"
4286                     "\tstatic GType type = 0;\n"
4287                     "\tif ___GOB_UNLIKELY(type == 0)\n"
4288                     "\t\ttype = g_flags_register_static (\"%s\", _%s_values);\n"
4289                     "\treturn type;\n"
4290                     "}\n\n",
4291                     funcprefix, type, funcprefix);
4292
4293         g_free (funcprefix);
4294         g_free (type);
4295 }
4296
4297 static void
4298 print_error (Error *enode)
4299 {
4300         GList *li;
4301         char *funcprefix;
4302         char *type;
4303         char *str;
4304
4305         funcprefix = replace_sep (enode->etype, '_');
4306         gob_strdown (funcprefix);
4307         out_printf (out, "static const GEnumValue _%s_values[] = {\n",
4308                     funcprefix);
4309         type = remove_sep (enode->etype);
4310
4311         out_printf (outh, "\ntypedef enum {\n");
4312
4313         for (li = enode->values; li != NULL; li = li->next) {
4314                 const char *name = li->data;
4315                 char *p;
4316                 char *sname = gob_strdown (g_strdup (name));
4317
4318                 while ((p = strchr (sname, '_')) != NULL)
4319                         *p = '-';
4320
4321                 out_printf (outh, "\t%s_%s", enode->prefix, name);
4322                 if (li->next != NULL)
4323                         out_printf (outh, ",\n");
4324                 else
4325                         out_printf (outh, "\n");
4326
4327                 out_printf (out, "\t{ %s_%s, (char *)\"%s_%s\", (char *)\"%s\" },\n",
4328                             enode->prefix, name,
4329                             enode->prefix, name,
4330                             sname);
4331
4332                 g_free (sname);
4333         }
4334
4335         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
4336
4337         out_printf (outh, "} %s;\n", type);
4338
4339         str = make_pre_macro (enode->etype, "TYPE");
4340         out_printf (outh, "#define %s ", str);
4341         g_free (str);
4342
4343         out_printf (outh, "%s_get_type ()\n", funcprefix);
4344         out_printf (outh, "GType %s_get_type (void) G_GNUC_CONST;\n\n", funcprefix);
4345
4346         out_printf (out,
4347                     "GType\n%s_get_type (void)\n"
4348                     "{\n"
4349                     "\tstatic GType type = 0;\n"
4350                     "\tif ___GOB_UNLIKELY(type == 0)\n"
4351                     "\t\ttype = g_enum_register_static (\"%s\", _%s_values);\n"
4352                     "\treturn type;\n"
4353                     "}\n\n",
4354                     funcprefix, type, funcprefix);
4355
4356         out_printf (outh, "#define %s %s_quark ()\n", enode->prefix, funcprefix);
4357         out_printf (outh, "GQuark %s_quark (void);\n\n", funcprefix);
4358
4359         str = replace_sep (enode->etype, '-');
4360         gob_strdown (str);
4361
4362         out_printf (out,
4363                     "GQuark\n%s_quark (void)\n"
4364                     "{\n"
4365                     "\tstatic GQuark q = 0;\n"
4366                     "\tif (q == 0)\n"
4367                     "\t\tq = g_quark_from_static_string (\"%s\");\n"
4368                     "\treturn q;\n"
4369                     "}\n\n",
4370                     funcprefix, str);
4371
4372         g_free (str);
4373
4374         g_free (funcprefix);
4375         g_free (type);
4376 }
4377
4378 static void
4379 generate_outfiles(void)
4380 {
4381         GList *li;
4382
4383         print_file_comments();
4384
4385         print_all_top();
4386
4387         print_header_top();
4388
4389         print_header_prefixes();
4390
4391         print_useful_macros();
4392
4393         print_includes();
4394
4395         print_more_useful_macros ();
4396
4397         for (li = nodes; li != NULL; li = li->next) {
4398                 Node *node = li->data;
4399                 if (node->type == CCODE_NODE) {
4400                         CCode *cc = (CCode *)node;
4401                         if (cc->cctype != HT_CCODE &&
4402                             cc->cctype != AT_CCODE &&
4403                             cc->cctype != AD_CCODE)
4404                                 print_ccode_block ((CCode *)node);
4405                 } else if (node->type == CLASS_NODE) {
4406                         print_class_block ((Class *)node);
4407                 } else if (node->type == ENUMDEF_NODE) {
4408                         print_enum ((EnumDef *)node);
4409                 } else if (node->type == FLAGS_NODE) {
4410                         print_flags ((Flags *)node);
4411                 } else if (node->type == ERROR_NODE) {
4412                         print_error ((Error *)node);
4413                 } else {
4414                         g_assert_not_reached();
4415                 }
4416         }
4417
4418         print_header_postfixes();
4419 }
4420
4421 static void
4422 print_help(void)
4423 {
4424         fprintf(stderr, "Gob version %s\n\n", VERSION);
4425         fprintf(stderr, "gob [options] file.gob\n\n");
4426         fprintf(stderr, "Options:\n"
4427                 "\t--help,-h,-?            Display this help\n"
4428                 "\t--version               Display version\n"
4429                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
4430                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
4431                 "\t--for-cpp               Create C++ files\n"
4432                 "\t--no-extern-c           Never print extern \"C\" into the "
4433                                           "header\n"
4434                 "\t--no-gnu                Never use GNU extentions\n"
4435                 "\t--no-touch              Don't touch output files unless they "
4436                                           "really\n"
4437                 "\t                        changed (implies --no-touch-headers)\n"
4438                 "\t--no-touch-headers      Don't touch headers unless they "
4439                                           "really changed\n"
4440                 "\t--always-private-header Always create a private header "
4441                                           "file,\n"
4442                 "\t                        even if it would be empty\n"
4443                 "\t--ondemand-private-header Create private header only when "
4444                                           "needed\n"
4445                 "\t                        [default]\n"
4446                 "\t--no-private-header     Don't create a private header, "
4447                                           "put private\n"
4448                 "\t                        structure and protected "
4449                                           "prototypes inside c file\n"
4450                 "\t--always-private-struct Always create a private pointer "
4451                                           "in\n"
4452                 "\t                        the object structure\n"
4453                 "\t--m4                    Preprocess source with m4. "
4454                                           "Following args will\n"
4455                 "\t                        be passed to m4\n"
4456                 "\t--m4-dir                Print directory that will be "
4457                                           "searched for m4\n"
4458                 "\t                        files\n"
4459                 "\t--no-write,-n           Don't write output files, just "
4460                                           "check syntax\n"
4461                 "\t--no-lines              Don't print '#line' to output\n"
4462                 "\t--no-self-alias         Don't create self type and macro "
4463                                           "aliases\n"
4464                 "\t--no-kill-underscores   Ignored for compatibility\n"
4465                 "\t-o,--output-dir         The directory where output "
4466                                           "should be placed\n"
4467                 "\t--file-sep[=c]          replace default \'-\' file "
4468                                           "name separator\n\n"
4469                 "\t--gtk3                  Use gtk+3\n"
4470                 );
4471         fprintf(stderr, "End world hunger, donate to the World Food Programme, http://www.wfp.org\n");
4472 }
4473
4474 static void
4475 parse_options(int argc, char *argv[])
4476 {
4477         int i;
4478         int got_file = FALSE;
4479         int no_opts = FALSE;
4480         int m4_opts = FALSE; /* if we are just passing on args to m4 */
4481
4482         filename = NULL;
4483
4484         for(i = 1 ; i < argc; i++) {
4485                 if(m4_opts) {
4486                         char *new_commandline;
4487                         g_assert(m4_commandline!=NULL);
4488
4489                         /* check whether this one looks like the filename */
4490                         if((!strcmp(argv[i],"-") || argv[i][0] != '-') 
4491                            && !got_file) {
4492                                 const gchar *m4_flags=use_m4_clean?"":M4_FLAGS;
4493                                 filename = argv[i];
4494                                 got_file = TRUE;
4495                                 
4496                                 /* insert flags before the filename */
4497                                 new_commandline=g_strconcat(m4_commandline,
4498                                                             " ",
4499                                                             m4_flags, 
4500                                                             " ",
4501                                                             argv[i],
4502                                                             NULL);
4503                         }
4504
4505                         /* just an ordinary option */
4506                         else                      
4507                           new_commandline=g_strconcat(m4_commandline,
4508                                                       " ",
4509                                                       argv[i],
4510                                                       NULL);
4511
4512                         /* free old commandline */
4513                         g_free(m4_commandline);
4514                         m4_commandline=new_commandline;
4515
4516                 } else if(no_opts ||
4517                    argv[i][0] != '-') {
4518                         /*must be a file*/
4519                         if(got_file) {
4520                                 fprintf(stderr, "Specify only one file!\n");
4521                                 print_help();
4522                                 exit(1);
4523                         }
4524                         filename = argv[i];
4525                         got_file = TRUE;
4526                 } else if(strcmp(argv[i], "--help")==0) {
4527                         print_help();
4528                         exit(0);
4529                 } else if(strcmp(argv[i], "--version")==0) {
4530                         fprintf(stderr, "Gob version %s\n", VERSION);
4531                         exit(0);
4532                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
4533                         exit_on_warn = TRUE;
4534                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
4535                         exit_on_warn = FALSE;
4536                 } else if(strcmp(argv[i], "--for-cpp")==0) {
4537                         for_cpp = TRUE;
4538                 } else if(strcmp(argv[i], "--no-touch")==0) {
4539                         no_touch = TRUE;
4540                         no_touch_headers = TRUE;
4541                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
4542                         no_touch_headers = TRUE;
4543                 } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
4544                         private_header = PRIVATE_HEADER_ONDEMAND;
4545                 } else if(strcmp(argv[i], "--always-private-header")==0) {
4546                         private_header = PRIVATE_HEADER_ALWAYS;
4547                 } else if(strcmp(argv[i], "--no-private-header")==0) {
4548                         private_header = PRIVATE_HEADER_NEVER;
4549                 } else if(strcmp(argv[i], "--no-gnu")==0) {
4550                         no_gnu = TRUE;
4551                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
4552                         no_extern_c = TRUE;
4553                 } else if(strcmp(argv[i], "--no-write")==0) {
4554                         no_write = TRUE;
4555                 } else if(strcmp(argv[i], "--no-lines")==0) {
4556                         no_lines = TRUE;
4557                 } else if(strcmp(argv[i], "--no-self-alias")==0) {
4558                         no_self_alias = TRUE;
4559                 } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
4560                         /* no op */;
4561                 } else if(strcmp(argv[i], "--always-private-struct")==0) {
4562                         always_private_struct = TRUE;
4563                 } else if(strcmp(argv[i], "--m4-dir")==0) {
4564                         printf("%s\n",M4_INCLUDE_DIR);
4565                         exit(0);
4566                 } else if(strcmp(argv[i], "--m4")==0) {
4567                         use_m4 = TRUE;
4568                         use_m4_clean=FALSE;
4569                         m4_opts = TRUE;
4570                         m4_commandline=g_strdup(M4_COMMANDLINE);
4571                 } else if(strcmp(argv[i], "--m4-clean")==0) {
4572                         use_m4 = TRUE;
4573                         use_m4_clean=TRUE;
4574                         m4_opts = TRUE;
4575                         m4_commandline=g_strdup(M4_COMMANDLINE);
4576                 } else if (strcmp (argv[i], "-o") == 0 || 
4577                            strcmp (argv[i], "--output-dir") == 0) {
4578                         if (i+1 < argc) {
4579                                 output_dir = g_strdup (argv[i+1]);
4580                                 i++;
4581                         } else {
4582                                 output_dir = NULL;
4583                         }
4584                 } else if (strncmp (argv[i], "-o=", strlen ("-o=")) == 0 || 
4585                            strncmp (argv[i],
4586                                     "--output-dir=",
4587                                     strlen ("--output-dir=")) == 0) {
4588                         char *p = strchr (argv[i], '=');
4589                         g_assert (p != NULL);
4590                         output_dir = g_strdup (p+1);
4591                 } else if (strncmp (argv[i], "--file-sep=",
4592                                     strlen ("--file-sep=")) == 0) {
4593                         char *p = strchr (argv[i], '=');
4594                         g_assert (p != NULL);
4595                         file_sep = *(p+1);
4596                 } else if (strncmp (argv[i], "--file-sep",
4597                                     strlen ("--file-sep")) == 0) {
4598                         if (i+1 < argc) {
4599                                 file_sep = (argv[i+1])[0];
4600                                 i++;
4601                         } else {
4602                                 file_sep = 0;
4603                         }
4604                 } else if(strcmp(argv[i], "--gtk3")==0) {
4605                         gtk3_ok = TRUE;
4606                 } else if(strcmp(argv[i], "--")==0) {
4607                         /*further arguments are files*/
4608                         no_opts = TRUE;
4609                 } else if(strncmp(argv[i], "--", 2)==0) {
4610                         /*unknown long option*/
4611                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
4612                         print_help();
4613                         exit(1);
4614                 } else {
4615                         /*by now we know we have a string starting with
4616                           - which is a short option string*/
4617                         char *p;
4618                         for(p = argv[i] + 1; *p; p++) {
4619                                 switch(*p) {
4620                                 case 'w':
4621                                         exit_on_warn=TRUE;
4622                                         break;
4623                                 case 'n':
4624                                         no_write = TRUE;
4625                                         break;
4626                                 case 'h':
4627                                 case '?':
4628                                         print_help();
4629                                         exit(0);
4630                                 default:
4631                                         fprintf(stderr,
4632                                                 "Unknown option '%c'!\n", *p);
4633                                         print_help();
4634                                         exit(1);
4635                                 }
4636                         }
4637                 }
4638         }
4639
4640 #if 0
4641         /* if we are using m4, and got no filename, append m4 flags now */
4642         if(!got_file && use_m4 && !use_m4_clean) {
4643                 char *new_commandline;
4644                 new_commandline=g_strconcat(m4_commandline,
4645                                             " ",
4646                                             M4_FLAGS,
4647                                             NULL);
4648                 g_free(m4_commandline);
4649                 m4_commandline=new_commandline;
4650         }
4651 #endif
4652 }
4653
4654 static void
4655 compare_and_move (const char *old_filename)
4656 {
4657         char *new_filename = g_strconcat (old_filename, "#gob#", NULL);
4658         FILE *old_f;
4659         gboolean equal = FALSE;
4660
4661         old_f = fopen (old_filename, "r");
4662         if (old_f) {
4663                 FILE *new_f;
4664                 gboolean error = FALSE;
4665
4666                 new_f = fopen (new_filename, "r");
4667                 if (new_f) {
4668                         char new_buf[1024];
4669                         char old_buf[1024];
4670
4671                         while (TRUE) {
4672                                 size_t new_n;
4673                                 size_t old_n;
4674
4675                                 new_n = fread (new_buf, 1, sizeof (new_buf), new_f);
4676                                 if (ferror (new_f)) {
4677                                         error = TRUE;
4678                                         error_printf (GOB_ERROR, 0,
4679                                                       "Can't read %s: %s",
4680                                                       new_filename,
4681                                                       g_strerror (errno));
4682                                         break;
4683                                 }
4684
4685                                 old_n = fread (old_buf, 1, sizeof (old_buf), old_f);
4686                                 if (ferror (old_f)
4687                                     || feof (new_f) != feof (old_f)
4688                                     || new_n != old_n
4689                                     || memcmp (new_buf, old_buf, new_n) != 0)
4690                                         break;
4691
4692                                 if (feof (new_f)) {
4693                                         equal = TRUE;
4694                                         break;
4695                                 }
4696                         }
4697                 } else
4698                         error_printf (GOB_ERROR, 0, "Can't open %s: %s",
4699                                       new_filename, g_strerror (errno));
4700
4701                 fclose (old_f);
4702                 fclose (new_f);
4703
4704                 if (error)
4705                         goto end;
4706
4707                 if (! equal && unlink (old_filename) != 0) {
4708                         error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
4709                                       old_filename, g_strerror (errno));
4710                         goto end;
4711                 }
4712         }
4713
4714         if (equal) {
4715                 if (unlink (new_filename) != 0)
4716                         error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
4717                                       new_filename, g_strerror (errno));
4718         } else {
4719                 if (rename (new_filename, old_filename) != 0)
4720                         error_printf (GOB_ERROR, 0, "Can't rename %s to %s: %s",
4721                                       new_filename, old_filename,
4722                                       g_strerror (errno));
4723         }
4724
4725  end:
4726         g_free (new_filename);
4727 }
4728
4729 int
4730 main(int argc, char *argv[])
4731 {
4732         parse_options(argc, argv);
4733
4734         if(use_m4) {
4735                 yyin = popen(m4_commandline, "r");
4736                 if(!yyin) {
4737                         fprintf(stderr, "Error: can't open pipe from '%s'\n",
4738                                 m4_commandline);
4739                         exit(1);
4740                 }
4741         } else if(filename) {
4742                 yyin = fopen(filename, "r");
4743                 if(!yyin) {
4744                         fprintf(stderr, "Error: can't open file '%s'\n",
4745                                 filename);
4746                         exit(1);
4747                 }
4748         }
4749
4750         if(filename==NULL)
4751                 filename = "stdin";
4752
4753         /* This is where parsing is done */
4754         /*yydebug = 1;*/
4755         if(yyparse() != 0)
4756                 error_print (GOB_ERROR, 0, "Parsing errors, quitting");
4757
4758         /* close input file */
4759         if(use_m4) pclose(yyin);
4760         else fclose(yyin);
4761         yyin=stdin;
4762
4763         if( ! class)
4764                 error_print (GOB_ERROR, 0, "no class defined");
4765         
4766
4767         exit_on_error = FALSE;
4768
4769         signals = count_signals ((Class *)class);
4770         set_properties = count_set_properties ((Class *)class) +
4771                 count_set_arguments ((Class *)class);
4772         get_properties = count_get_properties ((Class *)class) +
4773                 count_get_arguments ((Class *)class);
4774         overrides = count_overrides ((Class *)class);
4775         privates = count_privates ((Class *)class);
4776         protecteds = count_protecteds ((Class *)class);
4777         unreftors = count_unreftors ((Class *)class);
4778         destructors = count_destructors ((Class *)class);
4779         initializers = count_initializers ((Class *)class);
4780         glade_widgets = count_glade_widgets ((Class *)class);
4781         overrode_get_type = find_get_type ((Class *)class);
4782
4783         make_bases ();
4784         make_inits ((Class *)class);
4785
4786         find_constructor ((Class *)class);
4787         if (user_constructor != NULL)
4788                 need_constructor = TRUE;
4789
4790         find_dispose ((Class *)class);
4791         if (unreftors > 0 ||
4792             dispose_handler != NULL ||
4793             user_dispose_method != NULL)
4794                 need_dispose = TRUE;
4795
4796         find_finalize ((Class *)class);
4797         if (destructors > 0 ||
4798             privates > 0 ||
4799             user_finalize_method != NULL) {
4800                 need_finalize = TRUE;
4801         }
4802
4803         check_bad_symbols ((Class *)class);
4804         check_duplicate_symbols ((Class *)class);
4805         check_duplicate_overrides ((Class *)class);
4806         check_duplicate_signals_args ((Class *)class);
4807         check_public_new ((Class *)class);
4808         check_vararg ((Class *)class);
4809         check_firstarg ((Class *)class);
4810         check_nonvoidempty ((Class *)class);
4811         check_signal_args ((Class *)class);
4812         check_property_types ((Class *)class);
4813         check_argument_types ((Class *)class);
4814         check_func_arg_checks ((Class *)class);
4815         check_func_attrs ((Class *)class);
4816         check_for_class_destructors ((Class *)class);
4817
4818         exit_on_error = TRUE;
4819         
4820         if (got_error)
4821                 exit (1);
4822
4823         any_special = setup_special_array ((Class *)class, special_array);
4824
4825         open_files ();
4826         
4827         generate_outfiles ();
4828
4829         if (out)
4830                 fclose (out);
4831         if (outh)
4832                 fclose (outh);
4833         if (outph)
4834                 fclose (outph);
4835
4836         if (! no_write) {
4837                 if (no_touch) {
4838                         compare_and_move (outfilebase);
4839                         if (outfilephbase)
4840                                 compare_and_move (outfilephbase);
4841                 }
4842                 if (no_touch_headers)
4843                         compare_and_move (outfilehbase);
4844         }
4845         
4846         return 0;
4847 }