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