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