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