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