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