]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
fab7a2e0d46c5cd718d9c4d4f96607c014b23738
[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-2009 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                                      "Overriden property, flags ignored");
1659                 if (p->nick != NULL)
1660                         error_print (GOB_WARN, p->line_no,
1661                                      "Overriden property, nick ignored");
1662                 if (p->blurb != NULL)
1663                         error_print (GOB_WARN, p->line_no,
1664                                      "Overriden property, blurb ignored");
1665                 if (p->minimum != NULL)
1666                         error_print (GOB_WARN, p->line_no,
1667                                      "Overriden property, minimum ignored");
1668                 if (p->maximum != NULL)
1669                         error_print (GOB_WARN, p->line_no,
1670                                      "Overriden property, maximum ignored");
1671                 if (p->default_value != NULL)
1672                         error_print (GOB_WARN, p->line_no,
1673                                      "Overriden 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 C_CCODE:
3394                 fp = out;
3395                 out_printf(fp, "\n");
3396                 out_addline_infile(fp, cc->line_no);
3397                 break;
3398         case PH_CCODE:
3399                 if(outph)
3400                         fp = outph;
3401                 else
3402                         fp = out;
3403                 out_printf(fp, "\n");
3404                 out_addline_infile(fp, cc->line_no);
3405                 break;
3406         }
3407         out_printf(fp, "%s\n", cc->cbuf);
3408         if(cc->cctype == C_CCODE ||
3409            cc->cctype == AD_CCODE ||
3410            cc->cctype == A_CCODE ||
3411            cc->cctype == AT_CCODE ||
3412            cc->cctype == PH_CCODE)
3413                 out_addline_outfile(fp);
3414 }
3415
3416 static void
3417 print_class_block(Class *c)
3418 {
3419         GList *li;
3420         char *s;
3421         gboolean printed_private = FALSE;
3422
3423         if (c->glade_xml)
3424         {
3425                 out_printf(outph ? outph : outh, "#include <gtk/gtk.h>\n");
3426                 out_printf(outph ? outph : outh, "#include <glade/glade-xml.h>\n\n");
3427         }
3428         
3429         if(any_special) {
3430                 out_printf(out, "/* utility types we may need */\n");
3431                 if(special_array[SPECIAL_2POINTER])
3432                         out_printf(out, "typedef struct { "
3433                                    "gpointer a; gpointer b; "
3434                                    "} ___twopointertype;\n");
3435                 if(special_array[SPECIAL_3POINTER])
3436                         out_printf(out, "typedef struct { "
3437                                    "gpointer a; gpointer b; "
3438                                    "gpointer c; "
3439                                    "} ___threepointertype;\n");
3440                 if(special_array[SPECIAL_INT_POINTER])
3441                         out_printf(out, "typedef struct { "
3442                                    "gint a; gpointer b; "
3443                                    "} ___intpointertype;\n");
3444                 out_printf(out, "\n");
3445         }
3446
3447         out_printf(outh, "\n/*\n"
3448                    " * Type checking and casting macros\n"
3449                    " */\n");
3450         out_printf(outh, "#define %s\t"
3451                    "(%s_get_type())\n",
3452                    macrotype, funcbase);
3453         out_printf(outh, "#define %s(obj)\t"
3454                    "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s)\n",
3455                    macrobase, funcbase, typebase);
3456         out_printf(outh, "#define %s_CONST(obj)\t"
3457                    "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s const)\n",
3458                    macrobase, funcbase, typebase); 
3459         out_printf(outh, "#define %s_CLASS(klass)\t"
3460                    "G_TYPE_CHECK_CLASS_CAST((klass), %s_get_type(), %sClass)\n",
3461                    macrobase, funcbase, typebase);
3462         out_printf(outh, "#define %s(obj)\t"
3463                    "G_TYPE_CHECK_INSTANCE_TYPE((obj), %s_get_type ())\n\n",
3464                    macrois, funcbase);
3465         out_printf(outh,
3466                    "#define %s_GET_CLASS(obj)\t"
3467                    "G_TYPE_INSTANCE_GET_CLASS((obj), %s_get_type(), %sClass)\n",
3468                    macrobase, funcbase, typebase);
3469
3470         if ( ! no_self_alias) {
3471                 out_printf(out, "/* self casting macros */\n");
3472                 out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
3473                 out_printf(out, "#define SELF_CONST(x) %s_CONST(x)\n", macrobase);
3474                 out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
3475                 out_printf(out, "#define TYPE_SELF %s\n", macrotype);
3476                 out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n",
3477                            macrobase);
3478                 out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n",
3479                            macrobase);
3480
3481                 out_printf(out, "/* self typedefs */\n");
3482                 out_printf(out, "typedef %s Self;\n", typebase);
3483                 out_printf(out, "typedef %sClass SelfClass;\n\n", typebase);
3484         }
3485
3486         if (privates > 0 ||
3487             always_private_struct) {
3488                 out_printf (outh, "\n/* Private structure type */\n");
3489                 out_printf (outh, "typedef struct _%sPrivate %sPrivate;\n",
3490                            typebase, typebase);
3491                 if (privates == 0)
3492                         out_printf (outh, "/* There are no privates, this "
3493                                     "structure is thus never defined */\n");
3494         }
3495
3496         out_printf (outh, "\n/*\n"
3497                     " * Main object structure\n"
3498                     " */\n");
3499         s = replace_sep (c->otype, '_');
3500         gob_strup (s);
3501         out_printf (outh, "#ifndef __TYPEDEF_%s__\n"
3502                     "#define __TYPEDEF_%s__\n", s, s);
3503         g_free (s);
3504         out_printf (outh, "typedef struct _%s %s;\n"
3505                     "#endif\n", typebase, typebase);
3506         out_printf (outh, "struct _%s {\n\t%s __parent__;\n",
3507                     typebase, ptypebase);
3508         for (li = c->nodes; li; li=li->next) {
3509                 static gboolean printed_public = FALSE;
3510                 Node *n = li->data;
3511                 Variable *v = (Variable *)n;
3512                 if(n->type == VARIABLE_NODE &&
3513                    v->scope == PUBLIC_SCOPE) {
3514                         if( ! printed_public) {
3515                                 out_printf(outh, "\t/*< public >*/\n");
3516                                 printed_public = TRUE;
3517                         }
3518                         put_variable((Variable *)n, outh);
3519                 }
3520         }
3521         /* put protecteds always AFTER publics */
3522         for (li = c->nodes; li != NULL; li = li->next) {
3523                 Node *n = li->data;
3524                 Variable *v = (Variable *)n;
3525                 if (n->type == VARIABLE_NODE &&
3526                     v->scope == PROTECTED_SCOPE) {
3527                         if ( ! printed_private) {
3528                                 out_printf (outh, "\t/*< private >*/\n");
3529                                 printed_private = TRUE;
3530                         }
3531                         put_variable ((Variable *)n, outh);
3532                 }
3533         }
3534         if (privates > 0 ||
3535             always_private_struct) {
3536                 if ( ! printed_private)
3537                         out_printf (outh, "\t/*< private >*/\n");
3538                 out_printf (outh, "\t%sPrivate *_priv;\n", typebase);
3539         }
3540         out_printf (outh, "};\n");
3541
3542         if (privates > 0) {
3543                 FILE *outfp;
3544
3545                 /* if we are to stick this into the private
3546                    header, if not stick it directly into the
3547                    C file */
3548                 if (outph != NULL) 
3549                         outfp = outph;
3550                 else
3551                         outfp = out;
3552
3553                 out_printf (outfp, "struct _%sPrivate {\n",
3554                             typebase);
3555                 if (privates > 0)
3556                 {
3557                  for(li=c->nodes; li; li=li->next) {
3558                          Node *n = li->data;
3559                          Variable *v = (Variable *)n;
3560                          if(n->type == VARIABLE_NODE &&
3561                                         v->scope == PRIVATE_SCOPE) {
3562                                  out_addline_infile(outfp, v->line_no);
3563                                  put_variable(v, outfp);
3564                          }
3565                         }
3566                         out_addline_outfile(outfp);
3567                 }
3568                 out_printf(outfp, "};\n");
3569         }
3570
3571         out_printf(outh, "\n/*\n"
3572                    " * Class definition\n"
3573                    " */\n");
3574         out_printf(outh, "typedef struct _%sClass %sClass;\n",
3575                    typebase, typebase);
3576         out_printf(outh,
3577                    "struct _%sClass {\n\t%sClass __parent__;\n",
3578                    typebase, ptypebase);
3579         for(li = c->nodes; li != NULL; li = li->next) {
3580                 Node *n = li->data;
3581                 if(n->type == METHOD_NODE)
3582                         put_vs_method((Method *)n);
3583         }
3584         /* If BonoboX type class put down the epv */
3585         if (c->bonobo_object_class != NULL) {
3586                 out_printf (outh,
3587                             "\t/* Bonobo object epv */\n"
3588                             "\tPOA_%s__epv _epv;\n",
3589                             c->bonobo_object_class);
3590         }
3591         /* put class scope variables */
3592         for (li = c->nodes; li != NULL; li = li->next) {
3593                 Node *n = li->data;
3594                 Variable *v = (Variable *)n;
3595                 if (n->type == VARIABLE_NODE &&
3596                     v->scope == CLASS_SCOPE)
3597                         put_variable ((Variable *)n, outh);
3598         }
3599         out_printf (outh, "};\n\n");
3600
3601         out_printf (out, "/* here are local prototypes */\n");
3602         if (set_properties > 0) {
3603                 out_printf (out, "static void ___object_set_property "
3604                             "(GObject *object, guint property_id, "
3605                             "const GValue *value, GParamSpec *pspec);\n");
3606         }
3607         if (get_properties > 0) {
3608                 out_printf (out, "static void ___object_get_property "
3609                             "(GObject *object, guint property_id, "
3610                             "GValue *value, GParamSpec *pspec);\n");
3611         }
3612
3613         out_printf (outh, "\n/*\n"
3614                     " * Public methods\n"
3615                     " */\n");
3616
3617         if ( ! overrode_get_type) {
3618                 out_printf (outh, "GType\t%s_get_type\t(void) G_GNUC_CONST;\n", funcbase);
3619         }
3620
3621         for(li = c->nodes; li != NULL; li = li->next) {
3622                 Node *n = li->data;
3623                 if(n->type == METHOD_NODE) {
3624                         put_pub_method((Method *)n);
3625                         put_prot_method((Method *)n);
3626                         put_priv_method_prot((Method *)n);
3627                 }
3628         }
3629
3630         /* this idea is less and less apealing to me */
3631         if (signals > 0) {
3632                 out_printf (outh, "\n/*\n"
3633                             " * Signal connection wrapper macros\n"
3634                             " */\n");
3635                 if( ! no_gnu) {
3636                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
3637                         put_signal_macros (c, TRUE);
3638                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
3639                         put_signal_macros (c, FALSE);
3640                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n");
3641                 } else {
3642                         put_signal_macros (c, FALSE);
3643                         out_printf(outh, "\n");
3644                 }
3645
3646                 out_printf (out, "\n/*\n"
3647                             " * Signal connection wrapper macro shortcuts\n"
3648                             " */\n");
3649                 put_local_signal_macros (c);
3650                 out_printf(outh, "\n");
3651         }
3652
3653         /* argument wrapping macros */
3654         if(get_properties > 0 || set_properties > 0) {
3655                 out_printf(outh, "\n/*\n"
3656                            " * Argument wrapping macros\n"
3657                            " */\n");
3658                 if( ! no_gnu) {
3659                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
3660                         put_argument_gnu_wrappers(c);
3661                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
3662                         put_argument_nongnu_wrappers(c);
3663                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
3664                 } else {
3665                         put_argument_nongnu_wrappers(c);
3666                 }
3667         }
3668
3669         if(signals > 0) {
3670                 for(li = c->nodes; li != NULL; li = li->next) {
3671                         Node *n = li->data;
3672                         if(n->type == METHOD_NODE)
3673                                 add_signal_prots((Method *)n);
3674                 }
3675         }
3676
3677         add_enums (c);
3678
3679         if(any_method_to_alias(c)) {
3680                 out_printf (out, "/* Short form macros */\n");
3681                 make_method_aliases (c);
3682         }
3683
3684         add_interface_inits (c);
3685
3686         if ( ! overrode_get_type) {
3687                 if (c->bonobo_object_class != NULL)
3688                         add_bonobo_object_get_type ();
3689                 else
3690                         add_get_type ();
3691         }
3692
3693         out_printf (out, "/* a macro for creating a new object of our type */\n");
3694         out_printf (out,
3695                     "#define GET_NEW ((%s *)g_object_new(%s_get_type(), NULL))\n\n",
3696                     typebase, funcbase);
3697
3698         out_printf (out, "/* a function for creating a new object of our type */\n");
3699         out_printf (out, "#include <stdarg.h>\n");
3700         out_printf (out,
3701                     "static %s * GET_NEW_VARG (const char *first, ...)%s;\n"
3702                     "static %s *\nGET_NEW_VARG (const char *first, ...)\n"
3703                     "{\n\t%s *ret;\n\tva_list ap;\n"
3704                     "\tva_start (ap, first);\n"
3705                     "\tret = (%s *)g_object_new_valist (%s_get_type (), "
3706                     "first, ap);\n"
3707                     "\tva_end (ap);\n"
3708                     "\treturn ret;\n}\n\n",
3709                     typebase,
3710                     no_gnu ? "" : " G_GNUC_UNUSED",
3711                     typebase, typebase, typebase, funcbase);
3712
3713         if (c->glade_xml)
3714         {
3715                 out_printf (out, "/* a function to connect glade callback */\n");
3716                 out_printf (out,"static void\n"
3717                             "___glade_xml_connect_foreach(const gchar *handler_name,\n"
3718                             "GObject *object,\n"
3719                             "const gchar *signal_name,\n"
3720                             "const gchar *signal_data,\n"
3721                             "GObject *connect_object,\n"
3722                             "gboolean after,\n"
3723                             "gpointer user_data)\n"
3724                             "{\n"
3725                             "\tstatic GModule * allsymbols = NULL;\n"
3726                             "   \n"
3727                             "\tif (!allsymbols) allsymbols = g_module_open(NULL, 0);\n"
3728                             "\tif (allsymbols) {\n"
3729                             "\t\tgchar * func_name = g_strdup_printf(\"%s_%%s\", handler_name);\n"
3730                             "\t\tGCallback func;\n"
3731                             "\n"
3732                             "\t\tif (!g_module_symbol(allsymbols, func_name, (gpointer)&func)){\n"
3733                             "\t\t\tif (!g_module_symbol(allsymbols, handler_name, (gpointer)&func)) {\n"
3734                             "\t\t\t\tg_warning(\"could not find signal handler '%%s'.\", func_name);\n"
3735                             "\t\t\t\tg_free(func_name);\n"
3736                             "\t\t\t\treturn;\n"
3737                             "\t\t\t}\n"
3738                             "\t\t}\n"
3739                             "\t\tif (after)\n"
3740                             "\t\t\tg_signal_connect_data(object, signal_name, func, user_data, NULL, G_CONNECT_AFTER | G_CONNECT_SWAPPED);\n"
3741                             "\t\telse\n"
3742                             "\t\t\tg_signal_connect_data(object, signal_name, func, user_data, NULL, G_CONNECT_SWAPPED);\n"
3743                             "\t\tg_free(func_name);\n"
3744                             "\t}\n"
3745                             "}\n"
3746                             "\n",
3747                             funcbase);
3748         }
3749
3750         for (li = nodes; li != NULL; li = li->next) {
3751                 Node *node = li->data;
3752                 if (node->type == CCODE_NODE) {
3753                         CCode *cc = (CCode *)node;
3754                         if (cc->cctype == AD_CCODE)
3755                                 print_ccode_block (cc);
3756                 }
3757         }
3758
3759         if (need_constructor)
3760                 add_constructor (c);
3761
3762         if (need_dispose)
3763                 add_dispose (c);
3764
3765         if (need_finalize)
3766                 add_finalize (c);
3767
3768         add_inits(c);
3769
3770         if(set_properties > 0) {
3771                 add_getset_arg(c, TRUE);
3772         }
3773
3774         if(get_properties > 0) {
3775                 add_getset_arg(c, FALSE);
3776         }
3777
3778         for(li = c->nodes; li != NULL; li = li->next) {
3779                 Node *n = li->data;
3780                 if(n->type == METHOD_NODE)
3781                         put_method((Method *)n);
3782         }
3783
3784         add_bad_hack_to_avoid_unused_warnings(c);
3785 }
3786
3787 static void
3788 print_useful_macros(void)
3789 {
3790         int major = 0, minor = 0, pl = 0;
3791
3792         /* Version stuff */
3793         sscanf (VERSION, "%d.%d.%d", &major, &minor, &pl);
3794         out_printf (out, "#define GOB_VERSION_MAJOR %d\n", major);
3795         out_printf (out, "#define GOB_VERSION_MINOR %d\n", minor);
3796         out_printf (out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
3797
3798         /* Useful priv macro thingie */
3799         /* FIXME: this should be done the same way that priv is, as a var,
3800          * not a define */
3801         out_printf (out, "#define selfp (self->_priv)\n\n");
3802 }
3803
3804 static void
3805 print_more_useful_macros (void)
3806 {
3807         if (no_gnu) {
3808                 out_printf (out, "#define ___GOB_LIKELY(expr) (expr)\n");
3809                 out_printf (out, "#define ___GOB_UNLIKELY(expr) (expr)\n");
3810         } else {
3811                 out_printf (out, "#ifdef G_LIKELY\n");
3812                 out_printf (out, "#define ___GOB_LIKELY(expr) G_LIKELY(expr)\n");
3813                 out_printf (out, "#define ___GOB_UNLIKELY(expr) G_UNLIKELY(expr)\n");
3814                 out_printf (out, "#else /* ! G_LIKELY */\n");
3815                 out_printf (out, "#define ___GOB_LIKELY(expr) (expr)\n");
3816                 out_printf (out, "#define ___GOB_UNLIKELY(expr) (expr)\n");
3817                 out_printf (out, "#endif /* G_LIKELY */\n");
3818         }
3819 }
3820
3821 static void
3822 print_file_comments(void)
3823 {
3824         out_printf(outh, "/* Generated by GOB (v%s)"
3825                    "   (do not edit directly) */\n\n", VERSION);
3826         if(outph)
3827                 out_printf(outph, "/* Generated by GOB (v%s)"
3828                            "   (do not edit directly) */\n\n", VERSION);
3829         out_printf(out, "/* Generated by GOB (v%s)"
3830                    "   (do not edit directly) */\n\n", VERSION);
3831
3832         out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
3833 }
3834
3835 static void
3836 print_includes(void)
3837 {
3838         gboolean found_header;
3839         char *p;
3840
3841         /* We may need string.h for memset */
3842         if ( ! g_list_find_custom(include_files, "string.h", (GCompareFunc)strcmp)) {
3843                 out_printf(out, "#include <string.h> /* memset() */\n\n");
3844         }
3845
3846         p = g_strconcat(filebase, ".h", NULL);
3847         found_header = TRUE;
3848         if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
3849                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
3850                 found_header = FALSE;
3851         }
3852         g_free(p);
3853
3854         /* if we are creating a private header see if it was included */
3855         if(outph) {
3856                 char sep[2] = {0,0};
3857                 if (file_sep != 0)
3858                         sep[0] = file_sep;
3859                 p = g_strconcat(filebase, sep, "private.h", NULL);
3860                 if( ! g_list_find_custom(include_files, p,
3861                                          (GCompareFunc)strcmp)) {
3862                         out_printf(out, "#include \"%s%cprivate.h\"\n\n",
3863                                    filebase,
3864                                    file_sep);
3865                         if(found_header)
3866                                 error_printf(GOB_WARN, 0,
3867                                             "Implicit private header include "
3868                                             "added to top of\n"
3869                                             "\tsource file, while public "
3870                                             "header is at a custom location, "
3871                                             "you should\n"
3872                                             "\texplicitly include "
3873                                             "the private header below the "
3874                                             "public one.");
3875                 }
3876                 g_free(p);
3877         }
3878 }
3879
3880 static void
3881 print_header_prefixes(void)
3882 {
3883         char *p;
3884
3885         p = replace_sep(((Class *)class)->otype, '_');
3886         gob_strup (p);
3887         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
3888         if(outph)
3889                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
3890                            "#define __%s_PRIVATE_H__\n\n"
3891                            "#include \"%s.h\"\n\n", p, p, filebase);
3892         g_free(p);
3893
3894         if( ! no_extern_c) {
3895                 out_printf(outh, "#ifdef __cplusplus\n"
3896                            "extern \"C\" {\n"
3897                            "#endif /* __cplusplus */\n\n");
3898                 if(outph)
3899                         out_printf(outph, "#ifdef __cplusplus\n"
3900                                    "extern \"C\" {\n"
3901                                    "#endif /* __cplusplus */\n\n");
3902         }
3903 }
3904
3905 static void
3906 print_header_postfixes(void)
3907 {
3908         if( ! no_extern_c)
3909                 out_printf(outh, "\n#ifdef __cplusplus\n"
3910                            "}\n"
3911                            "#endif /* __cplusplus */\n");
3912         out_printf(outh, "\n#endif\n");
3913         if(outph) {
3914                 if( ! no_extern_c)
3915                         out_printf(outph, "\n#ifdef __cplusplus\n"
3916                                    "}\n"
3917                                    "#endif /* __cplusplus */\n");
3918                 out_printf(outph, "\n#endif\n");
3919         }
3920 }
3921
3922 static void
3923 print_all_top(void)
3924 {
3925         GList *li;
3926
3927         /* print the AT_CCODE blocks */
3928         for(li = nodes; li != NULL; li = li->next) {
3929                 Node *node = li->data;
3930                 if(node->type == CCODE_NODE) {
3931                         CCode *cc = (CCode *)node;
3932                         if(cc->cctype == AT_CCODE)
3933                                 print_ccode_block((CCode *)node);
3934                 }
3935         }
3936 }
3937
3938 static void
3939 print_header_top(void)
3940 {
3941         GList *li;
3942
3943         /* mandatory includes */
3944         out_printf (outh, "#include <glib.h>\n");
3945         out_printf (outh, "#include <glib-object.h>\n");
3946
3947         /* print the HT_CCODE blocks */
3948         for (li = nodes; li != NULL; li = li->next) {
3949                 Node *node = li->data;
3950                 if (node->type == CCODE_NODE) {
3951                         CCode *cc = (CCode *)node;
3952                         if (cc->cctype == HT_CCODE)
3953                                 print_ccode_block ((CCode *)node);
3954                 }
3955         }
3956 }
3957
3958 static void
3959 print_enum (EnumDef *enode)
3960 {
3961         GList *li;
3962         char *funcprefix;
3963         char *type;
3964         char *str;
3965
3966         funcprefix = replace_sep (enode->etype, '_');
3967         gob_strdown (funcprefix);
3968         out_printf (out, "static const GEnumValue _%s_values[] = {\n",
3969                     funcprefix);
3970         type = remove_sep (enode->etype);
3971
3972         out_printf (outh, "\ntypedef enum {\n");
3973
3974         for (li = enode->values; li != NULL; li = li->next) {
3975                 EnumValue *value = li->data; 
3976                 char *p;
3977                 char *sname = gob_strdown (g_strdup (value->name));
3978
3979                 while ((p = strchr (sname, '_')) != NULL)
3980                         *p = '-';
3981
3982                 out_printf (outh, "\t%s_%s", enode->prefix, value->name);
3983                 if (value->value != NULL)
3984                         out_printf (outh, " = %s", value->value);
3985                 if (li->next != NULL)
3986                         out_printf (outh, ",\n");
3987                 else
3988                         out_printf (outh, "\n");
3989
3990                 out_printf (out, "\t{ %s_%s, (char *)\"%s_%s\", (char *)\"%s\" },\n",
3991                             enode->prefix, value->name,
3992                             enode->prefix, value->name,
3993                             sname);
3994
3995                 g_free (sname);
3996         }
3997
3998         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
3999
4000         out_printf (outh, "} %s;\n", type);
4001
4002         str = make_pre_macro (enode->etype, "TYPE");
4003         out_printf (outh, "#define %s ", str);
4004         g_free (str);
4005
4006         out_printf (outh, "%s_get_type()\n", funcprefix);
4007         out_printf (outh, "GType %s_get_type (void) G_GNUC_CONST;\n\n", funcprefix);
4008
4009         out_printf (out,
4010                     "GType\n%s_get_type (void)\n"
4011                     "{\n"
4012                     "\tstatic GType type = 0;\n"
4013                     "\tif ___GOB_UNLIKELY(type == 0)\n"
4014                     "\t\ttype = g_enum_register_static (\"%s\", _%s_values);\n"
4015                     "\treturn type;\n"
4016                     "}\n\n",
4017                     funcprefix, type, funcprefix);
4018
4019         g_free (funcprefix);
4020         g_free (type);
4021 }
4022
4023 static void
4024 print_flags (Flags *fnode)
4025 {
4026         GList *li;
4027         char *funcprefix;
4028         char *type;
4029         char *str;
4030         int i;
4031
4032         funcprefix = replace_sep (fnode->ftype, '_');
4033         gob_strdown (funcprefix);
4034         out_printf (out, "static const GFlagsValue _%s_values[] = {\n",
4035                     funcprefix);
4036         type = remove_sep (fnode->ftype);
4037
4038         out_printf (outh, "\ntypedef enum {\n");
4039
4040         for (i = 0, li = fnode->values; li != NULL; i++, li = li->next) {
4041                 const char *name = li->data; 
4042                 char *p;
4043                 char *sname = gob_strdown (g_strdup (name));
4044
4045                 while ((p = strchr (sname, '_')) != NULL)
4046                         *p = '-';
4047
4048                 out_printf (outh, "\t%s_%s = 1<<%d",
4049                             fnode->prefix, name, i);
4050                 if (li->next != NULL)
4051                         out_printf (outh, ",\n");
4052                 else
4053                         out_printf (outh, "\n");
4054
4055                 out_printf (out, "\t{ %s_%s, (char *)\"%s_%s\", (char *)\"%s\" },\n",
4056                             fnode->prefix, name,
4057                             fnode->prefix, name,
4058                             sname);
4059
4060                 g_free (sname);
4061         }
4062
4063         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
4064
4065         out_printf (outh, "} %s;\n", type);
4066
4067         str = make_pre_macro (fnode->ftype, "TYPE");
4068         out_printf (outh, "#define %s ", str);
4069         g_free (str);
4070
4071         out_printf (outh, "%s_get_type()\n", funcprefix);
4072         out_printf (outh, "GType %s_get_type (void) G_GNUC_CONST;\n\n", funcprefix);
4073
4074         out_printf (out,
4075                     "GType\n%s_get_type (void)\n"
4076                     "{\n"
4077                     "\tstatic GType type = 0;\n"
4078                     "\tif ___GOB_UNLIKELY(type == 0)\n"
4079                     "\t\ttype = g_flags_register_static (\"%s\", _%s_values);\n"
4080                     "\treturn type;\n"
4081                     "}\n\n",
4082                     funcprefix, type, funcprefix);
4083
4084         g_free (funcprefix);
4085         g_free (type);
4086 }
4087
4088 static void
4089 print_error (Error *enode)
4090 {
4091         GList *li;
4092         char *funcprefix;
4093         char *type;
4094         char *str;
4095
4096         funcprefix = replace_sep (enode->etype, '_');
4097         gob_strdown (funcprefix);
4098         out_printf (out, "static const GEnumValue _%s_values[] = {\n",
4099                     funcprefix);
4100         type = remove_sep (enode->etype);
4101
4102         out_printf (outh, "\ntypedef enum {\n");
4103
4104         for (li = enode->values; li != NULL; li = li->next) {
4105                 const char *name = li->data;
4106                 char *p;
4107                 char *sname = gob_strdown (g_strdup (name));
4108
4109                 while ((p = strchr (sname, '_')) != NULL)
4110                         *p = '-';
4111
4112                 out_printf (outh, "\t%s_%s", enode->prefix, name);
4113                 if (li->next != NULL)
4114                         out_printf (outh, ",\n");
4115                 else
4116                         out_printf (outh, "\n");
4117
4118                 out_printf (out, "\t{ %s_%s, (char *)\"%s_%s\", (char *)\"%s\" },\n",
4119                             enode->prefix, name,
4120                             enode->prefix, name,
4121                             sname);
4122
4123                 g_free (sname);
4124         }
4125
4126         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
4127
4128         out_printf (outh, "} %s;\n", type);
4129
4130         str = make_pre_macro (enode->etype, "TYPE");
4131         out_printf (outh, "#define %s ", str);
4132         g_free (str);
4133
4134         out_printf (outh, "%s_get_type ()\n", funcprefix);
4135         out_printf (outh, "GType %s_get_type (void) G_GNUC_CONST;\n\n", funcprefix);
4136
4137         out_printf (out,
4138                     "GType\n%s_get_type (void)\n"
4139                     "{\n"
4140                     "\tstatic GType type = 0;\n"
4141                     "\tif ___GOB_UNLIKELY(type == 0)\n"
4142                     "\t\ttype = g_enum_register_static (\"%s\", _%s_values);\n"
4143                     "\treturn type;\n"
4144                     "}\n\n",
4145                     funcprefix, type, funcprefix);
4146
4147         out_printf (outh, "#define %s %s_quark ()\n", enode->prefix, funcprefix);
4148         out_printf (outh, "GQuark %s_quark (void);\n\n", funcprefix);
4149
4150         str = replace_sep (enode->etype, '-');
4151         gob_strdown (str);
4152
4153         out_printf (out,
4154                     "GQuark\n%s_quark (void)\n"
4155                     "{\n"
4156                     "\tstatic GQuark q = 0;\n"
4157                     "\tif (q == 0)\n"
4158                     "\t\tq = g_quark_from_static_string (\"%s\");\n"
4159                     "\treturn q;\n"
4160                     "}\n\n",
4161                     funcprefix, str);
4162
4163         g_free (str);
4164
4165         g_free (funcprefix);
4166         g_free (type);
4167 }
4168
4169 static void
4170 generate_outfiles(void)
4171 {
4172         GList *li;
4173
4174         print_file_comments();
4175
4176         print_all_top();
4177
4178         print_header_top();
4179
4180         print_header_prefixes();
4181
4182         print_useful_macros();
4183
4184         print_includes();
4185
4186         print_more_useful_macros ();
4187
4188         for (li = nodes; li != NULL; li = li->next) {
4189                 Node *node = li->data;
4190                 if (node->type == CCODE_NODE) {
4191                         CCode *cc = (CCode *)node;
4192                         if (cc->cctype != HT_CCODE &&
4193                             cc->cctype != AT_CCODE &&
4194                             cc->cctype != AD_CCODE)
4195                                 print_ccode_block ((CCode *)node);
4196                 } else if (node->type == CLASS_NODE) {
4197                         print_class_block ((Class *)node);
4198                 } else if (node->type == ENUMDEF_NODE) {
4199                         print_enum ((EnumDef *)node);
4200                 } else if (node->type == FLAGS_NODE) {
4201                         print_flags ((Flags *)node);
4202                 } else if (node->type == ERROR_NODE) {
4203                         print_error ((Error *)node);
4204                 } else {
4205                         g_assert_not_reached();
4206                 }
4207         }
4208
4209         print_header_postfixes();
4210 }
4211
4212 static void
4213 print_help(void)
4214 {
4215         fprintf(stderr, "Gob version %s\n\n", VERSION);
4216         fprintf(stderr, "gob [options] file.gob\n\n");
4217         fprintf(stderr, "Options:\n"
4218                 "\t--help,-h,-?            Display this help\n"
4219                 "\t--version               Display version\n"
4220                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
4221                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
4222                 "\t--for-cpp               Create C++ files\n"
4223                 "\t--no-extern-c           Never print extern \"C\" into the "
4224                                           "header\n"
4225                 "\t--no-gnu                Never use GNU extentions\n"
4226                 "\t--no-touch              Don't touch output files unless they "
4227                                           "really\n"
4228                 "\t                        changed (implies --no-touch-headers)\n"
4229                 "\t--no-touch-headers      Don't touch headers unless they "
4230                                           "really changed\n"
4231                 "\t--always-private-header Always create a private header "
4232                                           "file,\n"
4233                 "\t                        even if it would be empty\n"
4234                 "\t--ondemand-private-header Create private header only when "
4235                                           "needed\n"
4236                 "\t                        [default]\n"
4237                 "\t--no-private-header     Don't create a private header, "
4238                                           "put private\n"
4239                 "\t                        structure and protected "
4240                                           "prototypes inside c file\n"
4241                 "\t--always-private-struct Always create a private pointer "
4242                                           "in\n"
4243                 "\t                        the object structure\n"
4244                 "\t--m4                    Preprocess source with m4. "
4245                                           "Following args will\n"
4246                 "\t                        be passed to m4\n"
4247                 "\t--m4-dir                Print directory that will be "
4248                                           "searched for m4\n"
4249                 "\t                        files\n"
4250                 "\t--no-write,-n           Don't write output files, just "
4251                                           "check syntax\n"
4252                 "\t--no-lines              Don't print '#line' to output\n"
4253                 "\t--no-self-alias         Don't create self type and macro "
4254                                           "aliases\n"
4255                 "\t--no-kill-underscores   Ignored for compatibility\n"
4256                 "\t-o,--output-dir         The directory where output "
4257                                           "should be placed\n"
4258                 "\t--file-sep[=c]          replace default \'-\' file "
4259                                           "name separator\n\n");
4260         fprintf(stderr, "End world hunger, donate to the World Food Programme, http://www.wfp.org\n");
4261 }
4262
4263 static void
4264 parse_options(int argc, char *argv[])
4265 {
4266         int i;
4267         int got_file = FALSE;
4268         int no_opts = FALSE;
4269         int m4_opts = FALSE; /* if we are just passing on args to m4 */
4270
4271         filename = NULL;
4272
4273         for(i = 1 ; i < argc; i++) {
4274                 if(m4_opts) {
4275                         char *new_commandline;
4276                         g_assert(m4_commandline!=NULL);
4277
4278                         /* check whether this one looks like the filename */
4279                         if((!strcmp(argv[i],"-") || argv[i][0] != '-') 
4280                            && !got_file) {
4281                                 const gchar *m4_flags=use_m4_clean?"":M4_FLAGS;
4282                                 filename = argv[i];
4283                                 got_file = TRUE;
4284                                 
4285                                 /* insert flags before the filename */
4286                                 new_commandline=g_strconcat(m4_commandline,
4287                                                             " ",
4288                                                             m4_flags, 
4289                                                             " ",
4290                                                             argv[i],
4291                                                             NULL);
4292                         }
4293
4294                         /* just an ordinary option */
4295                         else                      
4296                           new_commandline=g_strconcat(m4_commandline,
4297                                                       " ",
4298                                                       argv[i],
4299                                                       NULL);
4300
4301                         /* free old commandline */
4302                         g_free(m4_commandline);
4303                         m4_commandline=new_commandline;
4304
4305                 } else if(no_opts ||
4306                    argv[i][0] != '-') {
4307                         /*must be a file*/
4308                         if(got_file) {
4309                                 fprintf(stderr, "Specify only one file!\n");
4310                                 print_help();
4311                                 exit(1);
4312                         }
4313                         filename = argv[i];
4314                         got_file = TRUE;
4315                 } else if(strcmp(argv[i], "--help")==0) {
4316                         print_help();
4317                         exit(0);
4318                 } else if(strcmp(argv[i], "--version")==0) {
4319                         fprintf(stderr, "Gob version %s\n", VERSION);
4320                         exit(0);
4321                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
4322                         exit_on_warn = TRUE;
4323                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
4324                         exit_on_warn = FALSE;
4325                 } else if(strcmp(argv[i], "--for-cpp")==0) {
4326                         for_cpp = TRUE;
4327                 } else if(strcmp(argv[i], "--no-touch")==0) {
4328                         no_touch = TRUE;
4329                         no_touch_headers = TRUE;
4330                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
4331                         no_touch_headers = TRUE;
4332                 } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
4333                         private_header = PRIVATE_HEADER_ONDEMAND;
4334                 } else if(strcmp(argv[i], "--always-private-header")==0) {
4335                         private_header = PRIVATE_HEADER_ALWAYS;
4336                 } else if(strcmp(argv[i], "--no-private-header")==0) {
4337                         private_header = PRIVATE_HEADER_NEVER;
4338                 } else if(strcmp(argv[i], "--no-gnu")==0) {
4339                         no_gnu = TRUE;
4340                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
4341                         no_extern_c = TRUE;
4342                 } else if(strcmp(argv[i], "--no-write")==0) {
4343                         no_write = TRUE;
4344                 } else if(strcmp(argv[i], "--no-lines")==0) {
4345                         no_lines = TRUE;
4346                 } else if(strcmp(argv[i], "--no-self-alias")==0) {
4347                         no_self_alias = TRUE;
4348                 } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
4349                         /* no op */;
4350                 } else if(strcmp(argv[i], "--always-private-struct")==0) {
4351                         always_private_struct = TRUE;
4352                 } else if(strcmp(argv[i], "--m4-dir")==0) {
4353                         printf("%s\n",M4_INCLUDE_DIR);
4354                         exit(0);
4355                 } else if(strcmp(argv[i], "--m4")==0) {
4356                         use_m4 = TRUE;
4357                         use_m4_clean=FALSE;
4358                         m4_opts = TRUE;
4359                         m4_commandline=g_strdup(M4_COMMANDLINE);
4360                 } else if(strcmp(argv[i], "--m4-clean")==0) {
4361                         use_m4 = TRUE;
4362                         use_m4_clean=TRUE;
4363                         m4_opts = TRUE;
4364                         m4_commandline=g_strdup(M4_COMMANDLINE);
4365                 } else if (strcmp (argv[i], "-o") == 0 || 
4366                            strcmp (argv[i], "--output-dir") == 0) {
4367                         if (i+1 < argc) {
4368                                 output_dir = g_strdup (argv[i+1]);
4369                                 i++;
4370                         } else {
4371                                 output_dir = NULL;
4372                         }
4373                 } else if (strncmp (argv[i], "-o=", strlen ("-o=")) == 0 || 
4374                            strncmp (argv[i],
4375                                     "--output-dir=",
4376                                     strlen ("--output-dir=")) == 0) {
4377                         char *p = strchr (argv[i], '=');
4378                         g_assert (p != NULL);
4379                         output_dir = g_strdup (p+1);
4380                 } else if (strncmp (argv[i], "--file-sep=",
4381                                     strlen ("--file-sep=")) == 0) {
4382                         char *p = strchr (argv[i], '=');
4383                         g_assert (p != NULL);
4384                         file_sep = *(p+1);
4385                 } else if (strncmp (argv[i], "--file-sep",
4386                                     strlen ("--file-sep")) == 0) {
4387                         if (i+1 < argc) {
4388                                 file_sep = (argv[i+1])[0];
4389                                 i++;
4390                         } else {
4391                                 file_sep = 0;
4392                         }
4393                 } else if(strcmp(argv[i], "--")==0) {
4394                         /*further arguments are files*/
4395                         no_opts = TRUE;
4396                 } else if(strncmp(argv[i], "--", 2)==0) {
4397                         /*unknown long option*/
4398                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
4399                         print_help();
4400                         exit(1);
4401                 } else {
4402                         /*by now we know we have a string starting with
4403                           - which is a short option string*/
4404                         char *p;
4405                         for(p = argv[i] + 1; *p; p++) {
4406                                 switch(*p) {
4407                                 case 'w':
4408                                         exit_on_warn=TRUE;
4409                                         break;
4410                                 case 'n':
4411                                         no_write = TRUE;
4412                                         break;
4413                                 case 'h':
4414                                 case '?':
4415                                         print_help();
4416                                         exit(0);
4417                                 default:
4418                                         fprintf(stderr,
4419                                                 "Unknown option '%c'!\n", *p);
4420                                         print_help();
4421                                         exit(1);
4422                                 }
4423                         }
4424                 }
4425         }
4426
4427 #if 0
4428         /* if we are using m4, and got no filename, append m4 flags now */
4429         if(!got_file && use_m4 && !use_m4_clean) {
4430                 char *new_commandline;
4431                 new_commandline=g_strconcat(m4_commandline,
4432                                             " ",
4433                                             M4_FLAGS,
4434                                             NULL);
4435                 g_free(m4_commandline);
4436                 m4_commandline=new_commandline;
4437         }
4438 #endif
4439 }
4440
4441 static void
4442 compare_and_move (const char *old_filename)
4443 {
4444         char *new_filename = g_strconcat (old_filename, "#gob#", NULL);
4445         FILE *old_f;
4446         gboolean equal = FALSE;
4447
4448         old_f = fopen (old_filename, "r");
4449         if (old_f) {
4450                 FILE *new_f;
4451                 gboolean error = FALSE;
4452
4453                 new_f = fopen (new_filename, "r");
4454                 if (new_f) {
4455                         char new_buf[1024];
4456                         char old_buf[1024];
4457
4458                         while (TRUE) {
4459                                 size_t new_n;
4460                                 size_t old_n;
4461
4462                                 new_n = fread (new_buf, 1, sizeof (new_buf), new_f);
4463                                 if (ferror (new_f)) {
4464                                         error = TRUE;
4465                                         error_printf (GOB_ERROR, 0,
4466                                                       "Can't read %s: %s",
4467                                                       new_filename,
4468                                                       g_strerror (errno));
4469                                         break;
4470                                 }
4471
4472                                 old_n = fread (old_buf, 1, sizeof (old_buf), old_f);
4473                                 if (ferror (old_f)
4474                                     || feof (new_f) != feof (old_f)
4475                                     || new_n != old_n
4476                                     || memcmp (new_buf, old_buf, new_n) != 0)
4477                                         break;
4478
4479                                 if (feof (new_f)) {
4480                                         equal = TRUE;
4481                                         break;
4482                                 }
4483                         }
4484                 } else
4485                         error_printf (GOB_ERROR, 0, "Can't open %s: %s",
4486                                       new_filename, g_strerror (errno));
4487
4488                 fclose (old_f);
4489                 fclose (new_f);
4490
4491                 if (error)
4492                         goto end;
4493
4494                 if (! equal && unlink (old_filename) != 0) {
4495                         error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
4496                                       old_filename, g_strerror (errno));
4497                         goto end;
4498                 }
4499         }
4500
4501         if (equal) {
4502                 if (unlink (new_filename) != 0)
4503                         error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
4504                                       new_filename, g_strerror (errno));
4505         } else {
4506                 if (rename (new_filename, old_filename) != 0)
4507                         error_printf (GOB_ERROR, 0, "Can't rename %s to %s: %s",
4508                                       new_filename, old_filename,
4509                                       g_strerror (errno));
4510         }
4511
4512  end:
4513         g_free (new_filename);
4514 }
4515
4516 int
4517 main(int argc, char *argv[])
4518 {
4519         parse_options(argc, argv);
4520
4521         if(use_m4) {
4522                 yyin = popen(m4_commandline, "r");
4523                 if(!yyin) {
4524                         fprintf(stderr, "Error: can't open pipe from '%s'\n",
4525                                 m4_commandline);
4526                         exit(1);
4527                 }
4528         } else if(filename) {
4529                 yyin = fopen(filename, "r");
4530                 if(!yyin) {
4531                         fprintf(stderr, "Error: can't open file '%s'\n",
4532                                 filename);
4533                         exit(1);
4534                 }
4535         }
4536
4537         if(filename==NULL)
4538                 filename = "stdin";
4539
4540         /* This is where parsing is done */
4541         /*yydebug = 1;*/
4542         if(yyparse() != 0)
4543                 error_print (GOB_ERROR, 0, "Parsing errors, quitting");
4544
4545         /* close input file */
4546         if(use_m4) pclose(yyin);
4547         else fclose(yyin);
4548         yyin=stdin;
4549
4550         if( ! class)
4551                 error_print (GOB_ERROR, 0, "no class defined");
4552         
4553
4554         exit_on_error = FALSE;
4555
4556         signals = count_signals ((Class *)class);
4557         set_properties = count_set_properties ((Class *)class) +
4558                 count_set_arguments ((Class *)class);
4559         get_properties = count_get_properties ((Class *)class) +
4560                 count_get_arguments ((Class *)class);
4561         overrides = count_overrides ((Class *)class);
4562         privates = count_privates ((Class *)class);
4563         protecteds = count_protecteds ((Class *)class);
4564         unreftors = count_unreftors ((Class *)class);
4565         destructors = count_destructors ((Class *)class);
4566         initializers = count_initializers ((Class *)class);
4567         glade_widgets = count_glade_widgets ((Class *)class);
4568         overrode_get_type = find_get_type ((Class *)class);
4569
4570         make_bases ();
4571         make_inits ((Class *)class);
4572
4573         find_constructor ((Class *)class);
4574         if (user_constructor != NULL)
4575                 need_constructor = TRUE;
4576
4577         find_dispose ((Class *)class);
4578         if (unreftors > 0 ||
4579             dispose_handler != NULL ||
4580             user_dispose_method != NULL)
4581                 need_dispose = TRUE;
4582
4583         find_finalize ((Class *)class);
4584         if (destructors > 0 ||
4585             privates > 0 ||
4586             user_finalize_method != NULL) {
4587                 need_finalize = TRUE;
4588         }
4589
4590         check_bad_symbols ((Class *)class);
4591         check_duplicate_symbols ((Class *)class);
4592         check_duplicate_overrides ((Class *)class);
4593         check_duplicate_signals_args ((Class *)class);
4594         check_public_new ((Class *)class);
4595         check_vararg ((Class *)class);
4596         check_firstarg ((Class *)class);
4597         check_nonvoidempty ((Class *)class);
4598         check_signal_args ((Class *)class);
4599         check_property_types ((Class *)class);
4600         check_argument_types ((Class *)class);
4601         check_func_arg_checks ((Class *)class);
4602         check_func_attrs ((Class *)class);
4603         check_for_class_destructors ((Class *)class);
4604
4605         exit_on_error = TRUE;
4606         
4607         if (got_error)
4608                 exit (1);
4609
4610         any_special = setup_special_array ((Class *)class, special_array);
4611
4612         open_files ();
4613         
4614         generate_outfiles ();
4615
4616         if (out)
4617                 fclose (out);
4618         if (outh)
4619                 fclose (outh);
4620         if (outph)
4621                 fclose (outph);
4622
4623         if (! no_write) {
4624                 if (no_touch) {
4625                         compare_and_move (outfilebase);
4626                         if (outfilephbase)
4627                                 compare_and_move (outfilephbase);
4628                 }
4629                 if (no_touch_headers)
4630                         compare_and_move (outfilehbase);
4631         }
4632         
4633         return 0;
4634 }