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