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