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