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