]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
5767215395598cef7ed841f4edb636fdf732cabc
[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 (void)
1126 {
1127         GList *li;
1128         for (li = ((Class *)class)->interfaces;
1129              li != NULL;
1130              li = li->next) {
1131                 char *name = replace_sep (li->data, '_');
1132                 out_printf (out,
1133                             "\t\tstatic const GInterfaceInfo %s_info = {\n"
1134                             "\t\t\t(GInterfaceInitFunc) ___%s_init,\n"
1135                             "\t\t\tNULL,\n"
1136                             "\t\t\tNULL\n"
1137                             "\t\t};\n\n",
1138                             name, name);
1139                 g_free (name);
1140         }
1141 }
1142
1143 static void
1144 add_interfaces (void)
1145 {
1146         GList *li;
1147         for (li = ((Class *)class)->interfaces;
1148              li != NULL;
1149              li = li->next) {
1150                 char *name = replace_sep (li->data, '_');
1151                 char *type = make_pre_macro (li->data, "TYPE");
1152
1153                 out_printf (out,
1154                             "\t\tg_type_add_interface_static (type,\n"
1155                             "\t\t\t%s,\n"
1156                             "\t\t\t&%s_info);\n",
1157                             type,
1158                             name);
1159
1160                 g_free (type);
1161                 g_free (name);
1162         }
1163 }
1164
1165 static void
1166 add_dynamic_interfaces(void)
1167 {
1168         GList *li = ((Class *)class)->interfaces;
1169
1170         if (li) {
1171                 /*
1172                  * Hack to work around bug in g_type_module_add_interface,
1173                  * which will fail to add an interface to types that derive
1174                  * from something that also implements the same interface.
1175                  *
1176                  * The actual GType system does not have any such problem,
1177                  * and the GTypeModule implementation details relied upon
1178                  * here have not changed once since the feature was first
1179                  * implemented almost 20 years ago.
1180                  */
1181                 out_printf(out, "\t\tstruct _ModuleInterfaceInfo {\n"
1182                                 "\t\t\tgboolean loaded;\n"
1183                                 "\t\t\tGType instance_type;\n"
1184                                 "\t\t\tGType interface_type;\n"
1185                                 "\t\t\tGInterfaceInfo info;\n"
1186                                 "\t\t} *modinfo;\n");
1187         }
1188
1189         for (; li; li = li->next) {
1190                 char *name = replace_sep(li->data, '_');
1191                 char *type = make_pre_macro(li->data, "TYPE");
1192
1193                 out_printf(out, "\n"
1194                                 "\t\tmodinfo = g_malloc(sizeof *modinfo);\n"
1195                                 "\t\tmodinfo->loaded = TRUE;\n"
1196                                 "\t\tmodinfo->instance_type = %s_type_id;\n"
1197                                 "\t\tmodinfo->interface_type = %s;\n"
1198                                 "\t\tmodinfo->info = %s_info;\n"
1199                                 "\t\tg_type_add_interface_dynamic\n"
1200                                 "\t\t\t( modinfo->instance_type\n"
1201                                 "\t\t\t, modinfo->interface_type\n"
1202                                 "\t\t\t, G_TYPE_PLUGIN(type_module)\n"
1203                                 "\t\t\t);\n"
1204                                 "\t\ttype_module->interface_infos = g_slist_prepend\n"
1205                                 "\t\t\t( type_module->interface_infos\n"
1206                                 "\t\t\t, modinfo\n"
1207                                 "\t\t\t);\n", funcbase, type, name);
1208
1209                 g_free(type);
1210                 g_free(name);
1211         }
1212 }
1213
1214 static void
1215 add_get_type(void)
1216 {
1217         /*char *chunk_size = ((Class*)class)->chunk_size;*/
1218
1219         out_printf(out,
1220                    "GType\n"
1221                    "%s_get_type (void)\n"
1222                    "{\n"
1223                    "\tstatic GType type = 0;\n\n"
1224                    "\tif ___GOB_UNLIKELY(type == 0) {\n"
1225                    "\t\tstatic const GTypeInfo info = {\n"
1226                    "\t\t\tsizeof (%sClass),\n"
1227                    "\t\t\t(GBaseInitFunc) NULL,\n"
1228                    "\t\t\t(GBaseFinalizeFunc) NULL,\n"
1229                    "\t\t\t(GClassInitFunc) %s_class_init,\n"
1230                    "\t\t\t(GClassFinalizeFunc) NULL,\n"
1231                    "\t\t\tNULL /* class_data */,\n"
1232                    "\t\t\tsizeof (%s),\n"
1233                    "\t\t\t%d /* n_preallocs */,\n"
1234                    "\t\t\t(GInstanceInitFunc) %s_init,\n"
1235                    "\t\t\tNULL\n"
1236                    "\t\t};\n\n",
1237                    funcbase, typebase, funcbase, typebase, prealloc, funcbase);
1238
1239         add_interface_infos ();
1240
1241         out_printf (out,
1242                     "\t\ttype = g_type_register_static (%s, \"%s\", &info, (GTypeFlags)%s);\n",
1243                     pmacrotype, typebase, ((Class *)class)->abstract ? "G_TYPE_FLAG_ABSTRACT" : "0");
1244
1245         add_interfaces ();
1246
1247         /*
1248         if(chunk_size)  {
1249                 out_printf(out,
1250                            "#if %s > 0\n"
1251                            "\t\tgtk_type_set_chunk_alloc(type, %s);\n"
1252                            "#endif\n", 
1253                            chunk_size, chunk_size);
1254         }
1255         */
1256         out_printf(out,
1257                    "\t}\n\n"
1258                    "\treturn type;\n"
1259                    "}\n\n");
1260 }
1261
1262 static void
1263 add_dynamic_get_type (void)
1264 {
1265         out_printf(out,
1266                    "static GType %s_type_id;\n\n"
1267                    "GType\n"
1268                    "%s_get_type (void)\n"
1269                    "{\n"
1270                    "\treturn %s_type_id;\n"
1271                    "}\n\n",
1272                    funcbase, funcbase, funcbase);
1273
1274         out_printf(out,
1275                    "void\n"
1276                    "%s_register_type (GTypeModule *type_module)\n"
1277                    "{\n"
1278                    "\tstatic const GTypeInfo info = {\n"
1279                    "\t\tsizeof (%sClass),\n"
1280                    "\t\t(GBaseInitFunc) NULL,\n"
1281                    "\t\t(GBaseFinalizeFunc) NULL,\n"
1282                    "\t\t(GClassInitFunc) %s_class_init,\n"
1283                    "\t\t(GClassFinalizeFunc) NULL,\n"
1284                    "\t\tNULL /* class_data */,\n"
1285                    "\t\tsizeof (%s),\n"
1286                    "\t\t%d /* n_preallocs */,\n"
1287                    "\t\t(GInstanceInitFunc) %s_init,\n"
1288                    "\t\tNULL\n"
1289                    "\t};\n\n",
1290                    funcbase, typebase, funcbase, typebase, prealloc, funcbase);
1291
1292         add_interface_infos();
1293
1294         out_printf(out,
1295                    "\t%s_type_id = g_type_module_register_type(\n"
1296                    "\t\ttype_module,\n"
1297                    "\t\t%s,\n"
1298                    "\t\t\"%s\",\n"
1299                    "\t\t&info,\n"
1300                    "\t\t(GTypeFlags)%s\n"
1301                    "\t);\n\n"
1302                    "\t{\n",
1303                    funcbase, pmacrotype, typebase,
1304                    ((Class *)class)->abstract ? "G_TYPE_FLAG_ABSTRACT" : "0");
1305
1306         add_dynamic_interfaces();
1307
1308         out_printf(out,
1309                    "\t}\n"
1310                    "}\n\n");
1311 }
1312
1313 static void
1314 add_bonobo_object_get_type (void)
1315 {
1316         /* char *chunk_size = ((Class*)class)->chunk_size; */
1317         /* _vicious_ spanks seth with a rusty nail
1318         out_printf(out,
1319                    "\n#warning \"Bonobo isn't fully ported to glib 2.0 and "
1320                    "gob2 doesn't officially support it yet. It'd be safer "
1321                    "and a lot more fun to blow goats.\"\n");
1322                    */
1323
1324         out_printf (out,
1325                     "GType\n"
1326                     "%s_get_type (void)\n" /* 1 */
1327                     "{\n"
1328                     "\tstatic GType type = 0;\n\n"
1329                     "\tif ___GOB_UNLIKELY(type == 0) {\n"
1330                     "\t\tstatic const GTypeInfo info = {\n"
1331                     "\t\t\tsizeof (%sClass),\n" /* 2 */
1332                     "\t\t\t(GBaseInitFunc) NULL,\n"
1333                     "\t\t\t(GBaseFinalizeFunc) NULL,\n"
1334                     "\t\t\t(GClassInitFunc) %s_class_init,\n" /* 3 */
1335                     "\t\t\tNULL, /* class_finalize */\n"
1336                     "\t\t\tNULL, /* class_data */\n"
1337                     "\t\t\tsizeof (%s),\n" /* 4 */
1338                     "\t\t\t0, /* n_preallocs */\n"
1339                     "\t\t\t(GInstanceInitFunc)  %s_init,\n" /* 5 */
1340                     "\t\t\tNULL\n"
1341                     "\t\t};\n\n",
1342                     funcbase /* 1 */,
1343                     typebase /* 2 */,
1344                     funcbase /* 3 */,
1345                     typebase /* 4 */,
1346                     funcbase /* 5 */);
1347
1348         add_interface_infos ();
1349
1350         out_printf (out,
1351                    "\t\ttype = bonobo_type_unique (\n"
1352                    "\t\t\tBONOBO_OBJECT_TYPE,\n"
1353                    "\t\t\tPOA_%s__init, NULL,\n" /* 1 */
1354                    "\t\t\tG_STRUCT_OFFSET (%sClass, _epv),\n" /* 2 */
1355                    "\t\t\t&info, \"%s\");\n", /* 3 */
1356                    ((Class*)class)->bonobo_object_class /* 1 */,
1357                    typebase /* 2 */,
1358                    typebase /* 3 */);
1359
1360         add_interfaces ();
1361
1362         /*if(chunk_size)  {
1363                 out_printf(out,
1364                            "#if %s > 0\n"
1365                            "\t\tgtk_type_set_chunk_alloc(type, %s);\n"
1366                            "#endif\n", 
1367                            chunk_size, chunk_size);
1368         }*/
1369         out_printf(out,
1370                    "\t}\n\n"
1371                    "\treturn type;\n"
1372                    "}\n\n");
1373 }
1374
1375 static void
1376 add_overrides(Class *c, const char *oname,
1377               gboolean did_base_obj)
1378 {
1379         GList *li;
1380         GHashTable *done;
1381         char *s;
1382         
1383         done = g_hash_table_new (g_str_hash, g_str_equal);
1384         if (did_base_obj) {
1385                 s = g_strdup ("GObject");
1386                 g_hash_table_insert (done, s, s);
1387         }
1388         for (li = c->nodes; li != NULL; li = li->next) {
1389                 Node *n = li->data;
1390                 char *f;
1391                 Method *m = (Method *)n;
1392                 if(n->type != METHOD_NODE ||
1393                    m->method != OVERRIDE_METHOD)
1394                         continue;
1395
1396                 s = remove_sep(m->otype);
1397                 
1398                 if(g_hash_table_lookup(done, s)) {
1399                         g_free(s);
1400                         continue;
1401                 }
1402                 g_hash_table_insert(done, s, s);
1403
1404                 f = replace_sep(m->otype, '_');
1405                 gob_strdown(f);
1406
1407                 out_printf(out, "\t%sClass *%s_class = (%sClass *)%s;\n",
1408                            s, f, s, oname);
1409                 
1410                 g_free(f);
1411         }
1412         g_hash_table_foreach (done, (GHFunc)g_free, NULL);
1413         g_hash_table_destroy (done);
1414 }
1415
1416 static char *
1417 make_run_signal_flags(Method *m, gboolean last)
1418 {
1419         GList *li;
1420         GString *gs;
1421         char *flags[] = {
1422                 "RUN_FIRST",
1423                 "RUN_LAST",
1424                 "RUN_CLEANUP",
1425                 "NO_RECURSE",
1426                 "DETAILED",
1427                 "ACTION",
1428                 "NO_HOOKS",
1429                 NULL
1430         };
1431
1432         gs = g_string_new(NULL);
1433
1434         if(last)
1435                 g_string_assign(gs, "G_SIGNAL_RUN_LAST");
1436         else
1437                 g_string_assign(gs, "G_SIGNAL_RUN_FIRST");
1438
1439         if(m->scope == PUBLIC_SCOPE)
1440                 g_string_append(gs, " | G_SIGNAL_ACTION");
1441
1442         for(li = m->flags; li; li = li->next) {
1443                 char *flag = li->data;
1444                 int i;
1445                 for(i=0;flags[i];i++) {
1446                         if(strcmp(flags[i], flag)==0)
1447                                 break;
1448                 }
1449                 /* if we haven't found it in our list */
1450                 if( ! flags[i]) {
1451                         error_printf(GOB_WARN, m->line_no,
1452                                      "Unknown flag '%s' used, "
1453                                      "perhaps it was misspelled",
1454                                      flag);
1455                 }
1456                 g_string_sprintfa(gs, " | G_SIGNAL_%s", flag);
1457         }
1458
1459         {
1460                 char *ret = gs->str;
1461                 g_string_free(gs, FALSE);
1462                 return ret;
1463         }
1464 }
1465                 
1466
1467 static void
1468 add_signals(Class *c)
1469 {
1470         GList *li;
1471
1472         out_printf(out, "\n");
1473         for(li=c->nodes;li;li=g_list_next(li)) {
1474                 Node *n = li->data;
1475                 char *mar, *sig, *flags;
1476                 gboolean is_none, last = FALSE;
1477                 Method *m = (Method *)n;
1478
1479                 if(n->type != METHOD_NODE ||
1480                    (m->method != SIGNAL_FIRST_METHOD &&
1481                     m->method != SIGNAL_LAST_METHOD))
1482                         continue;
1483
1484                 if(m->method == SIGNAL_FIRST_METHOD)
1485                         last = FALSE;
1486                 else
1487                         last = TRUE;
1488
1489                 if(g_hash_table_lookup(marsh, m))
1490                         mar = g_strconcat("___marshal_",
1491                                           (char *)g_hash_table_lookup(marsh, m),
1492                                           NULL);
1493                 else
1494                         mar = g_strdup("g_cclosure_marshal_VOID__VOID");
1495                 
1496                 is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
1497
1498                 sig = g_strdup (m->id);
1499                 gob_strup (sig);
1500                 flags = make_run_signal_flags (m, last);
1501                 out_printf (out, "\tobject_signals[%s_SIGNAL] =\n"
1502                             "\t\tg_signal_new (%s,\n"
1503                             "\t\t\tG_TYPE_FROM_CLASS (g_object_class),\n"
1504                             "\t\t\t(GSignalFlags)(%s),\n"
1505                             "\t\t\tG_STRUCT_OFFSET (%sClass, %s),\n"
1506                             "\t\t\tNULL, NULL,\n"
1507                             "\t\t\t%s,\n"
1508                             "\t\t\tG_TYPE_%s, %d",
1509                             sig, m->signal_name /*m->id* if not given signal_name*/,
1510                             flags,
1511                             typebase, m->id, mar,
1512                             (char *)m->gtktypes->data,
1513                             is_none ? 0 : g_list_length(m->gtktypes->next));
1514                 g_free(mar);
1515                 g_free(sig);
1516                 g_free(flags);
1517                 
1518                 if( ! is_none) {
1519                         GList *l;
1520                         char  *t;
1521                         for(l = m->gtktypes->next; l != NULL; l = l->next) {
1522                                 char *str = l->data;
1523                                 if (strncmp (str, "BOXED_", 6) == 0)
1524                                         t = g_strdup (&(str[6]));
1525                                 else
1526                                         t = g_strconcat ("G_TYPE_", str, NULL);
1527                                 out_printf (out, ",\n\t\t\t%s", t);
1528                                 g_free (t);
1529                         }
1530                 }
1531
1532                 out_printf(out, ");\n");
1533
1534                 if(strcmp(m->gtktypes->data, "NONE") != 0 ||
1535                    ! is_none) {
1536                         GList *gl, *al;
1537                         out_printf(out, "\tif ___GOB_UNLIKELY(");
1538                         if(strcmp(m->gtktypes->data, "NONE") != 0) {
1539                                 out_printf(out, "sizeof(");
1540                                 print_type(out, m->mtype, FALSE);
1541                                 out_printf(out, "%s",
1542                                            m->mtype->postfix ?
1543                                            m->mtype->postfix : ""); 
1544                                 out_printf(out, ") != sizeof(%s) || ",
1545                                            get_cast(m->gtktypes->data, FALSE));
1546                         }
1547
1548                         for(al = m->args->next, gl = m->gtktypes->next;
1549                             al != NULL && gl != NULL;
1550                             al = al->next, gl = gl->next) {
1551                                 FuncArg *arg = al->data;
1552                                 char *gtkarg = gl->data;
1553
1554                                 out_printf(out, "sizeof(");
1555                                 print_type(out, arg->atype, FALSE);
1556                                 out_printf(out, "%s",
1557                                            arg->atype->postfix ?
1558                                            arg->atype->postfix : ""); 
1559                                 out_printf(out, ") != sizeof(%s) || ",
1560                                            get_cast(gtkarg, FALSE));
1561                         }
1562
1563                         out_printf (out,
1564                                     "parent_class == NULL /* avoid warning */");
1565
1566                         out_printf(out, ") {\n"
1567                                    "\t\tg_error(\"%s line %d: Type mismatch "
1568                                    "of \\\"%s\\\" signal signature\");\n"
1569                                    "\t}\n",
1570                                    filename, m->line_no, m->id);
1571
1572                 }
1573         }
1574 }
1575
1576 static void
1577 set_def_handlers(Class *c, const char *oname)
1578 {
1579         GList *li;
1580         gboolean set_line = FALSE;
1581
1582         out_printf(out, "\n");
1583         for(li = c->nodes; li; li = g_list_next(li)) {
1584                 Node *n = li->data;
1585                 Method *m = (Method *)n;
1586
1587                 if(n->type != METHOD_NODE ||
1588                    (m->method != SIGNAL_FIRST_METHOD &&
1589                     m->method != SIGNAL_LAST_METHOD &&
1590                     m->method != VIRTUAL_METHOD &&
1591                     m->method != OVERRIDE_METHOD))
1592                         continue;
1593
1594                 if(m->line_no > 0 && m->cbuf) {
1595                         out_addline_infile(out, m->line_no);
1596                         set_line = TRUE;
1597                 } else if(set_line) {
1598                         out_addline_outfile(out);
1599                         set_line = FALSE;
1600                 }
1601
1602
1603                 if (m->method == OVERRIDE_METHOD) {
1604                         char *s;
1605                         s = replace_sep (m->otype, '_');
1606                         gob_strdown (s);
1607
1608                         if (need_dispose &&
1609                             dispose_handler != NULL &&
1610                             strcmp (m->id, "dispose") == 0)
1611                                 out_printf (out, "\tg_object_class->dispose "
1612                                             "= ___dispose;\n");
1613                         else if (need_finalize &&
1614                                 finalize_handler &&
1615                                 strcmp(m->id, "finalize") == 0)
1616                                 out_printf(out,
1617                                            "\tg_object_class->finalize = ___finalize;\n");
1618                         else if (m->cbuf != NULL)
1619                                 out_printf(out,
1620                                            "\t%s_class->%s = ___%x_%s_%s;\n",
1621                                            s, m->id, (guint)m->unique_id,
1622                                            funcbase, m->id);
1623                         else
1624                                 out_printf(out, "\t%s_class->%s = NULL;\n",
1625                                            s, m->id);
1626                 } else {
1627                         if(m->cbuf)
1628                                 out_printf(out, "\t%s->%s = ___real_%s_%s;\n",
1629                                            oname, m->id,
1630                                            funcbase, m->id);
1631                         else
1632                                 out_printf(out, "\t%s->%s = NULL;\n",
1633                                            oname, m->id);
1634                 }
1635         }
1636         if(set_line)
1637                 out_addline_outfile(out);
1638 }
1639
1640 static void
1641 make_argument (Argument *a)
1642 {
1643         GString *flags;
1644         GList *l;
1645         char *s;
1646         char *argflags[] = {
1647                 "CONSTRUCT",
1648                 "CONSTRUCT_ONLY",
1649                 "LAX_VALIDATION",
1650                 "PRIVATE",
1651                 NULL
1652         };
1653
1654         flags = g_string_new ("(GParamFlags)(");
1655
1656         if(a->get && a->set)
1657                 g_string_append (flags, "G_PARAM_READABLE | G_PARAM_WRITABLE");
1658         else if(a->get)
1659                 g_string_append (flags, "G_PARAM_READABLE");
1660         else
1661                 g_string_append (flags, "G_PARAM_WRITABLE");
1662
1663         g_assert(a->get || a->set);
1664
1665         for (l = a->flags; l != NULL; l = l->next) {
1666                 char *flag = l->data;
1667                 int i;
1668                 if(strcmp (flag, "READABLE") == 0 ||
1669                    strcmp (flag, "WRITABLE") == 0) {
1670                         error_print(GOB_WARN, a->line_no,
1671                                     "READABLE and "
1672                                     "WRITABLE argument flags are "
1673                                     "set automatically");
1674                         continue;
1675                 }
1676                 for(i = 0; argflags[i]; i++) {
1677                         if(strcmp(argflags[i], flag)==0)
1678                                 break;
1679                 }
1680                 g_string_sprintfa(flags, " | %s%s", argflags[i] ? "G_PARAM_" : "", flag);
1681         }
1682
1683         g_string_append (flags, ")");
1684
1685         s = g_strdup(a->name);
1686         gob_strup (s);
1687         if (!strcmp (a->gtktype, "ENUM"))
1688                 out_printf(out, "\tparam_spec = g_param_spec_enum (\"%s\", NULL, NULL,\n"
1689                            "\t\tG_TYPE_ENUM, 0,\n"
1690                            "\t\t%s);\n",
1691                            a->name, flags->str);
1692         if (!strcmp (a->gtktype, "FLAGS"))
1693                 out_printf(out, "\tparam_spec = g_param_spec_flags (\"%s\", NULL, NULL,\n"
1694                            "\t\tG_TYPE_FLAGS, 0,\n"
1695                            "\t\t%s);\n",
1696                            a->name, flags->str);
1697         else if (!strcmp (a->gtktype, "OBJECT"))
1698                 out_printf(out, "\tparam_spec = g_param_spec_object (\"%s\", NULL, NULL,\n"
1699                            "\t\tG_TYPE_OBJECT,\n"
1700                            "\t\t%s);\n",
1701                            a->name, flags->str);
1702         else if (!strcmp (a->gtktype, "STRING"))
1703                 out_printf(out, "\tparam_spec = g_param_spec_string (\"%s\", NULL, NULL,\n"
1704                            "\t\tNULL,\n"
1705                            "\t\t%s);\n",
1706                            a->name, flags->str);
1707         else if (!strcmp (a->gtktype, "INT"))
1708                 out_printf(out, "\tparam_spec = g_param_spec_int (\"%s\", NULL, NULL,\n"
1709                            "\t\tG_MININT, G_MAXINT,\n"
1710                            "\t\t0,\n"
1711                            "\t\t%s);\n",
1712                            a->name, flags->str);
1713         else if (!strcmp (a->gtktype, "UINT"))
1714                 out_printf(out, "\tparam_spec = g_param_spec_uint (\"%s\", NULL, NULL,\n"
1715                            "\t\t0, G_MAXUINT,\n"
1716                            "\t\t0,\n"
1717                            "\t\t%s);\n",
1718                            a->name, flags->str);
1719         else if (!strcmp (a->gtktype, "INT"))
1720                 out_printf(out, "\tparam_spec = g_param_spec_int (\"%s\", NULL, NULL,\n"
1721                            "\t\tG_MININT, G_MAXINT,\n"
1722                            "\t\t0,\n"
1723                            "\t\t%s);\n",
1724                            a->name, flags->str);
1725         else if (!strcmp (a->gtktype, "CHAR"))
1726                 out_printf(out, "\tparam_spec = g_param_spec_char (\"%s\", NULL, NULL,\n"
1727                            "\t\t-128, 127,\n"
1728                            "\t\t0,\n"
1729                            "\t\t%s);\n",
1730                            a->name, flags->str);
1731         else if (!strcmp (a->gtktype, "UCHAR"))
1732                 out_printf(out, "\tparam_spec = g_param_spec_uchar (\"%s\", NULL, NULL,\n"
1733                            "\t\t0, 0xFF,\n"
1734                            "\t\t0,\n"
1735                            "\t\t%s);\n",
1736                            a->name, flags->str);
1737         else if (!strcmp (a->gtktype, "BOOL") ||
1738                  !strcmp (a->gtktype, "BOOLEAN"))
1739                 out_printf(out, "\tparam_spec = g_param_spec_boolean (\"%s\", NULL, NULL,\n"
1740                            "\t\tFALSE,\n"
1741                            "\t\t%s);\n",
1742                            a->name, flags->str);
1743         else if (!strcmp (a->gtktype, "LONG"))
1744                 out_printf(out, "\tparam_spec = g_param_spec_long (\"%s\", NULL, NULL,\n"
1745                            "\t\tG_MINLONG, G_MAXLONG,\n"
1746                            "\t\t0,\n"
1747                            "\t\t%s);\n",
1748                            a->name, flags->str);
1749         else if (!strcmp (a->gtktype, "ULONG"))
1750                 out_printf(out, "\tparam_spec = g_param_spec_ulong (\"%s\", NULL, NULL,\n"
1751                            "\t\t0, G_MAXULONG,\n"
1752                            "\t\t0,\n"
1753                            "\t\t%s);\n",
1754                            a->name, flags->str);
1755         else if (!strcmp (a->gtktype, "INT64"))
1756                 out_printf(out, "\tparam_spec = g_param_spec_int64 (\"%s\", NULL, NULL,\n"
1757                            "\t\tG_MININT64, G_MAXINT64,\n"
1758                            "\t\t0,\n"
1759                            "\t\t%s);\n",
1760                            a->name, flags->str);
1761         else if (!strcmp (a->gtktype, "UINT64"))
1762                 out_printf(out, "\tparam_spec = g_param_spec_uint64 (\"%s\", NULL, NULL,\n"
1763                            "\t\t0, G_MAXUINT64,\n"
1764                            "\t\t0,\n"
1765                            "\t\t%s);\n",
1766                            a->name, flags->str);
1767         else if (!strcmp (a->gtktype, "FLOAT"))
1768                 out_printf(out, "\tparam_spec = g_param_spec_float (\"%s\", NULL, NULL,\n"
1769                            "\t\t-G_MAXFLOAT, G_MAXFLOAT,\n"
1770                            "\t\t0,\n"
1771                            "\t\t%s);\n",
1772                            a->name, flags->str);
1773         else if (!strcmp (a->gtktype, "DOUBLE"))
1774                 out_printf(out, "\tparam_spec = g_param_spec_double (\"%s\", NULL, NULL,\n"
1775                            "\t\t-G_MAXDOUBLE, G_MAXDOUBLE,\n"
1776                            "\t\t0,\n"
1777                            "\t\t%s);\n",
1778                            a->name, flags->str);
1779         else if (!strcmp (a->gtktype, "POINTER"))
1780                 out_printf(out, "\tparam_spec = g_param_spec_pointer (\"%s\", NULL, NULL,\n"
1781                            "\t\t%s);\n",
1782                            a->name, flags->str);
1783         else
1784                 error_printf (GOB_ERROR, a->line_no,
1785                               "%s type is not supported for arguments, try using properties",
1786                               a->gtktype);
1787
1788         out_printf(out, "\tg_object_class_install_property (g_object_class,\n"
1789                    "\t\tPROP_%s, param_spec);\n", s);
1790
1791
1792         g_free(s);
1793         g_string_free(flags, TRUE);
1794 }
1795
1796 #define value_for_print(str, alt) (str != NULL ? str : alt)
1797
1798 static void
1799 make_property (Property *p)
1800 {
1801         char *s;
1802
1803         if (p->get == NULL && p->set == NULL) {
1804                 error_print (GOB_ERROR, p->line_no,
1805                              "Property has no getter nor setter");
1806         }
1807
1808         if (p->override) {
1809                 if (p->flags != NULL)
1810                         error_print (GOB_WARN, p->line_no,
1811                                      "Overridden property, flags ignored");
1812                 if (p->nick != NULL)
1813                         error_print (GOB_WARN, p->line_no,
1814                                      "Overridden property, nick ignored");
1815                 if (p->blurb != NULL)
1816                         error_print (GOB_WARN, p->line_no,
1817                                      "Overridden property, blurb ignored");
1818                 if (p->minimum != NULL)
1819                         error_print (GOB_WARN, p->line_no,
1820                                      "Overridden property, minimum ignored");
1821                 if (p->maximum != NULL)
1822                         error_print (GOB_WARN, p->line_no,
1823                                      "Overridden property, maximum ignored");
1824                 if (p->default_value != NULL)
1825                         error_print (GOB_WARN, p->line_no,
1826                                      "Overridden property, default_value ignored");
1827
1828                 s = g_strdup (p->name);
1829                 gob_strup (s);
1830                 out_printf (out, "\tg_object_class_override_property (g_object_class,\n"
1831                             "\t\tPROP_%s,\n"
1832                             "\t\t\"%s\");\n", s, value_for_print (p->canonical_name, p->name) );
1833                 g_free (s);
1834         } else {
1835                 GString *flags;
1836                 GList *l;
1837                 char *argflags[] = {
1838                         "CONSTRUCT",
1839                         "CONSTRUCT_ONLY",
1840                         "LAX_VALIDATION",
1841                         "PRIVATE",
1842                         NULL
1843                 };
1844
1845                 flags = g_string_new ("(GParamFlags)(");
1846
1847                 if (p->get != NULL && p->set != NULL)
1848                         g_string_append (flags, "G_PARAM_READABLE | G_PARAM_WRITABLE");
1849                 else if (p->get != NULL)
1850                         g_string_append (flags, "G_PARAM_READABLE");
1851                 else
1852                         g_string_append (flags, "G_PARAM_WRITABLE");
1853
1854
1855                 for (l = p->flags; l != NULL; l = l->next) {
1856                         char *flag = l->data;
1857                         int i;
1858                         if(strcmp (flag, "READABLE") == 0 ||
1859                            strcmp (flag, "WRITABLE") == 0) {
1860                                 error_print(GOB_WARN, p->line_no,
1861                                             "READABLE and "
1862                                             "WRITABLE argument flags are "
1863                                             "set automatically");
1864                                 continue;
1865                         }
1866                         for(i = 0; argflags[i]; i++) {
1867                                 if(strcmp(argflags[i], flag)==0)
1868                                         break;
1869                         }
1870                         g_string_sprintfa(flags, " | %s%s", argflags[i] ? "G_PARAM_" : "", flag);
1871                 }
1872
1873                 g_string_append (flags, ")");
1874
1875                 if (strcmp (p->gtktype, "CHAR") == 0) {
1876                         out_printf (out, "\tparam_spec = g_param_spec_char\n"
1877                                     "\t\t(\"%s\" /* name */,\n"
1878                                     "\t\t %s /* nick */,\n"
1879                                     "\t\t %s /* blurb */,\n"
1880                                     "\t\t %s /* minimum */,\n"
1881                                     "\t\t %s /* maximum */,\n"
1882                                     "\t\t %s /* default_value */,\n"
1883                                     "\t\t %s);\n",
1884                                     value_for_print (p->canonical_name, p->name),
1885                                     value_for_print (p->nick, "NULL"),
1886                                     value_for_print (p->blurb, "NULL"),
1887                                     value_for_print (p->minimum, "-128"),
1888                                     value_for_print (p->maximum, "127"),
1889                                     value_for_print (p->default_value, "0"),
1890                                     flags->str);
1891                 } else if (strcmp (p->gtktype, "UCHAR") == 0) {
1892                         out_printf (out, "\tparam_spec = g_param_spec_uchar\n"
1893                                     "\t\t(\"%s\" /* name */,\n"
1894                                     "\t\t %s /* nick */,\n"
1895                                     "\t\t %s /* blurb */,\n"
1896                                     "\t\t %s /* minimum */,\n"
1897                                     "\t\t %s /* maximum */,\n"
1898                                     "\t\t %s /* default_value */,\n"
1899                                     "\t\t %s);\n",
1900                                     value_for_print (p->canonical_name, p->name),
1901                                     value_for_print (p->nick, "NULL"),
1902                                     value_for_print (p->blurb, "NULL"),
1903                                     value_for_print (p->minimum, "0"),
1904                                     value_for_print (p->maximum, "0xFF"),
1905                                     value_for_print (p->default_value, "0"),
1906                                     flags->str);
1907                 } else if (strcmp (p->gtktype, "BOOLEAN") == 0) {
1908                         out_printf (out, "\tparam_spec = g_param_spec_boolean\n"
1909                                     "\t\t(\"%s\" /* name */,\n"
1910                                     "\t\t %s /* nick */,\n"
1911                                     "\t\t %s /* blurb */,\n"
1912                                     "\t\t %s /* default_value */,\n"
1913                                     "\t\t %s);\n",
1914                                     value_for_print (p->canonical_name, p->name),
1915                                     value_for_print (p->nick, "NULL"),
1916                                     value_for_print (p->blurb, "NULL"),
1917                                     value_for_print (p->default_value, "FALSE"),
1918                                     flags->str);
1919                 } else if (strcmp (p->gtktype, "INT") == 0) {
1920                         out_printf (out, "\tparam_spec = g_param_spec_int\n"
1921                                     "\t\t(\"%s\" /* name */,\n"
1922                                     "\t\t %s /* nick */,\n"
1923                                     "\t\t %s /* blurb */,\n"
1924                                     "\t\t %s /* minimum */,\n"
1925                                     "\t\t %s /* maximum */,\n"
1926                                     "\t\t %s /* default_value */,\n"
1927                                     "\t\t %s);\n",
1928                                     value_for_print (p->canonical_name, p->name),
1929                                     value_for_print (p->nick, "NULL"),
1930                                     value_for_print (p->blurb, "NULL"),
1931                                     value_for_print (p->minimum, "G_MININT"),
1932                                     value_for_print (p->maximum, "G_MAXINT"),
1933                                     value_for_print (p->default_value, "0"),
1934                                     flags->str);
1935                 } else if (strcmp (p->gtktype, "UINT") == 0) {
1936                         out_printf (out, "\tparam_spec = g_param_spec_uint\n"
1937                                     "\t\t(\"%s\" /* name */,\n"
1938                                     "\t\t %s /* nick */,\n"
1939                                     "\t\t %s /* blurb */,\n"
1940                                     "\t\t %s /* minimum */,\n"
1941                                     "\t\t %s /* maximum */,\n"
1942                                     "\t\t %s /* default_value */,\n"
1943                                     "\t\t %s);\n",
1944                                     value_for_print (p->canonical_name, p->name),
1945                                     value_for_print (p->nick, "NULL"),
1946                                     value_for_print (p->blurb, "NULL"),
1947                                     value_for_print (p->minimum, "0"),
1948                                     value_for_print (p->maximum, "G_MAXUINT"),
1949                                     value_for_print (p->default_value, "0"),
1950                                     flags->str);
1951                 } else if (strcmp (p->gtktype, "LONG") == 0) {
1952                         out_printf (out, "\tparam_spec = g_param_spec_long\n"
1953                                     "\t\t(\"%s\" /* name */,\n"
1954                                     "\t\t %s /* nick */,\n"
1955                                     "\t\t %s /* blurb */,\n"
1956                                     "\t\t %s /* minimum */,\n"
1957                                     "\t\t %s /* maximum */,\n"
1958                                     "\t\t %s /* default_value */,\n"
1959                                     "\t\t %s);\n",
1960                                     value_for_print (p->canonical_name, p->name),
1961                                     value_for_print (p->nick, "NULL"),
1962                                     value_for_print (p->blurb, "NULL"),
1963                                     value_for_print (p->minimum, "G_MINLONG"),
1964                                     value_for_print (p->maximum, "G_MAXLONG"),
1965                                     value_for_print (p->default_value, "0"),
1966                                     flags->str);
1967                 } else if (strcmp (p->gtktype, "ULONG") == 0) {
1968                         out_printf (out, "\tparam_spec = g_param_spec_ulong\n"
1969                                     "\t\t(\"%s\" /* name */,\n"
1970                                     "\t\t %s /* nick */,\n"
1971                                     "\t\t %s /* blurb */,\n"
1972                                     "\t\t %s /* minimum */,\n"
1973                                     "\t\t %s /* maximum */,\n"
1974                                     "\t\t %s /* default_value */,\n"
1975                                     "\t\t %s);\n",
1976                                     value_for_print (p->canonical_name, p->name),
1977                                     value_for_print (p->nick, "NULL"),
1978                                     value_for_print (p->blurb, "NULL"),
1979                                     value_for_print (p->minimum, "0"),
1980                                     value_for_print (p->maximum, "G_MAXULONG"),
1981                                     value_for_print (p->default_value, "0"),
1982                                     flags->str);
1983                 } else if (strcmp (p->gtktype, "INT64") == 0) {
1984                         out_printf (out, "\tparam_spec = g_param_spec_int64\n"
1985                                     "\t\t(\"%s\" /* name */,\n"
1986                                     "\t\t %s /* nick */,\n"
1987                                     "\t\t %s /* blurb */,\n"
1988                                     "\t\t %s /* minimum */,\n"
1989                                     "\t\t %s /* maximum */,\n"
1990                                     "\t\t %s /* default_value */,\n"
1991                                     "\t\t %s);\n",
1992                                     value_for_print (p->canonical_name, p->name),
1993                                     value_for_print (p->nick, "NULL"),
1994                                     value_for_print (p->blurb, "NULL"),
1995                                     value_for_print (p->minimum, "G_MININT64"),
1996                                     value_for_print (p->maximum, "G_MAXINT64"),
1997                                     value_for_print (p->default_value, "0"),
1998                                     flags->str);
1999                 } else if (strcmp (p->gtktype, "UINT64") == 0) {
2000                         out_printf (out, "\tparam_spec = g_param_spec_uint64\n"
2001                                     "\t\t(\"%s\" /* name */,\n"
2002                                     "\t\t %s /* nick */,\n"
2003                                     "\t\t %s /* blurb */,\n"
2004                                     "\t\t %s /* minimum */,\n"
2005                                     "\t\t %s /* maximum */,\n"
2006                                     "\t\t %s /* default_value */,\n"
2007                                     "\t\t %s);\n",
2008                                     value_for_print (p->canonical_name, p->name),
2009                                     value_for_print (p->nick, "NULL"),
2010                                     value_for_print (p->blurb, "NULL"),
2011                                     value_for_print (p->minimum, "0"),
2012                                     value_for_print (p->maximum, "G_MAXUINT64"),
2013                                     value_for_print (p->default_value, "0"),
2014                                     flags->str);
2015                 } else if (strcmp (p->gtktype, "UNICHAR") == 0) {
2016                         out_printf (out, "\tparam_spec = g_param_spec_unichar\n"
2017                                     "\t\t(\"%s\" /* name */,\n"
2018                                     "\t\t %s /* nick */,\n"
2019                                     "\t\t %s /* blurb */,\n"
2020                                     "\t\t %s /* default_value */,\n"
2021                                     "\t\t %s);\n",
2022                                     value_for_print (p->canonical_name, p->name),
2023                                     value_for_print (p->nick, "NULL"),
2024                                     value_for_print (p->blurb, "NULL"),
2025                                     value_for_print (p->default_value, "0"),
2026                                     flags->str);
2027                 } else if (strcmp (p->gtktype, "ENUM") == 0) {
2028                         char *type = make_me_type (p->extra_gtktype,
2029                                                    "G_TYPE_ENUM");
2030                         out_printf (out, "\tparam_spec = g_param_spec_enum\n"
2031                                     "\t\t(\"%s\" /* name */,\n"
2032                                     "\t\t %s /* nick */,\n"
2033                                     "\t\t %s /* blurb */,\n"
2034                                     "\t\t %s /* enum_type */,\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                                     type,
2041                                     value_for_print (p->default_value, "0"),
2042                                     flags->str);
2043                         g_free (type);
2044                 } else if (strcmp (p->gtktype, "FLAGS") == 0) {
2045                         char *type = make_me_type (p->extra_gtktype,
2046                                                    "G_TYPE_FLAGS");
2047                         out_printf (out, "\tparam_spec = g_param_spec_flags\n"
2048                                     "\t\t(\"%s\" /* name */,\n"
2049                                     "\t\t %s /* nick */,\n"
2050                                     "\t\t %s /* blurb */,\n"
2051                                     "\t\t %s /* flags_type */,\n"
2052                                     "\t\t %s /* default_value */,\n"
2053                                     "\t\t %s);\n",
2054                                     value_for_print (p->canonical_name, p->name),
2055                                     value_for_print (p->nick, "NULL"),
2056                                     value_for_print (p->blurb, "NULL"),
2057                                     type,
2058                                     value_for_print (p->default_value, "0"),
2059                                     flags->str);
2060                         g_free (type);
2061                 } else if (strcmp (p->gtktype, "FLOAT") == 0) {
2062                         out_printf (out, "\tparam_spec = g_param_spec_float\n"
2063                                     "\t\t(\"%s\" /* name */,\n"
2064                                     "\t\t %s /* nick */,\n"
2065                                     "\t\t %s /* blurb */,\n"
2066                                     "\t\t %s /* minimum */,\n"
2067                                     "\t\t %s /* maximum */,\n"
2068                                     "\t\t %s /* default_value */,\n"
2069                                     "\t\t %s);\n",
2070                                     value_for_print (p->canonical_name, p->name),
2071                                     value_for_print (p->nick, "NULL"),
2072                                     value_for_print (p->blurb, "NULL"),
2073                                     value_for_print (p->minimum, "-G_MAXFLOAT"),
2074                                     value_for_print (p->maximum, "G_MAXFLOAT"),
2075                                     value_for_print (p->default_value, "0.0"),
2076                                     flags->str);
2077                 } else if (strcmp (p->gtktype, "DOUBLE") == 0) {
2078                         out_printf (out, "\tparam_spec = g_param_spec_double\n"
2079                                     "\t\t(\"%s\" /* name */,\n"
2080                                     "\t\t %s /* nick */,\n"
2081                                     "\t\t %s /* blurb */,\n"
2082                                     "\t\t %s /* minimum */,\n"
2083                                     "\t\t %s /* maximum */,\n"
2084                                     "\t\t %s /* default_value */,\n"
2085                                     "\t\t %s);\n",
2086                                     value_for_print (p->canonical_name, p->name),
2087                                     value_for_print (p->nick, "NULL"),
2088                                     value_for_print (p->blurb, "NULL"),
2089                                     value_for_print (p->minimum, "-G_MAXDOUBLE"),
2090                                     value_for_print (p->maximum, "G_MAXDOUBLE"),
2091                                     value_for_print (p->default_value, "0.0"),
2092                                     flags->str);
2093                 } else if (strcmp (p->gtktype, "STRING") == 0) {
2094                         out_printf (out, "\tparam_spec = g_param_spec_string\n"
2095                                     "\t\t(\"%s\" /* name */,\n"
2096                                     "\t\t %s /* nick */,\n"
2097                                     "\t\t %s /* blurb */,\n"
2098                                     "\t\t %s /* default_value */,\n"
2099                                     "\t\t %s);\n",
2100                                     value_for_print (p->canonical_name, p->name),
2101                                     value_for_print (p->nick, "NULL"),
2102                                     value_for_print (p->blurb, "NULL"),
2103                                     value_for_print (p->default_value, "NULL"),
2104                                     flags->str);
2105                 } else if (strcmp (p->gtktype, "PARAM") == 0) {
2106                         char *type = make_me_type (p->extra_gtktype,
2107                                                    "G_TYPE_PARAM");
2108                         out_printf (out, "\tparam_spec = g_param_spec_param\n"
2109                                     "\t\t(\"%s\" /* name */,\n"
2110                                     "\t\t %s /* nick */,\n"
2111                                     "\t\t %s /* blurb */,\n"
2112                                     "\t\t %s /* param_type */,\n"
2113                                     "\t\t %s);\n",
2114                                     value_for_print (p->canonical_name, p->name),
2115                                     value_for_print (p->nick, "NULL"),
2116                                     value_for_print (p->blurb, "NULL"),
2117                                     type,
2118                                     flags->str);
2119                         g_free (type);
2120                 } else if (strcmp (p->gtktype, "BOXED") == 0) {
2121                         char *type = make_me_type (p->extra_gtktype,
2122                                                    "G_TYPE_BOXED");
2123                         out_printf (out, "\tparam_spec = g_param_spec_boxed\n"
2124                                     "\t\t(\"%s\" /* name */,\n"
2125                                     "\t\t %s /* nick */,\n"
2126                                     "\t\t %s /* blurb */,\n"
2127                                     "\t\t %s /* boxed_type */,\n"
2128                                     "\t\t %s);\n",
2129                                     value_for_print (p->canonical_name, p->name),
2130                                     value_for_print (p->nick, "NULL"),
2131                                     value_for_print (p->blurb, "NULL"),
2132                                     type,
2133                                     flags->str);
2134                         g_free (type);
2135                 } else if (strcmp (p->gtktype, "POINTER") == 0) {
2136                         out_printf (out, "\tparam_spec = g_param_spec_pointer\n"
2137                                     "\t\t(\"%s\" /* name */,\n"
2138                                     "\t\t %s /* nick */,\n"
2139                                     "\t\t %s /* blurb */,\n"
2140                                     "\t\t %s);\n",
2141                                     value_for_print (p->canonical_name, p->name),
2142                                     value_for_print (p->nick, "NULL"),
2143                                     value_for_print (p->blurb, "NULL"),
2144                                     flags->str);
2145                 /* FIXME: VALUE_ARRAY */
2146                 } else if (strcmp (p->gtktype, "CLOSURE") == 0) {
2147                         out_printf (out, "\tparam_spec = g_param_spec_pointer\n"
2148                                     "\t\t(\"%s\" /* name */,\n"
2149                                     "\t\t %s /* nick */,\n"
2150                                     "\t\t %s /* blurb */,\n"
2151                                     "\t\t %s);\n",
2152                                     value_for_print (p->canonical_name, p->name),
2153                                     value_for_print (p->nick, "NULL"),
2154                                     value_for_print (p->blurb, "NULL"),
2155                                     flags->str);
2156                 } else if (strcmp (p->gtktype, "OBJECT") == 0) {
2157                         char *type = make_me_type (p->extra_gtktype,
2158                                                    "G_TYPE_BOXED");
2159                         out_printf (out, "\tparam_spec = g_param_spec_object\n"
2160                                     "\t\t(\"%s\" /* name */,\n"
2161                                     "\t\t %s /* nick */,\n"
2162                                     "\t\t %s /* blurb */,\n"
2163                                     "\t\t %s /* object_type */,\n"
2164                                     "\t\t %s);\n",
2165                                     value_for_print (p->canonical_name, p->name),
2166                                     value_for_print (p->nick, "NULL"),
2167                                     value_for_print (p->blurb, "NULL"),
2168                                     type,
2169                                     flags->str);
2170                         g_free (type);
2171                 } else {
2172                         error_printf (GOB_ERROR, p->line_no,
2173                                       "%s type is not supported by properties",
2174                                       p->gtktype);
2175                 }
2176
2177                 s = g_strdup (p->name);
2178                 gob_strup (s);
2179                 out_printf (out, "\tg_object_class_install_property (g_object_class,\n"
2180                             "\t\tPROP_%s,\n"
2181                             "\t\tparam_spec);\n", s);
2182                 g_free (s);
2183
2184                 g_string_free (flags, TRUE);
2185         }
2186 }
2187
2188 static void
2189 make_arguments(Class *c)
2190 {
2191         GList *li;
2192         if (get_properties > 0)
2193                 out_printf(out, "\tg_object_class->get_property = ___object_get_property;\n");
2194         if (set_properties > 0)
2195                 out_printf(out, "\tg_object_class->set_property = ___object_set_property;\n");
2196         out_printf (out, "    {\n");
2197         for (li = c->nodes; li != NULL; li = li->next) {
2198                 Node *n = li->data;
2199                 if ((n->type == PROPERTY_NODE && ! ((Property *) n)->override)
2200                     || n->type == ARGUMENT_NODE) {
2201                         out_printf(out, "\tGParamSpec   *param_spec;\n\n");
2202                         break;
2203                 }
2204         }
2205
2206         for (li = c->nodes; li != NULL; li = li->next) {
2207                 Node *n = li->data;
2208                 if (n->type == PROPERTY_NODE)
2209                         make_property ((Property *)n);
2210                 else if (n->type == ARGUMENT_NODE)
2211                         make_argument ((Argument *)n);
2212         }
2213         out_printf(out, "    }\n");
2214 }
2215
2216 static void
2217 print_initializer(Method *m, Variable *v)
2218 {
2219         char *root;
2220         
2221         if(v->glade_widget)
2222                 return;
2223
2224         if(v->initializer == NULL)
2225                 return;
2226
2227         if(v->scope == PRIVATE_SCOPE)
2228                 root = g_strconcat(((FuncArg *)m->args->data)->name,
2229                                    "->_priv", NULL);
2230         else
2231                 root = g_strdup(((FuncArg *)m->args->data)->name);
2232
2233         if(v->initializer_line > 0)
2234                 out_addline_infile(out, v->initializer_line);
2235
2236         if (v->initializer_simple)
2237                 out_printf(out, "\t%s->%s = %s;\n",
2238                    root, v->id, v->initializer);
2239         else if (strcmp(v->id, "_glade_xml") == 0)
2240                 /* This is OK, this v->initializer string is set internally
2241                    and it will eat exactly one string! */
2242                 out_printf(out,v->initializer, ((FuncArg *)m->args->data)->name);
2243         else
2244                 out_printf(out, "%s", v->initializer);
2245
2246         if(v->initializer_line > 0)
2247                 out_addline_outfile(out);
2248
2249         g_free(root);
2250 }
2251
2252 static void
2253 print_glade_widget(Method *m, Variable *v)
2254 {
2255         char *root;
2256   char *cast;
2257         
2258         if(!v->glade_widget)
2259                 return;
2260
2261         if(v->scope == PRIVATE_SCOPE)
2262                 root = g_strconcat(((FuncArg *)m->args->data)->name,
2263                                    "->_priv", NULL);
2264         else
2265                 root = g_strdup(((FuncArg *)m->args->data)->name);
2266
2267         cast = get_type(v->vtype, FALSE);
2268         out_printf(out, "\t%s->%s = (%s)glade_xml_get_widget(%s->_glade_xml, \"%s\");\n",
2269                    root, v->id, cast, root, v->id);
2270
2271         g_free(root);
2272 }
2273         
2274 static void
2275 print_destructor (Variable *v)
2276 {
2277         const char *root;
2278
2279         if(v->destructor == NULL)
2280                 return;
2281
2282         if(v->scope == PRIVATE_SCOPE)
2283                 root = "self->_priv";
2284         else
2285                 root = "self";
2286
2287         if(v->destructor_simple) {
2288                 if(v->destructor_line > 0)
2289                         out_addline_infile(out, v->destructor_line);
2290
2291                 if (for_cpp) {
2292                         out_printf(out, "\tif(%s->%s) { "
2293                                    "(reinterpret_cast<void (*)(void *)>(%s)) ((gpointer)%s->%s); "
2294                                    "%s->%s = NULL; }\n",
2295                                    root, v->id, v->destructor, root, v->id,
2296                                    root, v->id);
2297                 } else {
2298                         out_printf(out, "\tif(%s->%s) { "
2299                                    "%s ((gpointer) %s->%s); "
2300                                    "%s->%s = NULL; }\n",
2301                                    root, v->id, v->destructor, root, v->id,
2302                                    root, v->id);
2303                 }
2304
2305                 if(v->destructor_line > 0)
2306                         out_addline_outfile(out);
2307         } else {
2308                 out_printf(out, "#define %s (%s->%s)\n", v->id, root, v->id);
2309                 out_printf(out, "#define VAR %s\n", v->id);
2310                 out_printf(out, "\t{\n");
2311                 if(v->destructor_line > 0)
2312                         out_addline_infile(out, v->destructor_line);
2313
2314                 out_printf(out, "\t%s}\n", v->destructor);
2315
2316                 if(v->destructor_line > 0)
2317                         out_addline_outfile(out);
2318                 out_printf(out, "\tmemset(&(%s), 0, sizeof(%s));\n",
2319                            v->id, v->id);
2320                 out_printf(out, "#undef VAR\n");
2321                 out_printf(out, "#undef %s\n", v->id);
2322         }
2323 }
2324
2325 static void
2326 add_constructor (Class *c)
2327 {
2328         out_printf(out, "\nstatic GObject *\n"
2329                    "___constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties)\n"
2330                    "{\n");
2331         out_printf(out,
2332                    "#define __GOB_FUNCTION__ \"%s::constructor\"\n",
2333                    c->otype);
2334
2335         out_printf(out, "\tGObject *obj_self;\n");
2336         out_printf(out, "\t%s *self;\n", typebase);
2337
2338         out_printf(out, "\tobj_self = G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_properties, construct_properties);\n");
2339         out_printf(out, "\tself = %s (obj_self);\n", macrobase);
2340
2341         if (user_constructor->line_no > 0)
2342                 out_addline_infile (out, user_constructor->line_no);
2343         out_printf (out, "\t%s_constructor (self);\n", funcbase);
2344         if (user_constructor->line_no > 0)
2345                 out_addline_outfile (out);
2346
2347         out_printf(out, "\treturn obj_self;\n");
2348         out_printf(out, "}\n"
2349                    "#undef __GOB_FUNCTION__\n\n");
2350 }
2351
2352 static void
2353 print_unreftors (Class *c)
2354 {
2355         GList *li;
2356         for(li = ((Class *)class)->nodes;
2357             li != NULL;
2358             li = li->next) {
2359                 Node *n = li->data;
2360                 Variable *v = (Variable *)n;
2361                 if (n->type == VARIABLE_NODE &&
2362                     v->scope != CLASS_SCOPE &&
2363                     v->destructor_unref)
2364                         print_destructor (v);
2365         }
2366 }
2367
2368 static void
2369 add_dispose (Class *c)
2370 {
2371         out_printf(out, "\nstatic void\n"
2372                    "___dispose (GObject *obj_self)\n"
2373                    "{\n");
2374         out_printf(out,
2375                    "#define __GOB_FUNCTION__ \"%s::dispose\"\n",
2376                    c->otype);
2377
2378         if (unreftors > 0 || user_dispose_method != NULL) {
2379                 out_printf (out, "\t%s *self%s = %s (obj_self);\n",
2380                             typebase,
2381                             ! no_gnu ? " G_GNUC_UNUSED" : "",
2382                             macrobase);
2383         }
2384
2385         if (dispose_handler != NULL) {
2386                 if (unreftors > 0) {
2387                         print_unreftors (c);
2388                 }
2389
2390                 /* so we get possible bad argument warning */
2391                 if (dispose_handler->line_no > 0)
2392                         out_addline_infile (out, dispose_handler->line_no);
2393                 out_printf (out, "\t___%x_%s_dispose(obj_self);\n",
2394                             (guint)dispose_handler->unique_id, funcbase);
2395                 if (dispose_handler->line_no > 0)
2396                         out_addline_outfile (out);
2397         } else {
2398                 if (user_dispose_method != NULL) {
2399                         if (user_dispose_method->line_no > 0)
2400                                 out_addline_infile (out, user_dispose_method->line_no);
2401                         out_printf (out, "\t%s_dispose (self);\n", funcbase);
2402                         if (user_dispose_method->line_no > 0)
2403                                 out_addline_outfile (out);
2404                 }
2405
2406                 if (unreftors > 0) {
2407                         print_unreftors (c);
2408                 }
2409
2410                 out_printf (out,
2411                             "\tif (G_OBJECT_CLASS (parent_class)->dispose) \\\n"
2412                             "\t\t(* G_OBJECT_CLASS (parent_class)->dispose) (obj_self);\n");
2413         }
2414
2415         out_printf(out, "}\n"
2416                    "#undef __GOB_FUNCTION__\n\n");
2417 }
2418
2419 static void
2420 print_destructors (Class *c)
2421 {
2422         GList *li;
2423         for (li = ((Class *)class)->nodes;
2424              li != NULL;
2425              li = li->next) {
2426                 Node *n = li->data;
2427                 Variable *v = (Variable *)n;
2428                 if (n->type == VARIABLE_NODE &&
2429                     v->scope != CLASS_SCOPE &&
2430                     ! v->destructor_unref)
2431                         print_destructor (v);
2432         }
2433 }
2434
2435 static void
2436 add_finalize (Class *c)
2437 {
2438         out_printf(out,
2439                    "\nstatic void\n"
2440                    "___finalize(GObject *obj_self)\n"
2441                    "{\n");
2442         out_printf(out,
2443                    "#define __GOB_FUNCTION__ \"%s::finalize\"\n",
2444                    c->otype);
2445
2446         if (privates > 0 ||
2447             destructors > 0 ||
2448             user_finalize_method != NULL) {
2449                 const char *unused = "";
2450                 if ( ! no_gnu)
2451                         unused = " G_GNUC_UNUSED";
2452                 out_printf(out, "\t%s *self%s = %s (obj_self);\n",
2453                            typebase, unused, macrobase);
2454         }
2455         if (privates > 0) {
2456                 const char *unused = "";
2457                 if ( ! no_gnu)
2458                         unused = " G_GNUC_UNUSED";
2459                 out_printf(out, "\tgpointer priv%s = self->_priv;\n",
2460                            unused);
2461         }
2462
2463         if(finalize_handler) {
2464                 if (destructors > 0) {
2465                         print_destructors (c);
2466                 }
2467
2468                 /* so we get possible bad argument warning */
2469                 if(finalize_handler->line_no > 0)
2470                         out_addline_infile(out, finalize_handler->line_no);
2471                 out_printf(out, "\t___%x_%s_finalize(obj_self);\n",
2472                            (guint)finalize_handler->unique_id, funcbase);
2473                 if(finalize_handler->line_no > 0)
2474                         out_addline_outfile(out);
2475         } else {
2476                 if (user_finalize_method != NULL) {
2477                         if (user_finalize_method->line_no > 0)
2478                                 out_addline_infile (out, user_finalize_method->line_no);
2479                         out_printf (out, "\t%s_finalize (self);\n", funcbase);
2480                         if (user_finalize_method->line_no > 0)
2481                                 out_addline_outfile (out);
2482                 }
2483
2484                 if (destructors > 0) {
2485                         print_destructors (c);
2486                 }
2487
2488                 out_printf(out,
2489                            "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
2490                            "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n");
2491         }
2492
2493         out_printf(out, "}\n"
2494                    "#undef __GOB_FUNCTION__\n\n");
2495 }
2496
2497 static void
2498 make_bonobo_object_epv (Class *c, const char *classname)
2499 {
2500         GList *li;
2501         gboolean added_line = FALSE;
2502
2503         for (li = c->nodes; li != NULL; li = li->next) {
2504                 Node *n = li->data;
2505                 Method *m = (Method *)n;
2506                 if(n->type != METHOD_NODE ||
2507                    m->method == OVERRIDE_METHOD)
2508                         continue;
2509
2510                 if (m->bonobo_object_func) {
2511                         if(m->line_no > 0) {
2512                                 out_addline_infile(out, m->line_no);
2513                                 added_line = TRUE;
2514                         } else if (m->line_no == 0 &&
2515                                    added_line) {
2516                                 out_addline_outfile(out);
2517                                 added_line = FALSE;
2518                         }
2519                         out_printf (out, "\t%s->_epv.%s = self_%s;\n",
2520                                     classname, m->id, m->id);
2521                 }
2522         }
2523         if (added_line)
2524                 out_addline_outfile(out);
2525 }
2526
2527 static void
2528 add_inits(Class *c)
2529 {
2530         const char *unused = "";
2531         GList *li;
2532
2533         if ( ! no_gnu)
2534                 unused = " G_GNUC_UNUSED";
2535
2536         for(li=c->nodes;li;li=g_list_next(li)) {
2537                 Node *n = li->data;
2538                 Method *m;
2539
2540                 if(n->type != METHOD_NODE)
2541                         continue;
2542                 m = (Method *)n;
2543                 if(m->method == INIT_METHOD) {
2544                         if(m->line_no > 0)
2545                                 out_addline_infile(out, m->line_no);
2546                         print_method(out, "static ", "\n", "", " ", "", "\n",
2547                                      m, FALSE, FALSE, FALSE, TRUE, TRUE,
2548                                      FALSE);
2549                         out_printf(out, "{\n");
2550                         if(m->line_no > 0)
2551                                 out_addline_outfile(out);
2552                         out_printf(out,
2553                                    "#define __GOB_FUNCTION__ \"%s::init\"\n",
2554                                    c->otype);
2555                         if (privates > 0) {
2556                                 out_printf(out, "\t%s->_priv = "
2557                                                 "G_TYPE_INSTANCE_GET_PRIVATE(%s,%s,%sPrivate);\n",
2558                                                 ((FuncArg *)m->args->data)->name,
2559                                                 ((FuncArg *)m->args->data)->name,
2560                                                 macrotype,
2561                                                 typebase);
2562                         } else if(always_private_struct) {
2563                                 out_printf(out, "\t%s->_priv = NULL;\n",
2564                                            ((FuncArg *)m->args->data)->name);
2565                         }
2566                         if(initializers > 0) {
2567                                 GList *li;
2568                                 for(li = ((Class *)class)->nodes;
2569                                     li != NULL;
2570                                     li = li->next) {
2571                                         Node *n = li->data;
2572                                         Variable *v = (Variable *)n;
2573                                         if(n->type != VARIABLE_NODE ||
2574                                            v->scope == CLASS_SCOPE)
2575                                                 continue;
2576                                         print_initializer(m, v);
2577                                 }
2578                         }
2579                         if(glade_widgets > 0) {
2580                                 GList *li;
2581                                 for(li = ((Class *)class)->nodes;
2582                                     li != NULL;
2583                                     li = li->next) {
2584                                         Node *n = li->data;
2585                                         Variable *v = (Variable *)n;
2586                                         if(n->type != VARIABLE_NODE ||
2587                                            v->scope == CLASS_SCOPE)
2588                                                 continue;
2589                                         print_glade_widget(m, v);
2590                                 }
2591                         }
2592                 } else if(m->method == CLASS_INIT_METHOD) {
2593                         gboolean did_base_obj = FALSE;
2594
2595                         if(m->line_no > 0)
2596                                 out_addline_infile(out, m->line_no);
2597                         print_method(out, "static ", "\n", "", " ", "", "\n",
2598                                      m, FALSE, FALSE, FALSE, TRUE, TRUE,
2599                                      FALSE);
2600                         out_printf(out, "{\n");
2601                         if(m->line_no > 0)
2602                                 out_addline_outfile(out);
2603                         out_printf(out,
2604                                    "#define __GOB_FUNCTION__ \"%s::class_init\"\n",
2605                                    c->otype);
2606                         if (set_properties > 0 ||
2607                             get_properties > 0 ||
2608                             signals > 0 ||
2609                             need_constructor ||
2610                             need_dispose ||
2611                             need_finalize) {
2612                                 out_printf(out,
2613                                            "\tGObjectClass *"
2614                                            "g_object_class%s = "
2615                                            "(GObjectClass*) %s;\n",
2616                                            unused,
2617                                            ((FuncArg *)m->args->data)->name);
2618                                 did_base_obj = TRUE;
2619                         }
2620
2621                         if (overrides > 0)
2622                                 add_overrides (c,
2623                                                ((FuncArg *)m->args->data)->name,
2624                                                did_base_obj);
2625
2626                         if (privates > 0)
2627                                 out_printf (out,
2628                                             "\n\tg_type_class_add_private(%s,sizeof(%sPrivate));\n",
2629                                             ((FuncArg *)m->args->data)->name,
2630                                             typebase);
2631
2632                         if (initializers > 0) {
2633                                 GList *li;
2634                                 for(li = ((Class *)class)->nodes;
2635                                     li != NULL;
2636                                     li = li->next) {
2637                                         Node *n = li->data;
2638                                         Variable *v = (Variable *)n;
2639                                         if(n->type == VARIABLE_NODE &&
2640                                            v->scope == CLASS_SCOPE)
2641                                                 print_initializer(m, v);
2642                                 }
2643                         }
2644                         
2645                         out_printf(out, "\n\tparent_class = ");
2646                         if(for_cpp)
2647                                 out_printf(out, "(%sClass *)", ptypebase);
2648                         out_printf(out, "g_type_class_ref (%s);\n",
2649                                    pmacrotype);
2650
2651                         if(signals > 0)
2652                                 add_signals(c);
2653
2654                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
2655
2656                         /* if there are no handlers for these things, we
2657                          * need to set them up here */
2658                         if(need_constructor)
2659                                 out_printf(out, "\tg_object_class->constructor "
2660                                            "= ___constructor;\n");
2661                         if(need_dispose && !dispose_handler)
2662                                 out_printf(out, "\tg_object_class->dispose "
2663                                            "= ___dispose;\n");
2664                         if(need_finalize && !finalize_handler)
2665                                 out_printf(out, "\tg_object_class->finalize = "
2666                                            "___finalize;\n");
2667                         
2668                         if(get_properties > 0 || set_properties > 0)
2669                                 make_arguments(c);
2670
2671                         if (c->bonobo_object_class != NULL) {
2672                                 make_bonobo_object_epv (c, ((FuncArg *)m->args->data)->name);
2673                         }
2674                 } else
2675                         continue;
2676
2677                 if(m->cbuf) {
2678                         out_printf(out, " {\n");
2679                         out_addline_infile(out, m->ccode_line);
2680                         out_printf(out, "%s\n", m->cbuf);
2681                         out_addline_outfile(out);
2682                         out_printf(out, " }\n");
2683                 }
2684                 out_printf(out, "}\n"
2685                            "#undef __GOB_FUNCTION__\n");
2686         }
2687 }
2688
2689 static void
2690 add_argument (Argument *a, gboolean is_set)
2691 {
2692         char *s;
2693         char *cbuf;
2694         char *the_type_lower;
2695         int line_no;
2696
2697         if(is_set) {
2698                 cbuf = a->set;
2699                 line_no = a->set_line;
2700         } else {
2701                 cbuf = a->get;
2702                 line_no = a->get_line;
2703         }
2704         if (cbuf == NULL)
2705                 return;
2706         s = g_strdup(a->name);
2707         gob_strup (s);
2708         out_printf(out, "\tcase PROP_%s:\n\t{", s);
2709
2710         the_type_lower = g_strdup (a->gtktype);
2711         gob_strdown (the_type_lower);
2712
2713         /* HACK because there is no g_value_set/get for unichar */
2714         if (strcmp (the_type_lower, "unichar") == 0) {
2715                 g_free (the_type_lower);
2716                 the_type_lower = g_strdup ("uint");
2717         }
2718
2719         if (is_set) {
2720                 char *cast;
2721                 const char *unused = "";
2722
2723                 if ( ! no_gnu && ! for_cpp /* g++ has a cow with this */) {
2724                         unused = " G_GNUC_UNUSED";
2725                 }
2726
2727                 if (a->atype != NULL &&
2728                     /* gcc -Wbad-function-cast is wanking stupid, moronic
2729                        and otherwise evil so we should just use a (gint)
2730                        or (guint) cast, not the specific type cast */
2731                     (for_cpp ||
2732                      (strcmp (a->gtktype, "ENUM") != 0 &&
2733                      strcmp (a->gtktype, "FLAGS") != 0)))
2734                         cast = get_type (a->atype, TRUE);
2735                 else
2736                         cast = g_strdup (get_cast (a->gtktype, FALSE));
2737
2738                 out_printf (out, "\t%s ARG%s = (%s) g_value_get_%s (VAL);\n",
2739                             cast, unused, cast, the_type_lower);
2740
2741                 g_free (cast);
2742         } else if ( ! is_set) {
2743                 char *cast;
2744
2745                 if (a->atype != NULL)
2746                         cast = get_type (a->atype, TRUE);
2747                 else
2748                         cast = g_strdup (get_cast (a->gtktype, FALSE));
2749                 out_printf (out, "\t%s ARG;\n"
2750                             "\tmemset (&ARG, 0, sizeof (%s));\n",
2751                             cast, cast);
2752
2753                 g_free(cast);
2754         }
2755         g_free (s);
2756         out_printf(out, "\t\t{\n");
2757         if (line_no > 0)
2758                 out_addline_infile (out, line_no);
2759         out_printf (out, "%s\n", cbuf);
2760         if (line_no > 0)
2761                 out_addline_outfile (out);
2762         out_printf (out, "\t\t}\n");
2763         if ( ! is_set) {
2764                 if (strcmp (a->gtktype, "OBJECT") == 0)
2765                         out_printf (out, "\t\tg_value_set_%s (VAL, G_OBJECT (ARG));\n",
2766                                     the_type_lower);
2767                 else
2768                         out_printf (out, "\t\t"
2769                                     "g_value_set_%s (VAL, ARG);\n",
2770                                     the_type_lower);
2771         }
2772         g_free (the_type_lower);
2773
2774         if (is_set &&
2775             (no_gnu || for_cpp /* g++ has a cow with G_GNUC_UNUSED */)) {
2776                 out_printf (out, "\t\tif (&ARG) break;\n");
2777         }
2778
2779         out_printf (out, "\t\tbreak;\n");
2780
2781         out_printf (out, "\t}\n");
2782 }
2783
2784 static void
2785 add_property (Property *p, gboolean is_set)
2786 {
2787         const char *cbuf;
2788         char *the_type_lower;
2789         char *name_upper;
2790         int line_no;
2791
2792         if (is_set) {
2793                 cbuf = p->set;
2794                 line_no = p->set_line;
2795         } else {
2796                 cbuf = p->get;
2797                 line_no = p->get_line;
2798         }
2799         if (cbuf == NULL)
2800                 return;
2801
2802         name_upper = g_strdup (p->name);
2803         gob_strup (name_upper);
2804         the_type_lower = g_strdup (p->gtktype);
2805         gob_strdown (the_type_lower);
2806
2807         out_printf (out, "\tcase PROP_%s:\n", name_upper);
2808
2809         out_printf(out, "\t\t{\n");
2810         if (line_no > 0)
2811                 out_addline_infile (out, line_no);
2812         out_printf (out, "%s\n", cbuf);
2813         if (line_no > 0)
2814                 out_addline_outfile (out);
2815         out_printf (out, "\t\t}\n");
2816
2817         g_free (name_upper);
2818         g_free (the_type_lower);
2819
2820         out_printf (out, "\t\tbreak;\n");
2821 }
2822
2823 static void
2824 add_getset_arg(Class *c, gboolean is_set)
2825 {
2826         GList *li;
2827         const char *unused = "";
2828         const char *hack_unused = "";
2829
2830         if ( ! no_gnu && ! for_cpp /* g++ has a cow with this */) {
2831                 unused = " G_GNUC_UNUSED";
2832         } else {
2833                 hack_unused = "if (&VAL || &pspec) break;\n\t\t";
2834         }
2835
2836         out_printf(out, "\nstatic void\n"
2837                    "___object_%s_property (GObject *object,\n"
2838                    "\tguint property_id,\n"
2839                    "\t%sGValue *VAL%s,\n"
2840                    "\tGParamSpec *pspec%s)\n"
2841                    "#define __GOB_FUNCTION__ \"%s::%s_property\"\n"
2842                    "{\n"
2843                    "\t%s *self%s;\n\n"
2844                    "\tself = %s (object);\n\n"
2845                    "\tswitch (property_id) {\n",
2846                    is_set ? "set" : "get",
2847                    is_set ? "const " : "",
2848                    unused,
2849                    unused,
2850                    c->otype,
2851                    is_set ? "set" : "get",
2852                    typebase,
2853                    unused,
2854                    macrobase);
2855
2856         for (li = c->nodes; li != NULL; li = li->next) {
2857                 Node *n = li->data;
2858                 if (n->type == PROPERTY_NODE)
2859                         add_property ((Property *)n, is_set);
2860                 else if (n->type == ARGUMENT_NODE)
2861                         add_argument ((Argument *)n, is_set);
2862         }
2863         out_printf (out, "\tdefault:\n"
2864                     "/* Apparently in g++ this is needed, glib is b0rk */\n"
2865                     "#ifndef __PRETTY_FUNCTION__\n"
2866                     "#  undef G_STRLOC\n"
2867                     "#  define G_STRLOC __FILE__ \":\" G_STRINGIFY (__LINE__)\n"
2868                     "#endif\n"
2869                     "\t\tG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);\n"
2870                     "\t\t%sbreak;\n\t}\n"
2871                     "}\n"
2872                     "#undef __GOB_FUNCTION__\n", hack_unused);
2873 }
2874
2875 static void
2876 print_checks (Method *m, FuncArg *fa)
2877 {
2878         GList *li;
2879         gboolean is_void;
2880         gboolean checked_null = FALSE;
2881         is_void = (strcmp(m->mtype->name, "void")==0 &&
2882                    m->mtype->pointer == NULL);
2883         
2884         for(li = fa->checks; li != NULL; li = li->next) {
2885                 Check *ch = li->data;
2886                 char *s;
2887                 /* point to the method prot in .gob for failed checks */
2888                 if(m->line_no > 0)
2889                         out_addline_infile(out, m->line_no);
2890                 if(is_void)
2891                         out_printf(out, "\tg_return_if_fail (");
2892                 else
2893                         out_printf(out, "\tg_return_val_if_fail (");
2894                 switch(ch->chtype) {
2895                 case NULL_CHECK:
2896                         out_printf(out, "%s != NULL", fa->name);
2897                         checked_null = TRUE;
2898                         break;
2899                 case TYPE_CHECK:
2900                         s = make_pre_macro(fa->atype->name, "IS");
2901                         if(checked_null)
2902                                 out_printf(out, "%s (%s)", s, fa->name);
2903                         else
2904                                 /* if not check null, null may be valid */
2905                                 out_printf(out, "!(%s) || %s (%s)", fa->name,
2906                                            s, fa->name);
2907                         g_free(s);
2908                         break;
2909                 case LT_CHECK:
2910                         out_printf(out, "%s < %s", fa->name, ch->number);
2911                         break;
2912                 case GT_CHECK:
2913                         out_printf(out, "%s > %s", fa->name, ch->number);
2914                         break;
2915                 case LE_CHECK:
2916                         out_printf(out, "%s <= %s", fa->name, ch->number);
2917                         break;
2918                 case GE_CHECK:
2919                         out_printf(out, "%s >= %s", fa->name, ch->number);
2920                         break;
2921                 case EQ_CHECK:
2922                         out_printf(out, "%s == %s", fa->name, ch->number);
2923                         break;
2924                 case NE_CHECK:
2925                         out_printf(out, "%s != %s", fa->name, ch->number);
2926                         break;
2927                 }
2928                 if(is_void)
2929                         out_printf(out, ");\n");
2930                 else {
2931                         out_printf(out, ", (");
2932                         print_type(out, m->mtype, TRUE);
2933                         out_printf(out, ")%s);\n",
2934                                 m->onerror?m->onerror:"0");
2935                 }
2936         }
2937 }
2938
2939 static void
2940 print_preconditions(Method *m)
2941 {
2942         GList *li;
2943         
2944         for(li=m->args;li;li=g_list_next(li)) {
2945                 FuncArg *fa = li->data;
2946                 if(fa->checks)
2947                         print_checks(m, fa);
2948         }
2949         if(m->line_no>0)
2950                 out_addline_outfile(out);
2951 }
2952
2953 static void
2954 print_method_body (Method *m, gboolean pre, gboolean unused_self)
2955 {
2956         out_printf(out, "{\n");
2957         if (m->line_no > 0)
2958                 out_addline_outfile(out);
2959         out_printf(out, "#define __GOB_FUNCTION__ \"%s::%s\"\n",
2960                    ((Class *)class)->otype,
2961                    m->id);
2962         if (pre)
2963                 print_preconditions(m);
2964
2965         if ( ! pre &&
2966              unused_self &&
2967             (no_gnu || for_cpp) &&
2968             m->args != NULL &&
2969             ((FuncArg *)(m->args->data))->name != NULL &&
2970             strcmp (((FuncArg *)(m->args->data))->name, "self") == 0) {
2971                 out_printf (out, "\tif (&self) { ; }\n");
2972         }
2973
2974         /* Note: the trailing }'s are on one line, this is so
2975            that we get the no return warning correctly and point to
2976            the correct line in the .gob file, yes this is slightly
2977            ugly in the .c file, but that is not supposed to be
2978            human readable anyway. */
2979         if(m->cbuf) {
2980                 out_printf(out, "{\n");
2981                 if(m->ccode_line>0)
2982                         out_addline_infile(out, m->ccode_line);
2983                 out_printf(out, "\t%s}", m->cbuf);
2984         }
2985
2986         /* Note, there is no \n between the last } and this } so that
2987          * errors/warnings reported on the end of the body get pointed to the
2988          * right line in the .gob source */
2989         out_printf(out, "}\n");
2990
2991         if(m->cbuf)
2992                 out_addline_outfile(out);
2993         out_printf(out, "#undef __GOB_FUNCTION__\n");
2994 }
2995
2996 static void
2997 put_signal_args (Method *m)
2998 {
2999         GList *li;
3000         GList *ali;
3001         int i;
3002
3003         if (m->args->next == NULL)
3004                 return;
3005
3006         for (ali = m->gtktypes->next, li = m->args->next, i = 1;
3007              li != NULL && ali != NULL;
3008              li = li->next, ali = ali->next, i++) {
3009                 FuncArg *fa = li->data;
3010                 char *str = ali->data;
3011                 char *cast = g_strdup (get_cast (str, FALSE));
3012                 /* FIXME: This code is so fucking ugly it hurts */
3013                 gboolean do_static = 
3014                         (strcmp  (str, "STRING") == 0 ||
3015                          strcmp  (str, "BOXED") == 0 ||
3016                          strncmp (str, "BOXED_", 6) == 0);
3017                 char *set_func;
3018                 char *t;
3019
3020                 if (cast == NULL) {
3021                         cast = get_type (fa->atype, TRUE);
3022                 }
3023                 /* we should have already proved before that
3024                    the we know all the types */
3025                 g_assert (cast != NULL);
3026
3027                 if (strncmp (str, "BOXED_", 6) == 0)
3028                         t = g_strdup (&(str[6]));
3029                 else
3030                         t = g_strconcat ("G_TYPE_", str, NULL);
3031
3032                 out_printf (out,
3033                             "\t___param_values[%d].g_type = 0;\n"
3034                             "\tg_value_init (&___param_values[%d], %s);\n",
3035                             i, i, t);
3036                 g_free (t);
3037
3038                 if (strcmp (str, "UNICHAR") == 0)
3039                         /* hack because glib is braindamaged */
3040                         set_func = g_strdup ("g_value_set_uint");
3041                 else if (strncmp (str, "BOXED_", 6) == 0)
3042                         set_func = g_strdup ("g_value_set_static_boxed");
3043                 else
3044                         set_func = g_strdup_printf ("g_value_set%s_%s",
3045                                                     do_static ? "_static" : "",
3046                                                     str);
3047                 gob_strdown (set_func);
3048
3049                 out_printf (out, "\t%s (&___param_values[%d], (%s) %s);\n\n",
3050                             set_func, i, cast, fa->name);
3051
3052                 g_free (set_func);
3053                 g_free (cast);
3054         }
3055 }
3056
3057 static void
3058 clear_signal_args (Method *m)
3059 {
3060         GList *li;
3061         int i;
3062
3063         out_printf (out, "\n\tg_value_unset (&___param_values[0]);\n");
3064
3065         if (m->args->next == NULL)
3066                 return;
3067
3068         for (li = m->args->next, i = 1;
3069              li != NULL;
3070              li = li->next, i++) {
3071                 out_printf (out,
3072                             "\tg_value_unset (&___param_values[%d]);\n", i);
3073         }
3074 }
3075
3076 static char *
3077 get_arg_names_for_macro (Method *m)
3078 {
3079         const char *sep;
3080         GList *li;
3081         GString *gs = g_string_new(NULL);
3082         sep = "";
3083         for(li=m->args;li;li=g_list_next(li)) {
3084                 FuncArg *arg = li->data;
3085                 g_string_sprintfa (gs, "%s___%s", sep, arg->name);
3086                 sep = ",";
3087         }
3088         return g_string_free (gs, FALSE);
3089 }
3090
3091 static gboolean method_is_void(Method *m)
3092 {
3093         return !strcmp(m->mtype->name, "void") && !m->mtype->pointer;
3094 }
3095
3096 static const char *method_err_retval(Method *m)
3097 {
3098         if (method_is_void(m))
3099                 return "(void)0";
3100         if (m->onerror)
3101                 return m->onerror;
3102         return "0";
3103 }
3104
3105 static void
3106 put_interface_parent_handler(Method *m)
3107 {
3108         const char *errval = method_err_retval(m);
3109         char *name = replace_sep(m->interface, '_');
3110         char *args = get_arg_names_for_macro(m);
3111
3112         out_printf(out, "#define PARENT_HANDLER(%s) (%s_parent_iface \\\n"
3113                         "\t? %s_parent_iface->%s(%s) \\\n"
3114                         "\t: %s)\n", args, name, name, m->id, args, errval);
3115
3116         g_free(name);
3117         g_free(args);
3118 }
3119
3120 static void
3121 put_method(Method *m)
3122 {
3123         char *s, *args, *doc;
3124         gboolean is_void;
3125         is_void = (strcmp(m->mtype->name, "void")==0 &&
3126                    m->mtype->pointer == NULL);
3127         out_printf(out, "\n");
3128         if(m->method != OVERRIDE_METHOD) {
3129                 doc = get_gtk_doc(m->id);
3130                 if(doc) {
3131                         out_printf(out, "%s", doc);
3132                         g_free(doc);
3133                 }
3134         }
3135
3136         switch(m->method) {
3137         case REGULAR_METHOD:
3138                 if(m->line_no > 0)
3139                         out_addline_infile(out, m->line_no);
3140                 if(m->scope == PRIVATE_SCOPE)
3141                         print_method(out, "static ", "\n", "", " ", "", "\n",
3142                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3143                 else /* PUBLIC, PROTECTED */
3144                         print_method(out, "", "\n", "", " ", "", "\n",
3145                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3146
3147                 if (m->interface) {
3148                         out_addline_outfile(out);
3149                         put_interface_parent_handler(m);
3150                 }
3151
3152                 print_method_body(m, TRUE, TRUE);
3153
3154                 if (m->interface) {
3155                         out_printf(out, "#undef PARENT_HANDLER\n");
3156                 }
3157
3158                 /* the outfile line was added above */
3159                 break;
3160         case SIGNAL_FIRST_METHOD:
3161         case SIGNAL_LAST_METHOD:
3162                 if(m->line_no > 0)
3163                         out_addline_infile(out, m->line_no);
3164                 if(m->scope == PRIVATE_SCOPE)
3165                         print_method(out, "static ", "\n", "", " ", "", "\n",
3166                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3167                 else /* PUBLIC, PROTECTED */
3168                         print_method(out, "", "\n", "", " ", "", "\n",
3169                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3170                 out_printf (out, "{\n");
3171
3172                 out_addline_outfile (out);
3173
3174                 out_printf (out,
3175                             "\tGValue ___param_values[%d];\n"
3176                             "\tGValue ___return_val;\n\n"
3177                             "memset (&___return_val, 0, "
3178                               "sizeof (___return_val));\n"
3179                             "memset (&___param_values, 0, "
3180                               "sizeof (___param_values));\n\n",
3181                             g_list_length (m->args));
3182
3183                 print_preconditions (m);
3184
3185                 out_printf (out,
3186                             "\n\t___param_values[0].g_type = 0;\n"
3187                             "\tg_value_init (&___param_values[0], G_TYPE_FROM_INSTANCE (%s));\n"
3188                             "\tg_value_set_instance (&___param_values[0], (gpointer) %s);\n\n",
3189                             ((FuncArg *)m->args->data)->name,
3190                             ((FuncArg *)m->args->data)->name);
3191
3192                 put_signal_args (m);
3193
3194                 if (strcmp (m->gtktypes->data, "NONE") != 0) {
3195                         const char *defret = NULL;
3196
3197                         out_printf (out, "\tg_value_init (&___return_val, G_TYPE_%s);\n",
3198                                     (char *)m->gtktypes->data);
3199
3200                         if (m->defreturn != NULL)
3201                                 defret = m->defreturn;
3202                         else if (m->onerror != NULL)
3203                                 defret = m->onerror;
3204
3205                         if (defret != NULL) {
3206                                 char *set_func;
3207                                 /* FIXME: This code is so fucking ugly it hurts */
3208                                 gboolean do_static = 
3209                                         (strcmp ((char *)m->gtktypes->data, "STRING") == 0 ||
3210                                          strcmp ((char *)m->gtktypes->data, "BOXED") == 0);
3211                                 char *cast = g_strdup (get_cast (m->gtktypes->data, FALSE));
3212                                 if (cast == NULL)
3213                                         cast = get_type (m->mtype, TRUE);
3214
3215                                 if (strcmp (m->gtktypes->data, "UNICHAR") == 0)
3216                                         /* hack because glib is braindamaged */
3217                                         set_func = g_strdup ("g_value_set_uint");
3218                                 else
3219                                         set_func = g_strdup_printf ("g_value_set%s_%s",
3220                                                                     do_static ? "_static" : "",
3221                                                                     (char *)m->gtktypes->data);
3222                                 gob_strdown (set_func);
3223
3224                                 out_printf (out, "\t%s (&___return_val, (%s) (%s));\n",
3225                                             set_func, cast, defret);
3226
3227                                 g_free (set_func);
3228                                 g_free (cast);
3229                         }
3230                         out_printf (out, "\n");
3231                 }
3232
3233                 s = g_strdup (m->id);
3234                 gob_strup (s);
3235
3236                 out_printf(out, "\tg_signal_emitv (___param_values,\n"
3237                            "\t\tobject_signals[%s_SIGNAL],\n"
3238                            "\t\t0 /* detail */,\n"
3239                            "\t\t&___return_val);\n", s);
3240
3241                 g_free (s);
3242
3243                 clear_signal_args (m);
3244
3245                 if (strcmp (m->gtktypes->data, "NONE") != 0) {
3246                         char *cast = g_strdup (get_cast (m->gtktypes->data, FALSE));
3247                         char *getfunc;
3248                         /* Hack because glib is very very braindead */
3249                         gboolean do_dup = 
3250                                 (strcmp ((char *)m->gtktypes->data, "STRING") == 0 ||
3251                                  strcmp ((char *)m->gtktypes->data, "BOXED") == 0 ||
3252                                  strcmp ((char *)m->gtktypes->data, "OBJECT") == 0 ||
3253                                  strcmp ((char *)m->gtktypes->data, "PARAM") == 0);
3254
3255                         if (strcmp (m->gtktypes->data, "UNICHAR") == 0)
3256                                 /* hack because glib is braindamaged */
3257                                 getfunc = g_strdup ("g_value_get_uint");
3258                         else
3259                                 getfunc = g_strdup_printf ("g_value_%s_%s",
3260                                                            do_dup ? "dup" : "get",
3261                                                            (char *)m->gtktypes->data);
3262                         gob_strdown (getfunc);
3263
3264                         if (cast == NULL)
3265                                 cast = get_type (m->mtype, TRUE);
3266
3267                         out_printf (out,
3268                                     "\n\t{\n"
3269                                     "\t\t");
3270                         print_type (out, m->mtype, TRUE);
3271                         out_printf (out,
3272                                     " ___ret = (%s) %s (&___return_val);\n"
3273                                     "\t\tg_value_unset (&___return_val);\n"
3274                                     "\t\treturn ___ret;\n"
3275                                     "\t}\n",
3276                                     cast, getfunc);
3277
3278                         g_free (cast);
3279                         g_free (getfunc);
3280                 }
3281                 out_printf(out, "}\n");
3282
3283                 if(!m->cbuf)
3284                         break;
3285                 if(m->line_no > 0)
3286                         out_addline_infile(out, m->line_no);
3287                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
3288                              m, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE);
3289                 print_method_body(m, FALSE, TRUE);
3290                 /* the outfile line was added above */
3291                 break;
3292         case VIRTUAL_METHOD:
3293                 if(m->line_no > 0)
3294                         out_addline_infile(out, m->line_no);
3295                 if(m->scope==PRIVATE_SCOPE)
3296                         print_method(out, "static ", "\n", "", " ", "", "\n",
3297                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3298                 else /* PUBLIC, PROTECTED */
3299                         print_method(out, "", "\n", "", " ", "", "\n",
3300                                      m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
3301                 out_printf(out, "{\n");
3302                 out_addline_outfile(out);
3303                 out_printf(out, "\t%sClass *klass;\n", typebase);
3304                 print_preconditions(m);
3305                 out_printf(out, "\tklass = %s_GET_CLASS(%s);\n\n"
3306                         "\tif(klass->%s)\n",
3307                         macrobase, ((FuncArg *)m->args->data)->name,
3308                         m->id);
3309                 if(strcmp(m->mtype->name, "void") == 0 &&
3310                    m->mtype->pointer == NULL) {
3311                         GList *li;
3312                         out_printf(out, "\t\t(*klass->%s)(%s",
3313                                    m->id,
3314                                    ((FuncArg *)m->args->data)->name);
3315                         for(li=m->args->next;li;li=g_list_next(li)) {
3316                                 FuncArg *fa = li->data;
3317                                 out_printf(out, ",%s", fa->name);
3318                         }
3319                         out_printf(out, ");\n}\n");
3320                 } else {
3321                         GList *li;
3322                         out_printf(out, "\t\treturn (*klass->%s)(%s",
3323                                    m->id,
3324                                    ((FuncArg *)m->args->data)->name);
3325                         for(li=m->args->next;li;li=g_list_next(li)) {
3326                                 FuncArg *fa = li->data;
3327                                 out_printf(out, ",%s", fa->name);
3328                         }
3329                         out_printf(out, ");\n"
3330                                 "\telse\n"
3331                                 "\t\treturn (");
3332                         print_type(out, m->mtype, TRUE);
3333                         if(m->defreturn)
3334                                 out_printf(out, ")(%s);\n}\n", m->defreturn);
3335                         else if(m->onerror)
3336                                 out_printf(out, ")(%s);\n}\n", m->onerror);
3337                         else
3338                                 out_printf(out, ")(0);\n}\n");
3339                 }
3340
3341                 if(!m->cbuf)
3342                         break;
3343                 if(m->line_no > 0)
3344                         out_addline_infile(out, m->line_no);
3345                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
3346                              m, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE);
3347                 print_method_body(m, FALSE, TRUE);
3348                 /* the outfile line was added above */
3349                 break;
3350         case OVERRIDE_METHOD:
3351                 if(!m->cbuf)
3352                         break;
3353                 if(m->line_no > 0)
3354                         out_addline_infile(out, m->line_no);
3355                 s = g_strdup_printf("\n___%x_", (guint)m->unique_id);
3356                 print_method(out, "static ", s, "", " ", "", "\n",
3357                              m, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE);
3358                 g_free(s);
3359                 out_addline_outfile(out);
3360                 s = replace_sep(m->otype, '_');
3361                 gob_strup (s);
3362                 args = get_arg_names_for_macro(m);
3363                 if(is_void) {
3364                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
3365                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
3366                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n",
3367                                    args, s, m->id, s, m->id, args);
3368                 } else {
3369                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
3370                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
3371                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n"
3372                                    "\t\t(",
3373                                    args, s, m->id, s, m->id, args);
3374                         out_printf(out, "(");
3375                         print_type(out, m->mtype, TRUE);
3376                         out_printf(out, ")%s))\n",
3377                                    m->onerror?m->onerror:"0");
3378                 }
3379                 g_free(args);
3380                 g_free(s);
3381                 print_method_body(m, TRUE, TRUE);
3382                 /* the outfile line was added above */
3383                 out_printf(out, "#undef PARENT_HANDLER\n");
3384                 break;
3385         case CONSTRUCTOR_METHOD:
3386         case DISPOSE_METHOD:
3387         case FINALIZE_METHOD:
3388                 if(m->line_no > 0)
3389                         out_addline_infile(out, m->line_no);
3390                 print_method(out, "static ", "\n", "", " ", "", "\n",
3391                              m, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE);
3392                 print_method_body(m, TRUE, TRUE);
3393                 /* the outfile line was added above */
3394         default:
3395                 break;
3396         }
3397 }
3398
3399 static void
3400 open_files(void)
3401 {
3402         char *outfile, *outfileh, *outfileph;
3403
3404         outfilebase = g_strconcat (fullfilebase, for_cpp ? ".cc" : ".c", NULL);
3405         outfile = g_strconcat(outfilebase, no_touch ? "#gob#" : "", NULL);
3406
3407         outfilehbase = g_strconcat (fullfilebase, ".h", NULL);
3408         outfileh = g_strconcat(outfilehbase, no_touch_headers ? "#gob#" : "", NULL);
3409
3410         if ((privates > 0 || protecteds > 0 ||
3411              private_header == PRIVATE_HEADER_ALWAYS) &&
3412             private_header != PRIVATE_HEADER_NEVER) {
3413                 char sep[2] = {0,0};
3414                 if (file_sep != 0)
3415                         sep[0] = file_sep;
3416                 outfilephbase = g_strconcat (fullfilebase, sep, "private.h", NULL);
3417                 outfileph = g_strconcat (outfilephbase, no_touch ? "#gob#" : "", NULL);
3418         } else {
3419                 outfilephbase = NULL;
3420                 outfileph = NULL;
3421         }
3422
3423         
3424         if ( ! no_write) {
3425                 out = fopen (outfile, "w");
3426                 if (out == NULL) {
3427                         error_printf (GOB_ERROR, 0,
3428                                       "Cannot open outfile: %s", outfile);
3429                 }
3430                 outh = fopen (outfileh, "w");
3431                 if (outh == NULL) {
3432                         error_printf (GOB_ERROR, 0,
3433                                       "Cannot open outfile: %s", outfileh);
3434                 }
3435                 if (outfileph != NULL) {
3436                         outph = fopen (outfileph, "w");
3437                         if (outph == NULL) {
3438                                 error_printf (GOB_ERROR, 0,
3439                                               "Cannot open outfile: %s",
3440                                               outfileph);
3441                         }
3442                 }
3443         }
3444 }
3445
3446 static void
3447 put_argument_nongnu_wrappers (Class *c)
3448 {
3449         GList *li;
3450
3451         if (get_properties < 0 && set_properties < 0)
3452                 return;
3453
3454         for (li = c->nodes; li != NULL; li = li->next) {
3455                 Node *n = li->data;
3456                 const char *name, *gtktype;
3457                 gboolean get, set;
3458                 Type *atype;
3459                 char *aname;
3460                 char *cast;
3461
3462                 if (n->type == ARGUMENT_NODE) {
3463                         Argument *a = (Argument *)n;
3464                         name = a->name;
3465                         gtktype = a->gtktype;
3466                         atype = a->atype;
3467                         get = a->get != NULL;
3468                         set = a->set != NULL;
3469                 } else if (n->type == PROPERTY_NODE) {
3470                         Property *p = (Property *)n;
3471                         name = p->name;
3472                         gtktype = p->gtktype;
3473                         atype = p->ptype;
3474                         get = p->get != NULL;
3475                         set = p->set != NULL;
3476                 } else {
3477                         continue;
3478                 }
3479
3480                 aname = g_strdup (name);
3481                 gob_strup (aname);
3482
3483                 if (atype != NULL)
3484                         cast = get_type (atype, TRUE);
3485                 else
3486                         cast = g_strdup (get_cast (gtktype, TRUE));
3487
3488                 if (cast != NULL) {
3489                         if (set)
3490                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3491                                             "\"%s\",(%s)(arg)\n",
3492                                             macrobase, aname, name, cast);
3493                         if (get)
3494                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3495                                             "\"%s\",(%s*)(arg)\n",
3496                                             macrobase, aname, name, cast);
3497                 } else {
3498                         if(set)
3499                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3500                                             "\"%s\",(arg)\n",
3501                                             macrobase, aname, name);
3502                         if(get)
3503                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3504                                             "\"%s\",(arg)\n",
3505                                             macrobase, aname, name);
3506                 }
3507                 g_free (cast);
3508                 g_free (aname);
3509         }
3510 }
3511
3512 static void
3513 put_argument_gnu_wrappers(Class *c)
3514 {
3515         GList *li;
3516
3517         if(get_properties < 0 && set_properties < 0)
3518                 return;
3519
3520         for (li = c->nodes; li != NULL; li = li->next) {
3521                 Node *n = li->data;
3522                 const char *name, *gtktype;
3523                 gboolean get, set;
3524                 Type *atype;
3525                 char *aname;
3526                 char *cast;
3527
3528                 if (n->type == ARGUMENT_NODE) {
3529                         Argument *a = (Argument *)n;
3530                         name = a->name;
3531                         gtktype = a->gtktype;
3532                         atype = a->atype;
3533                         get = a->get != NULL;
3534                         set = a->set != NULL;
3535                 } else if (n->type == PROPERTY_NODE) {
3536                         Property *p = (Property *)n;
3537                         name = p->name;
3538                         gtktype = p->gtktype;
3539                         atype = p->ptype;
3540                         get = p->get != NULL;
3541                         set = p->set != NULL;
3542                 } else {
3543                         continue;
3544                 }
3545
3546                 aname = g_strdup (name);
3547                 gob_strup (aname);
3548
3549                 if (atype != NULL)
3550                         cast = get_type (atype, TRUE);
3551                 else
3552                         cast = g_strdup (get_cast (gtktype, TRUE));
3553
3554                 if (cast != NULL) {
3555                         if (set)
3556                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3557                                            "\"%s\", __extension__ ({%sz = (arg); z;})\n",
3558                                            macrobase, aname, name, cast);
3559                         if (get)
3560                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3561                                            "\"%s\", __extension__ ({%s*z = (arg); z;})\n",
3562                                            macrobase, aname, name, cast);
3563                 } else {
3564                         if (set)
3565                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3566                                            "\"%s\",(arg)\n",
3567                                            macrobase, aname, name);
3568                         if (get)
3569                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3570                                            "\"%s\",(arg)\n",
3571                                            macrobase, aname, name);
3572                 }
3573                 g_free (cast);
3574                 g_free (aname);
3575         }
3576 }
3577
3578 static void
3579 print_ccode_block(CCode *cc)
3580 {
3581         FILE *fp;
3582         switch(cc->cctype) {
3583         case HT_CCODE:
3584                 /* HT code is printed exactly like normal header
3585                    code but is printed before */
3586         case H_CCODE:
3587                 fp = outh;
3588                 out_printf(fp, "\n");
3589                 break;
3590         case AT_CCODE:
3591                 /* AT code is printed exactly like normal 'all'
3592                    code but is printed before */
3593         case A_CCODE:
3594                 if(outph) {
3595                         out_printf(outph, "\n");
3596                         out_printf(outph, "%s\n", cc->cbuf);
3597                         out_addline_infile(outph, cc->line_no);
3598                         out_addline_outfile(outph);
3599                 }
3600                 out_printf(outh, "\n");
3601                 out_printf(outh, "%s\n", cc->cbuf);
3602                 fp = out;
3603                 out_printf(fp, "\n");
3604                 out_addline_infile(fp, cc->line_no);
3605                 break;
3606         default:
3607         case CT_CCODE:
3608         case C_CCODE:
3609                 fp = out;
3610                 out_printf(fp, "\n");
3611                 out_addline_infile(fp, cc->line_no);
3612                 break;
3613         case PH_CCODE:
3614                 if(outph)
3615                         fp = outph;
3616                 else
3617                         fp = out;
3618                 out_printf(fp, "\n");
3619                 out_addline_infile(fp, cc->line_no);
3620                 break;
3621         }
3622         out_printf(fp, "%s\n", cc->cbuf);
3623         if(cc->cctype == C_CCODE ||
3624            cc->cctype == AD_CCODE ||
3625            cc->cctype == A_CCODE ||
3626            cc->cctype == AT_CCODE ||
3627            cc->cctype == PH_CCODE)
3628                 out_addline_outfile(fp);
3629 }
3630
3631 static void
3632 print_class_block(Class *c)
3633 {
3634         GList *li;
3635         char *s;
3636         gboolean printed_private = FALSE;
3637
3638         if (c->glade_xml)
3639         {
3640                 out_printf(outph ? outph : outh, "#include <gtk/gtk.h>\n");
3641                 out_printf(outph ? outph : outh, "#include <glade/glade-xml.h>\n\n");
3642         }
3643         
3644         if(any_special) {
3645                 out_printf(out, "/* utility types we may need */\n");
3646                 if(special_array[SPECIAL_2POINTER])
3647                         out_printf(out, "typedef struct { "
3648                                    "gpointer a; gpointer b; "
3649                                    "} ___twopointertype;\n");
3650                 if(special_array[SPECIAL_3POINTER])
3651                         out_printf(out, "typedef struct { "
3652                                    "gpointer a; gpointer b; "
3653                                    "gpointer c; "
3654                                    "} ___threepointertype;\n");
3655                 if(special_array[SPECIAL_INT_POINTER])
3656                         out_printf(out, "typedef struct { "
3657                                    "gint a; gpointer b; "
3658                                    "} ___intpointertype;\n");
3659                 out_printf(out, "\n");
3660         }
3661
3662         out_printf(outh, "\n/*\n"
3663                    " * Type checking and casting macros\n"
3664                    " */\n");
3665         out_printf(outh, "#define %s\t"
3666                    "(%s_get_type())\n",
3667                    macrotype, funcbase);
3668         out_printf(outh, "#define %s(obj)\t"
3669                    "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s)\n",
3670                    macrobase, funcbase, typebase);
3671         out_printf(outh, "#define %s_CONST(obj)\t"
3672                    "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s const)\n",
3673                    macrobase, funcbase, typebase); 
3674         out_printf(outh, "#define %s_CLASS(klass)\t"
3675                    "G_TYPE_CHECK_CLASS_CAST((klass), %s_get_type(), %sClass)\n",
3676                    macrobase, funcbase, typebase);
3677         out_printf(outh, "#define %s(obj)\t"
3678                    "G_TYPE_CHECK_INSTANCE_TYPE((obj), %s_get_type ())\n\n",
3679                    macrois, funcbase);
3680         out_printf(outh,
3681                    "#define %s_GET_CLASS(obj)\t"
3682                    "G_TYPE_INSTANCE_GET_CLASS((obj), %s_get_type(), %sClass)\n",
3683                    macrobase, funcbase, typebase);
3684
3685         if ( ! no_self_alias) {
3686                 out_printf(out, "/* self casting macros */\n");
3687                 out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
3688                 out_printf(out, "#define SELF_CONST(x) %s_CONST(x)\n", macrobase);
3689                 out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
3690                 out_printf(out, "#define TYPE_SELF %s\n", macrotype);
3691                 out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n",
3692                            macrobase);
3693                 out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n",
3694                            macrobase);
3695
3696                 out_printf(out, "/* self typedefs */\n");
3697                 out_printf(out, "typedef %s Self;\n", typebase);
3698                 out_printf(out, "typedef %sClass SelfClass;\n\n", typebase);
3699         }
3700
3701         if (privates > 0 ||
3702             always_private_struct) {
3703                 out_printf (outh, "\n/* Private structure type */\n");
3704                 out_printf (outh, "typedef struct _%sPrivate %sPrivate;\n",
3705                            typebase, typebase);
3706                 if (privates == 0)
3707                         out_printf (outh, "/* There are no privates, this "
3708                                     "structure is thus never defined */\n");
3709         }
3710
3711         out_printf (outh, "\n/*\n"
3712                     " * Main object structure\n"
3713                     " */\n");
3714         s = replace_sep (c->otype, '_');
3715         gob_strup (s);
3716         out_printf (outh, "#ifndef __TYPEDEF_%s__\n"
3717                     "#define __TYPEDEF_%s__\n", s, s);
3718         g_free (s);
3719         out_printf (outh, "typedef struct _%s %s;\n"
3720                     "#endif\n", typebase, typebase);
3721         out_printf (outh, "struct _%s {\n\t%s __parent__;\n",
3722                     typebase, ptypebase);
3723         for (li = c->nodes; li; li=li->next) {
3724                 static gboolean printed_public = FALSE;
3725                 Node *n = li->data;
3726                 Variable *v = (Variable *)n;
3727                 if(n->type == VARIABLE_NODE &&
3728                    v->scope == PUBLIC_SCOPE) {
3729                         if( ! printed_public) {
3730                                 out_printf(outh, "\t/*< public >*/\n");
3731                                 printed_public = TRUE;
3732                         }
3733                         put_variable((Variable *)n, outh);
3734                 }
3735         }
3736         /* put protecteds always AFTER publics */
3737         for (li = c->nodes; li != NULL; li = li->next) {
3738                 Node *n = li->data;
3739                 Variable *v = (Variable *)n;
3740                 if (n->type == VARIABLE_NODE &&
3741                     v->scope == PROTECTED_SCOPE) {
3742                         if ( ! printed_private) {
3743                                 out_printf (outh, "\t/*< private >*/\n");
3744                                 printed_private = TRUE;
3745                         }
3746                         put_variable ((Variable *)n, outh);
3747                 }
3748         }
3749         if (privates > 0 ||
3750             always_private_struct) {
3751                 if ( ! printed_private)
3752                         out_printf (outh, "\t/*< private >*/\n");
3753                 out_printf (outh, "\t%sPrivate *_priv;\n", typebase);
3754         }
3755         out_printf (outh, "};\n");
3756
3757         if (privates > 0) {
3758                 FILE *outfp;
3759
3760                 /* if we are to stick this into the private
3761                    header, if not stick it directly into the
3762                    C file */
3763                 if (outph != NULL) 
3764                         outfp = outph;
3765                 else
3766                         outfp = out;
3767
3768                 out_printf (outfp, "struct _%sPrivate {\n",
3769                             typebase);
3770                 if (privates > 0)
3771                 {
3772                  for(li=c->nodes; li; li=li->next) {
3773                          Node *n = li->data;
3774                          Variable *v = (Variable *)n;
3775                          if(n->type == VARIABLE_NODE &&
3776                                         v->scope == PRIVATE_SCOPE) {
3777                                  out_addline_infile(outfp, v->line_no);
3778                                  put_variable(v, outfp);
3779                          }
3780                         }
3781                         out_addline_outfile(outfp);
3782                 }
3783                 out_printf(outfp, "};\n");
3784         }
3785
3786         out_printf(outh, "\n/*\n"
3787                    " * Class definition\n"
3788                    " */\n");
3789         out_printf(outh, "typedef struct _%sClass %sClass;\n",
3790                    typebase, typebase);
3791         out_printf(outh,
3792                    "struct _%sClass {\n\t%sClass __parent__;\n",
3793                    typebase, ptypebase);
3794         for(li = c->nodes; li != NULL; li = li->next) {
3795                 Node *n = li->data;
3796                 if(n->type == METHOD_NODE)
3797                         put_vs_method((Method *)n);
3798         }
3799         /* If BonoboX type class put down the epv */
3800         if (c->bonobo_object_class != NULL) {
3801                 out_printf (outh,
3802                             "\t/* Bonobo object epv */\n"
3803                             "\tPOA_%s__epv _epv;\n",
3804                             c->bonobo_object_class);
3805         }
3806         /* put class scope variables */
3807         for (li = c->nodes; li != NULL; li = li->next) {
3808                 Node *n = li->data;
3809                 Variable *v = (Variable *)n;
3810                 if (n->type == VARIABLE_NODE &&
3811                     v->scope == CLASS_SCOPE)
3812                         put_variable ((Variable *)n, outh);
3813         }
3814         out_printf (outh, "};\n\n");
3815
3816         out_printf (out, "/* here are local prototypes */\n");
3817         if (set_properties > 0) {
3818                 out_printf (out, "static void ___object_set_property "
3819                             "(GObject *object, guint property_id, "
3820                             "const GValue *value, GParamSpec *pspec);\n");
3821         }
3822         if (get_properties > 0) {
3823                 out_printf (out, "static void ___object_get_property "
3824                             "(GObject *object, guint property_id, "
3825                             "GValue *value, GParamSpec *pspec);\n");
3826         }
3827
3828         out_printf (outh, "\n/*\n"
3829                     " * Public methods\n"
3830                     " */\n");
3831
3832         if (!overrode_get_type) {
3833                 /*
3834                  * For ordinary "static" types it should be safe to mark the
3835                  * get_type implementation as const, since the get_type
3836                  * function return really is constant at the call boundary
3837                  * (even though there is an initial setup on the first call).
3838                  * But for dynamic types, since the registration is explicitly
3839                  * separated, we need to settle for "pure" as the results of
3840                  * get_type differ before and after type registration.
3841                  */
3842                 out_printf(outh, "GType\t%s_get_type\t(void) %s;\n", funcbase,
3843                                  c->dynamic ? "G_GNUC_PURE" : "G_GNUC_CONST");
3844         }
3845
3846         if (c->dynamic) {
3847                 out_printf(outh, "void\t%s_register_type\t(GTypeModule *);\n",
3848                                  funcbase);
3849         }
3850
3851         for(li = c->nodes; li != NULL; li = li->next) {
3852                 Node *n = li->data;
3853                 if(n->type == METHOD_NODE) {
3854                         put_pub_method((Method *)n);
3855                         put_prot_method((Method *)n);
3856                         put_priv_method_prot((Method *)n);
3857                 }
3858         }
3859
3860         /* this idea is less and less apealing to me */
3861         if (signals > 0) {
3862                 out_printf (outh, "\n/*\n"
3863                             " * Signal connection wrapper macros\n"
3864                             " */\n");
3865                 if( ! no_gnu) {
3866                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
3867                         put_signal_macros (c, TRUE);
3868                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
3869                         put_signal_macros (c, FALSE);
3870                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n");
3871                 } else {
3872                         put_signal_macros (c, FALSE);
3873                         out_printf(outh, "\n");
3874                 }
3875
3876                 out_printf (out, "\n/*\n"
3877                             " * Signal connection wrapper macro shortcuts\n"
3878                             " */\n");
3879                 put_local_signal_macros (c);
3880                 out_printf(outh, "\n");
3881         }
3882
3883         /* argument wrapping macros */
3884         if(get_properties > 0 || set_properties > 0) {
3885                 out_printf(outh, "\n/*\n"
3886                            " * Argument wrapping macros\n"
3887                            " */\n");
3888                 if( ! no_gnu) {
3889                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
3890                         put_argument_gnu_wrappers(c);
3891                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
3892                         put_argument_nongnu_wrappers(c);
3893                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
3894                 } else {
3895                         put_argument_nongnu_wrappers(c);
3896                 }
3897         }
3898
3899         if(signals > 0) {
3900                 for(li = c->nodes; li != NULL; li = li->next) {
3901                         Node *n = li->data;
3902                         if(n->type == METHOD_NODE)
3903                                 add_signal_prots((Method *)n);
3904                 }
3905         }
3906
3907         add_enums (c);
3908
3909         if(any_method_to_alias(c)) {
3910                 out_printf (out, "/* Short form macros */\n");
3911                 make_method_aliases (c);
3912         }
3913
3914         add_interface_inits (c);
3915
3916         if (!overrode_get_type) {
3917                 if (c->bonobo_object_class != NULL)
3918                         add_bonobo_object_get_type();
3919                 else if (c->dynamic)
3920                         add_dynamic_get_type();
3921                 else
3922                         add_get_type();
3923         }
3924
3925         out_printf (out, "/* a macro for creating a new object of our type */\n");
3926         out_printf (out,
3927                     "#define GET_NEW ((%s *)g_object_new(%s_get_type(), NULL))\n\n",
3928                     typebase, funcbase);
3929
3930         out_printf (out, "/* a function for creating a new object of our type */\n");
3931         out_printf (out, "#include <stdarg.h>\n");
3932         out_printf (out,
3933                     "static %s * GET_NEW_VARG (const char *first, ...)%s;\n"
3934                     "static %s *\nGET_NEW_VARG (const char *first, ...)\n"
3935                     "{\n\t%s *ret;\n\tva_list ap;\n"
3936                     "\tva_start (ap, first);\n"
3937                     "\tret = (%s *)g_object_new_valist (%s_get_type (), "
3938                     "first, ap);\n"
3939                     "\tva_end (ap);\n"
3940                     "\treturn ret;\n}\n\n",
3941                     typebase,
3942                     no_gnu ? "" : " G_GNUC_UNUSED",
3943                     typebase, typebase, typebase, funcbase);
3944
3945         if (c->glade_xml)
3946         {
3947                 out_printf (out, "/* a function to connect glade callback */\n");
3948                 out_printf (out,"static void\n"
3949                             "___glade_xml_connect_foreach(const gchar *handler_name,\n"
3950                             "GObject *object,\n"
3951                             "const gchar *signal_name,\n"
3952                             "const gchar *signal_data,\n"
3953                             "GObject *connect_object,\n"
3954                             "gboolean after,\n"
3955                             "gpointer user_data)\n"
3956                             "{\n"
3957                             "\tstatic GModule * allsymbols = NULL;\n"
3958                             "   \n"
3959                             "\tif (!allsymbols) allsymbols = g_module_open(NULL, 0);\n"
3960                             "\tif (allsymbols) {\n"
3961                             "\t\tgchar * func_name = g_strdup_printf(\"%s_%%s\", handler_name);\n"
3962                             "\t\tGCallback func;\n"
3963                             "\n"
3964                             "\t\tif (!g_module_symbol(allsymbols, func_name, (gpointer)&func)){\n"
3965                             "\t\t\tif (!g_module_symbol(allsymbols, handler_name, (gpointer)&func)) {\n"
3966                             "\t\t\t\tg_warning(\"could not find signal handler '%%s'.\", func_name);\n"
3967                             "\t\t\t\tg_free(func_name);\n"
3968                             "\t\t\t\treturn;\n"
3969                             "\t\t\t}\n"
3970                             "\t\t}\n"
3971                             "\t\tif (after)\n"
3972                             "\t\t\tg_signal_connect_data(object, signal_name, func, user_data, NULL, G_CONNECT_AFTER | G_CONNECT_SWAPPED);\n"
3973                             "\t\telse\n"
3974                             "\t\t\tg_signal_connect_data(object, signal_name, func, user_data, NULL, G_CONNECT_SWAPPED);\n"
3975                             "\t\tg_free(func_name);\n"
3976                             "\t}\n"
3977                             "}\n"
3978                             "\n",
3979                             funcbase);
3980         }
3981
3982         for (li = nodes; li != NULL; li = li->next) {
3983                 Node *node = li->data;
3984                 if (node->type == CCODE_NODE) {
3985                         CCode *cc = (CCode *)node;
3986                         if (cc->cctype == AD_CCODE)
3987                                 print_ccode_block (cc);
3988                 }
3989         }
3990
3991         if (need_constructor)
3992                 add_constructor (c);
3993
3994         if (need_dispose)
3995                 add_dispose (c);
3996
3997         if (need_finalize)
3998                 add_finalize (c);
3999
4000         add_inits(c);
4001
4002         if(set_properties > 0) {
4003                 add_getset_arg(c, TRUE);
4004         }
4005
4006         if(get_properties > 0) {
4007                 add_getset_arg(c, FALSE);
4008         }
4009
4010         for(li = c->nodes; li != NULL; li = li->next) {
4011                 Node *n = li->data;
4012                 if(n->type == METHOD_NODE)
4013                         put_method((Method *)n);
4014         }
4015
4016         add_bad_hack_to_avoid_unused_warnings(c);
4017 }
4018
4019 static void
4020 print_useful_macros(void)
4021 {
4022         int major = 0, minor = 0, pl = 0;
4023
4024         /* Version stuff */
4025         sscanf (VERSION, "%d.%d.%d", &major, &minor, &pl);
4026         out_printf (out, "#define GOB_VERSION_MAJOR %d\n", major);
4027         out_printf (out, "#define GOB_VERSION_MINOR %d\n", minor);
4028         out_printf (out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
4029
4030         /* Useful priv macro thingie */
4031         /* FIXME: this should be done the same way that priv is, as a var,
4032          * not a define */
4033         out_printf (out, "#define selfp (self->_priv)\n\n");
4034 }
4035
4036 static void
4037 print_more_useful_macros (void)
4038 {
4039         if (no_gnu) {
4040                 out_printf (out, "#define ___GOB_LIKELY(expr) (expr)\n");
4041                 out_printf (out, "#define ___GOB_UNLIKELY(expr) (expr)\n");
4042         } else {
4043                 out_printf (out, "#ifdef G_LIKELY\n");
4044                 out_printf (out, "#define ___GOB_LIKELY(expr) G_LIKELY(expr)\n");
4045                 out_printf (out, "#define ___GOB_UNLIKELY(expr) G_UNLIKELY(expr)\n");
4046                 out_printf (out, "#else /* ! G_LIKELY */\n");
4047                 out_printf (out, "#define ___GOB_LIKELY(expr) (expr)\n");
4048                 out_printf (out, "#define ___GOB_UNLIKELY(expr) (expr)\n");
4049                 out_printf (out, "#endif /* G_LIKELY */\n");
4050         }
4051 }
4052
4053 static void
4054 print_file_comments(void)
4055 {
4056         out_printf(outh, "/* Generated by GOB (v%s)"
4057                    "   (do not edit directly) */\n\n", VERSION);
4058         if(outph)
4059                 out_printf(outph, "/* Generated by GOB (v%s)"
4060                            "   (do not edit directly) */\n\n", VERSION);
4061         out_printf(out, "/* Generated by GOB (v%s)"
4062                    "   (do not edit directly) */\n\n", VERSION);
4063
4064         out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
4065 }
4066
4067 static void
4068 print_includes(void)
4069 {
4070         gboolean found_header;
4071         char *p;
4072
4073         /* We may need string.h for memset */
4074         if ( ! g_list_find_custom(include_files, "string.h", (GCompareFunc)strcmp)) {
4075                 out_printf(out, "#include <string.h> /* memset() */\n\n");
4076         }
4077
4078         p = g_strconcat(filebase, ".h", NULL);
4079         found_header = TRUE;
4080         if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
4081                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
4082                 found_header = FALSE;
4083         }
4084         g_free(p);
4085
4086         /* if we are creating a private header see if it was included */
4087         if(outph) {
4088                 char sep[2] = {0,0};
4089                 if (file_sep != 0)
4090                         sep[0] = file_sep;
4091                 p = g_strconcat(filebase, sep, "private.h", NULL);
4092                 if( ! g_list_find_custom(include_files, p,
4093                                          (GCompareFunc)strcmp)) {
4094                         out_printf(out, "#include \"%s%sprivate.h\"\n\n",
4095                                    filebase,
4096                                    sep);
4097                         if(found_header)
4098                                 error_printf(GOB_WARN, 0,
4099                                             "Implicit private header include "
4100                                             "added to top of\n"
4101                                             "\tsource file, while public "
4102                                             "header is at a custom location, "
4103                                             "you should\n"
4104                                             "\texplicitly include "
4105                                             "the private header below the "
4106                                             "public one.");
4107                 }
4108                 g_free(p);
4109         }
4110 }
4111
4112 static void
4113 print_header_prefixes(void)
4114 {
4115         char *p;
4116
4117         p = replace_sep(((Class *)class)->otype, '_');
4118         gob_strup (p);
4119         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
4120         if(outph)
4121                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
4122                            "#define __%s_PRIVATE_H__\n\n"
4123                            "#include \"%s.h\"\n\n", p, p, filebase);
4124         g_free(p);
4125
4126         if( ! no_extern_c) {
4127                 out_printf(outh, "#ifdef __cplusplus\n"
4128                            "extern \"C\" {\n"
4129                            "#endif /* __cplusplus */\n\n");
4130                 if(outph)
4131                         out_printf(outph, "#ifdef __cplusplus\n"
4132                                    "extern \"C\" {\n"
4133                                    "#endif /* __cplusplus */\n\n");
4134         }
4135 }
4136
4137 static void
4138 print_header_postfixes(void)
4139 {
4140         if( ! no_extern_c)
4141                 out_printf(outh, "\n#ifdef __cplusplus\n"
4142                            "}\n"
4143                            "#endif /* __cplusplus */\n");
4144         out_printf(outh, "\n#endif\n");
4145         if(outph) {
4146                 if( ! no_extern_c)
4147                         out_printf(outph, "\n#ifdef __cplusplus\n"
4148                                    "}\n"
4149                                    "#endif /* __cplusplus */\n");
4150                 out_printf(outph, "\n#endif\n");
4151         }
4152 }
4153
4154 static void
4155 print_all_top(void)
4156 {
4157         GList *li;
4158
4159         /* print the AT_CCODE and CT_CCODE blocks */
4160         for(li = nodes; li != NULL; li = li->next) {
4161                 Node *node = li->data;
4162                 if(node->type == CCODE_NODE) {
4163                         CCode *cc = (CCode *)node;
4164                         if (cc->cctype == AT_CCODE ||
4165                             cc->cctype == CT_CCODE)
4166                                 print_ccode_block((CCode *)node);
4167                 }
4168         }
4169 }
4170
4171 static void
4172 print_header_top(void)
4173 {
4174         GList *li;
4175
4176         /* mandatory includes */
4177         out_printf (outh, "#include <glib.h>\n");
4178         out_printf (outh, "#include <glib-object.h>\n");
4179
4180         /* print the HT_CCODE blocks */
4181         for (li = nodes; li != NULL; li = li->next) {
4182                 Node *node = li->data;
4183                 if (node->type == CCODE_NODE) {
4184                         CCode *cc = (CCode *)node;
4185                         if (cc->cctype == HT_CCODE)
4186                                 print_ccode_block ((CCode *)node);
4187                 }
4188         }
4189 }
4190
4191 static void
4192 print_enum (EnumDef *enode)
4193 {
4194         GList *li;
4195         char *funcprefix;
4196         char *type;
4197         char *str;
4198
4199         funcprefix = replace_sep (enode->etype, '_');
4200         gob_strdown (funcprefix);
4201         out_printf (out, "static const GEnumValue _%s_values[] = {\n",
4202                     funcprefix);
4203         type = remove_sep (enode->etype);
4204
4205         out_printf (outh, "\ntypedef enum {\n");
4206
4207         for (li = enode->values; li != NULL; li = li->next) {
4208                 EnumValue *value = li->data; 
4209                 char *p;
4210                 char *sname = gob_strdown (g_strdup (value->name));
4211
4212                 while ((p = strchr (sname, '_')) != NULL)
4213                         *p = '-';
4214
4215                 out_printf (outh, "\t%s_%s", enode->prefix, value->name);
4216                 if (value->value != NULL)
4217                         out_printf (outh, " = %s", value->value);
4218                 if (li->next != NULL)
4219                         out_printf (outh, ",\n");
4220                 else
4221                         out_printf (outh, "\n");
4222
4223                 out_printf (out, "\t{ %s_%s, (char *)\"%s_%s\", (char *)\"%s\" },\n",
4224                             enode->prefix, value->name,
4225                             enode->prefix, value->name,
4226                             sname);
4227
4228                 g_free (sname);
4229         }
4230
4231         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
4232
4233         out_printf (outh, "} %s;\n", type);
4234
4235         str = make_pre_macro (enode->etype, "TYPE");
4236         out_printf (outh, "#define %s ", str);
4237         g_free (str);
4238
4239         out_printf (outh, "%s_get_type()\n", funcprefix);
4240         out_printf (outh, "GType %s_get_type (void) G_GNUC_CONST;\n\n", funcprefix);
4241
4242         out_printf (out,
4243                     "GType\n%s_get_type (void)\n"
4244                     "{\n"
4245                     "\tstatic GType type = 0;\n"
4246                     "\tif ___GOB_UNLIKELY(type == 0)\n"
4247                     "\t\ttype = g_enum_register_static (\"%s\", _%s_values);\n"
4248                     "\treturn type;\n"
4249                     "}\n\n",
4250                     funcprefix, type, funcprefix);
4251
4252         g_free (funcprefix);
4253         g_free (type);
4254 }
4255
4256 static void
4257 print_flags (Flags *fnode)
4258 {
4259         GList *li;
4260         char *funcprefix;
4261         char *type;
4262         char *str;
4263         int i;
4264
4265         funcprefix = replace_sep (fnode->ftype, '_');
4266         gob_strdown (funcprefix);
4267         out_printf (out, "static const GFlagsValue _%s_values[] = {\n",
4268                     funcprefix);
4269         type = remove_sep (fnode->ftype);
4270
4271         out_printf (outh, "\ntypedef enum {\n");
4272
4273         for (i = 0, li = fnode->values; li != NULL; i++, li = li->next) {
4274                 const char *name = li->data; 
4275                 char *p;
4276                 char *sname = gob_strdown (g_strdup (name));
4277
4278                 while ((p = strchr (sname, '_')) != NULL)
4279                         *p = '-';
4280
4281                 out_printf (outh, "\t%s_%s = 1<<%d",
4282                             fnode->prefix, name, i);
4283                 if (li->next != NULL)
4284                         out_printf (outh, ",\n");
4285                 else
4286                         out_printf (outh, "\n");
4287
4288                 out_printf (out, "\t{ %s_%s, (char *)\"%s_%s\", (char *)\"%s\" },\n",
4289                             fnode->prefix, name,
4290                             fnode->prefix, name,
4291                             sname);
4292
4293                 g_free (sname);
4294         }
4295
4296         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
4297
4298         out_printf (outh, "} %s;\n", type);
4299
4300         str = make_pre_macro (fnode->ftype, "TYPE");
4301         out_printf (outh, "#define %s ", str);
4302         g_free (str);
4303
4304         out_printf (outh, "%s_get_type()\n", funcprefix);
4305         out_printf (outh, "GType %s_get_type (void) G_GNUC_CONST;\n\n", funcprefix);
4306
4307         out_printf (out,
4308                     "GType\n%s_get_type (void)\n"
4309                     "{\n"
4310                     "\tstatic GType type = 0;\n"
4311                     "\tif ___GOB_UNLIKELY(type == 0)\n"
4312                     "\t\ttype = g_flags_register_static (\"%s\", _%s_values);\n"
4313                     "\treturn type;\n"
4314                     "}\n\n",
4315                     funcprefix, type, funcprefix);
4316
4317         g_free (funcprefix);
4318         g_free (type);
4319 }
4320
4321 static void
4322 print_error (Error *enode)
4323 {
4324         GList *li;
4325         char *funcprefix;
4326         char *type;
4327         char *str;
4328
4329         funcprefix = replace_sep (enode->etype, '_');
4330         gob_strdown (funcprefix);
4331         out_printf (out, "static const GEnumValue _%s_values[] = {\n",
4332                     funcprefix);
4333         type = remove_sep (enode->etype);
4334
4335         out_printf (outh, "\ntypedef enum {\n");
4336
4337         for (li = enode->values; li != NULL; li = li->next) {
4338                 const char *name = li->data;
4339                 char *p;
4340                 char *sname = gob_strdown (g_strdup (name));
4341
4342                 while ((p = strchr (sname, '_')) != NULL)
4343                         *p = '-';
4344
4345                 out_printf (outh, "\t%s_%s", enode->prefix, name);
4346                 if (li->next != NULL)
4347                         out_printf (outh, ",\n");
4348                 else
4349                         out_printf (outh, "\n");
4350
4351                 out_printf (out, "\t{ %s_%s, (char *)\"%s_%s\", (char *)\"%s\" },\n",
4352                             enode->prefix, name,
4353                             enode->prefix, name,
4354                             sname);
4355
4356                 g_free (sname);
4357         }
4358
4359         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
4360
4361         out_printf (outh, "} %s;\n", type);
4362
4363         str = make_pre_macro (enode->etype, "TYPE");
4364         out_printf (outh, "#define %s ", str);
4365         g_free (str);
4366
4367         out_printf (outh, "%s_get_type ()\n", funcprefix);
4368         out_printf (outh, "GType %s_get_type (void) G_GNUC_CONST;\n\n", funcprefix);
4369
4370         out_printf (out,
4371                     "GType\n%s_get_type (void)\n"
4372                     "{\n"
4373                     "\tstatic GType type = 0;\n"
4374                     "\tif ___GOB_UNLIKELY(type == 0)\n"
4375                     "\t\ttype = g_enum_register_static (\"%s\", _%s_values);\n"
4376                     "\treturn type;\n"
4377                     "}\n\n",
4378                     funcprefix, type, funcprefix);
4379
4380         out_printf (outh, "#define %s %s_quark ()\n", enode->prefix, funcprefix);
4381         out_printf (outh, "GQuark %s_quark (void);\n\n", funcprefix);
4382
4383         str = replace_sep (enode->etype, '-');
4384         gob_strdown (str);
4385
4386         out_printf (out,
4387                     "GQuark\n%s_quark (void)\n"
4388                     "{\n"
4389                     "\tstatic GQuark q = 0;\n"
4390                     "\tif (q == 0)\n"
4391                     "\t\tq = g_quark_from_static_string (\"%s\");\n"
4392                     "\treturn q;\n"
4393                     "}\n\n",
4394                     funcprefix, str);
4395
4396         g_free (str);
4397
4398         g_free (funcprefix);
4399         g_free (type);
4400 }
4401
4402 static void
4403 generate_outfiles(void)
4404 {
4405         GList *li;
4406
4407         print_file_comments();
4408
4409         print_all_top();
4410
4411         print_header_top();
4412
4413         print_header_prefixes();
4414
4415         print_useful_macros();
4416
4417         print_includes();
4418
4419         print_more_useful_macros ();
4420
4421         for (li = nodes; li != NULL; li = li->next) {
4422                 Node *node = li->data;
4423                 if (node->type == CCODE_NODE) {
4424                         CCode *cc = (CCode *)node;
4425                         if (cc->cctype != HT_CCODE &&
4426                             cc->cctype != AT_CCODE &&
4427                             cc->cctype != AD_CCODE)
4428                                 print_ccode_block ((CCode *)node);
4429                 } else if (node->type == CLASS_NODE) {
4430                         print_class_block ((Class *)node);
4431                 } else if (node->type == ENUMDEF_NODE) {
4432                         print_enum ((EnumDef *)node);
4433                 } else if (node->type == FLAGS_NODE) {
4434                         print_flags ((Flags *)node);
4435                 } else if (node->type == ERROR_NODE) {
4436                         print_error ((Error *)node);
4437                 } else {
4438                         g_assert_not_reached();
4439                 }
4440         }
4441
4442         print_header_postfixes();
4443 }
4444
4445 static void
4446 print_help(void)
4447 {
4448         fprintf(stderr, "Gob version %s\n\n", VERSION);
4449         fprintf(stderr, "gob [options] file.gob\n\n");
4450         fprintf(stderr, "Options:\n"
4451                 "\t--help,-h,-?            Display this help\n"
4452                 "\t--version               Display version\n"
4453                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
4454                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
4455                 "\t--for-cpp               Create C++ files\n"
4456                 "\t--no-extern-c           Never print extern \"C\" into the "
4457                                           "header\n"
4458                 "\t--no-gnu                Never use GNU extentions\n"
4459                 "\t--no-touch              Don't touch output files unless they "
4460                                           "really\n"
4461                 "\t                        changed (implies --no-touch-headers)\n"
4462                 "\t--no-touch-headers      Don't touch headers unless they "
4463                                           "really changed\n"
4464                 "\t--always-private-header Always create a private header "
4465                                           "file,\n"
4466                 "\t                        even if it would be empty\n"
4467                 "\t--ondemand-private-header Create private header only when "
4468                                           "needed\n"
4469                 "\t                        [default]\n"
4470                 "\t--no-private-header     Don't create a private header, "
4471                                           "put private\n"
4472                 "\t                        structure and protected "
4473                                           "prototypes inside c file\n"
4474                 "\t--always-private-struct Always create a private pointer "
4475                                           "in\n"
4476                 "\t                        the object structure\n"
4477                 "\t--m4                    Preprocess source with m4. "
4478                                           "Following args will\n"
4479                 "\t                        be passed to m4\n"
4480                 "\t--m4-dir                Print directory that will be "
4481                                           "searched for m4\n"
4482                 "\t                        files\n"
4483                 "\t--no-write,-n           Don't write output files, just "
4484                                           "check syntax\n"
4485                 "\t--no-lines              Don't print '#line' to output\n"
4486                 "\t--no-self-alias         Don't create self type and macro "
4487                                           "aliases\n"
4488                 "\t--no-kill-underscores   Ignored for compatibility\n"
4489                 "\t-o,--output-dir         The directory where output "
4490                                           "should be placed\n"
4491                 "\t--file-sep[=c]          replace default \'-\' file "
4492                                           "name separator\n\n"
4493                 "\t--gtk3                  Use gtk+3\n"
4494                 );
4495         fprintf(stderr, "End world hunger, donate to the World Food Programme, http://www.wfp.org\n");
4496 }
4497
4498 static void
4499 parse_options(int argc, char *argv[])
4500 {
4501         int i;
4502         int got_file = FALSE;
4503         int no_opts = FALSE;
4504         int m4_opts = FALSE; /* if we are just passing on args to m4 */
4505
4506         filename = NULL;
4507
4508         for(i = 1 ; i < argc; i++) {
4509                 if(m4_opts) {
4510                         char *new_commandline;
4511                         g_assert(m4_commandline!=NULL);
4512
4513                         /* check whether this one looks like the filename */
4514                         if((!strcmp(argv[i],"-") || argv[i][0] != '-') 
4515                            && !got_file) {
4516                                 const gchar *m4_flags=use_m4_clean?"":M4_FLAGS;
4517                                 filename = argv[i];
4518                                 got_file = TRUE;
4519                                 
4520                                 /* insert flags before the filename */
4521                                 new_commandline=g_strconcat(m4_commandline,
4522                                                             " ",
4523                                                             m4_flags, 
4524                                                             " ",
4525                                                             argv[i],
4526                                                             NULL);
4527                         }
4528
4529                         /* just an ordinary option */
4530                         else                      
4531                           new_commandline=g_strconcat(m4_commandline,
4532                                                       " ",
4533                                                       argv[i],
4534                                                       NULL);
4535
4536                         /* free old commandline */
4537                         g_free(m4_commandline);
4538                         m4_commandline=new_commandline;
4539
4540                 } else if(no_opts ||
4541                    argv[i][0] != '-') {
4542                         /*must be a file*/
4543                         if(got_file) {
4544                                 fprintf(stderr, "Specify only one file!\n");
4545                                 print_help();
4546                                 exit(1);
4547                         }
4548                         filename = argv[i];
4549                         got_file = TRUE;
4550                 } else if(strcmp(argv[i], "--help")==0) {
4551                         print_help();
4552                         exit(0);
4553                 } else if(strcmp(argv[i], "--version")==0) {
4554                         fprintf(stderr, "Gob version %s\n", VERSION);
4555                         exit(0);
4556                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
4557                         exit_on_warn = TRUE;
4558                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
4559                         exit_on_warn = FALSE;
4560                 } else if(strcmp(argv[i], "--for-cpp")==0) {
4561                         for_cpp = TRUE;
4562                 } else if(strcmp(argv[i], "--no-touch")==0) {
4563                         no_touch = TRUE;
4564                         no_touch_headers = TRUE;
4565                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
4566                         no_touch_headers = TRUE;
4567                 } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
4568                         private_header = PRIVATE_HEADER_ONDEMAND;
4569                 } else if(strcmp(argv[i], "--always-private-header")==0) {
4570                         private_header = PRIVATE_HEADER_ALWAYS;
4571                 } else if(strcmp(argv[i], "--no-private-header")==0) {
4572                         private_header = PRIVATE_HEADER_NEVER;
4573                 } else if(strcmp(argv[i], "--no-gnu")==0) {
4574                         no_gnu = TRUE;
4575                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
4576                         no_extern_c = TRUE;
4577                 } else if(strcmp(argv[i], "--no-write")==0) {
4578                         no_write = TRUE;
4579                 } else if(strcmp(argv[i], "--no-lines")==0) {
4580                         no_lines = TRUE;
4581                 } else if(strcmp(argv[i], "--no-self-alias")==0) {
4582                         no_self_alias = TRUE;
4583                 } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
4584                         /* no op */;
4585                 } else if(strcmp(argv[i], "--always-private-struct")==0) {
4586                         always_private_struct = TRUE;
4587                 } else if(strcmp(argv[i], "--m4-dir")==0) {
4588                         printf("%s\n",M4_INCLUDE_DIR);
4589                         exit(0);
4590                 } else if(strcmp(argv[i], "--m4")==0) {
4591                         use_m4 = TRUE;
4592                         use_m4_clean=FALSE;
4593                         m4_opts = TRUE;
4594                         m4_commandline=g_strdup(M4_COMMANDLINE);
4595                 } else if(strcmp(argv[i], "--m4-clean")==0) {
4596                         use_m4 = TRUE;
4597                         use_m4_clean=TRUE;
4598                         m4_opts = TRUE;
4599                         m4_commandline=g_strdup(M4_COMMANDLINE);
4600                 } else if (strcmp (argv[i], "-o") == 0 || 
4601                            strcmp (argv[i], "--output-dir") == 0) {
4602                         if (i+1 < argc) {
4603                                 output_dir = g_strdup (argv[i+1]);
4604                                 i++;
4605                         } else {
4606                                 output_dir = NULL;
4607                         }
4608                 } else if (strncmp (argv[i], "-o=", strlen ("-o=")) == 0 || 
4609                            strncmp (argv[i],
4610                                     "--output-dir=",
4611                                     strlen ("--output-dir=")) == 0) {
4612                         char *p = strchr (argv[i], '=');
4613                         g_assert (p != NULL);
4614                         output_dir = g_strdup (p+1);
4615                 } else if (strncmp (argv[i], "--file-sep=",
4616                                     strlen ("--file-sep=")) == 0) {
4617                         char *p = strchr (argv[i], '=');
4618                         g_assert (p != NULL);
4619                         file_sep = *(p+1);
4620                 } else if (strncmp (argv[i], "--file-sep",
4621                                     strlen ("--file-sep")) == 0) {
4622                         if (i+1 < argc) {
4623                                 file_sep = (argv[i+1])[0];
4624                                 i++;
4625                         } else {
4626                                 file_sep = 0;
4627                         }
4628                 } else if(strcmp(argv[i], "--gtk3")==0) {
4629                         gtk3_ok = TRUE;
4630                 } else if(strcmp(argv[i], "--")==0) {
4631                         /*further arguments are files*/
4632                         no_opts = TRUE;
4633                 } else if(strncmp(argv[i], "--", 2)==0) {
4634                         /*unknown long option*/
4635                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
4636                         print_help();
4637                         exit(1);
4638                 } else {
4639                         /*by now we know we have a string starting with
4640                           - which is a short option string*/
4641                         char *p;
4642                         for(p = argv[i] + 1; *p; p++) {
4643                                 switch(*p) {
4644                                 case 'w':
4645                                         exit_on_warn=TRUE;
4646                                         break;
4647                                 case 'n':
4648                                         no_write = TRUE;
4649                                         break;
4650                                 case 'h':
4651                                 case '?':
4652                                         print_help();
4653                                         exit(0);
4654                                 default:
4655                                         fprintf(stderr,
4656                                                 "Unknown option '%c'!\n", *p);
4657                                         print_help();
4658                                         exit(1);
4659                                 }
4660                         }
4661                 }
4662         }
4663
4664 #if 0
4665         /* if we are using m4, and got no filename, append m4 flags now */
4666         if(!got_file && use_m4 && !use_m4_clean) {
4667                 char *new_commandline;
4668                 new_commandline=g_strconcat(m4_commandline,
4669                                             " ",
4670                                             M4_FLAGS,
4671                                             NULL);
4672                 g_free(m4_commandline);
4673                 m4_commandline=new_commandline;
4674         }
4675 #endif
4676 }
4677
4678 static void
4679 compare_and_move (const char *old_filename)
4680 {
4681         char *new_filename = g_strconcat (old_filename, "#gob#", NULL);
4682         FILE *old_f;
4683         gboolean equal = FALSE;
4684
4685         old_f = fopen (old_filename, "r");
4686         if (old_f) {
4687                 FILE *new_f;
4688                 gboolean error = FALSE;
4689
4690                 new_f = fopen (new_filename, "r");
4691                 if (new_f) {
4692                         char new_buf[1024];
4693                         char old_buf[1024];
4694
4695                         while (TRUE) {
4696                                 size_t new_n;
4697                                 size_t old_n;
4698
4699                                 new_n = fread (new_buf, 1, sizeof (new_buf), new_f);
4700                                 if (ferror (new_f)) {
4701                                         error = TRUE;
4702                                         error_printf (GOB_ERROR, 0,
4703                                                       "Can't read %s: %s",
4704                                                       new_filename,
4705                                                       g_strerror (errno));
4706                                         break;
4707                                 }
4708
4709                                 old_n = fread (old_buf, 1, sizeof (old_buf), old_f);
4710                                 if (ferror (old_f)
4711                                     || feof (new_f) != feof (old_f)
4712                                     || new_n != old_n
4713                                     || memcmp (new_buf, old_buf, new_n) != 0)
4714                                         break;
4715
4716                                 if (feof (new_f)) {
4717                                         equal = TRUE;
4718                                         break;
4719                                 }
4720                         }
4721                 } else
4722                         error_printf (GOB_ERROR, 0, "Can't open %s: %s",
4723                                       new_filename, g_strerror (errno));
4724
4725                 fclose (old_f);
4726                 fclose (new_f);
4727
4728                 if (error)
4729                         goto end;
4730
4731                 if (! equal && unlink (old_filename) != 0) {
4732                         error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
4733                                       old_filename, g_strerror (errno));
4734                         goto end;
4735                 }
4736         }
4737
4738         if (equal) {
4739                 if (unlink (new_filename) != 0)
4740                         error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
4741                                       new_filename, g_strerror (errno));
4742         } else {
4743                 if (rename (new_filename, old_filename) != 0)
4744                         error_printf (GOB_ERROR, 0, "Can't rename %s to %s: %s",
4745                                       new_filename, old_filename,
4746                                       g_strerror (errno));
4747         }
4748
4749  end:
4750         g_free (new_filename);
4751 }
4752
4753 int
4754 main(int argc, char *argv[])
4755 {
4756         parse_options(argc, argv);
4757
4758         if(use_m4) {
4759                 yyin = popen(m4_commandline, "r");
4760                 if(!yyin) {
4761                         fprintf(stderr, "Error: can't open pipe from '%s'\n",
4762                                 m4_commandline);
4763                         exit(1);
4764                 }
4765         } else if(filename) {
4766                 yyin = fopen(filename, "r");
4767                 if(!yyin) {
4768                         fprintf(stderr, "Error: can't open file '%s'\n",
4769                                 filename);
4770                         exit(1);
4771                 }
4772         }
4773
4774         if(filename==NULL)
4775                 filename = "stdin";
4776
4777         /* This is where parsing is done */
4778         /*yydebug = 1;*/
4779         if(yyparse() != 0)
4780                 error_print (GOB_ERROR, 0, "Parsing errors, quitting");
4781
4782         /* close input file */
4783         if(use_m4) pclose(yyin);
4784         else fclose(yyin);
4785         yyin=stdin;
4786
4787         if( ! class)
4788                 error_print (GOB_ERROR, 0, "no class defined");
4789         
4790
4791         exit_on_error = FALSE;
4792
4793         signals = count_signals ((Class *)class);
4794         set_properties = count_set_properties ((Class *)class) +
4795                 count_set_arguments ((Class *)class);
4796         get_properties = count_get_properties ((Class *)class) +
4797                 count_get_arguments ((Class *)class);
4798         overrides = count_overrides ((Class *)class);
4799         privates = count_privates ((Class *)class);
4800         protecteds = count_protecteds ((Class *)class);
4801         unreftors = count_unreftors ((Class *)class);
4802         destructors = count_destructors ((Class *)class);
4803         initializers = count_initializers ((Class *)class);
4804         glade_widgets = count_glade_widgets ((Class *)class);
4805         overrode_get_type = find_get_type ((Class *)class);
4806
4807         make_bases ();
4808         make_inits ((Class *)class);
4809
4810         find_constructor ((Class *)class);
4811         if (user_constructor != NULL)
4812                 need_constructor = TRUE;
4813
4814         find_dispose ((Class *)class);
4815         if (unreftors > 0 ||
4816             dispose_handler != NULL ||
4817             user_dispose_method != NULL)
4818                 need_dispose = TRUE;
4819
4820         find_finalize ((Class *)class);
4821         if (destructors > 0 ||
4822             privates > 0 ||
4823             user_finalize_method != NULL) {
4824                 need_finalize = TRUE;
4825         }
4826
4827         check_bad_symbols ((Class *)class);
4828         check_duplicate_symbols ((Class *)class);
4829         check_duplicate_overrides ((Class *)class);
4830         check_duplicate_signals_args ((Class *)class);
4831         check_public_new ((Class *)class);
4832         check_vararg ((Class *)class);
4833         check_firstarg ((Class *)class);
4834         check_nonvoidempty ((Class *)class);
4835         check_signal_args ((Class *)class);
4836         check_property_types ((Class *)class);
4837         check_argument_types ((Class *)class);
4838         check_func_arg_checks ((Class *)class);
4839         check_func_attrs ((Class *)class);
4840         check_for_class_destructors ((Class *)class);
4841
4842         exit_on_error = TRUE;
4843         
4844         if (got_error)
4845                 exit (1);
4846
4847         any_special = setup_special_array ((Class *)class, special_array);
4848
4849         open_files ();
4850         
4851         generate_outfiles ();
4852
4853         if (out)
4854                 fclose (out);
4855         if (outh)
4856                 fclose (outh);
4857         if (outph)
4858                 fclose (outph);
4859
4860         if (! no_write) {
4861                 if (no_touch) {
4862                         compare_and_move (outfilebase);
4863                         if (outfilephbase)
4864                                 compare_and_move (outfilephbase);
4865                 }
4866                 if (no_touch_headers)
4867                         compare_and_move (outfilehbase);
4868         }
4869         
4870         return 0;
4871 }