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