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