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