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