]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
6f5bf2cb5e2368b43726f4f7edcbcd50d704df95
[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 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         g_strdown (filebase);
124
125         funcbase = replace_sep (((Class *)class)->otype, '_');
126         g_strdown (funcbase);
127
128         pfuncbase = replace_sep (((Class *)class)->ptype, '_');
129         g_strdown (pfuncbase);
130
131         macrobase = replace_sep (((Class *)class)->otype, '_');
132         g_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                         g_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                 g_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                                         g_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                                 g_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                                 g_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                 g_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                 g_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                         g_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         g_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, "FLOAT"))
1542                 out_printf(out, "\tparam_spec = g_param_spec_float (\"%s\", NULL, NULL,\n"
1543                            "\t\tG_MINFLOAT, G_MAXFLOAT,\n"
1544                            "\t\t0,\n"
1545                            "\t\t%s);\n",
1546                            a->name, flags->str);
1547         else if (!strcmp (a->gtktype, "DOUBLE"))
1548                 out_printf(out, "\tparam_spec = g_param_spec_double (\"%s\", NULL, NULL,\n"
1549                            "\t\tG_MINDOUBLE, G_MAXDOUBLE,\n"
1550                            "\t\t0,\n"
1551                            "\t\t%s);\n",
1552                            a->name, flags->str);
1553         else if (!strcmp (a->gtktype, "POINTER"))
1554                 out_printf(out, "\tparam_spec = g_param_spec_pointer (\"%s\", NULL, NULL,\n"
1555                            "\t\t%s);\n",
1556                            a->name, flags->str);
1557         else
1558                 error_printf (GOB_ERROR, a->line_no,
1559                               "%s type is not supported for arguments, try using properties",
1560                               a->gtktype);
1561
1562         out_printf(out, "\tg_object_class_install_property (g_object_class,\n"
1563                    "\t\tPROP_%s, param_spec);\n", s);
1564
1565
1566         g_free(s);
1567         g_string_free(flags, TRUE);
1568 }
1569
1570 #define value_for_print(str, alt) (str != NULL ? str : alt)
1571
1572 static char *
1573 make_me_type (const char *type, const char *alt)
1574 {
1575         if (type == NULL)
1576                 return g_strdup (alt);
1577         /* HACK!  just in case someone made this
1578          * work with 2.0.0 by using the TYPE
1579          * macro directly */
1580         if ((strstr (type, "_TYPE_") != NULL ||
1581              strstr (type, "TYPE_") == type) &&
1582             strchr (type, ':') == NULL)
1583                 return g_strdup (type);
1584         return make_pre_macro (type, "TYPE");
1585 }
1586
1587 static void
1588 make_property (Property *p)
1589 {
1590         GString *flags;
1591         GList *l;
1592         char *s;
1593         char *argflags[] = {
1594                 "CONSTRUCT",
1595                 "CONSTRUCT_ONLY",
1596                 "CHILD_ARG",
1597                 "MASK",
1598                 NULL
1599         };
1600
1601         flags = g_string_new ("(GParamFlags)(");
1602
1603         if (p->get != NULL && p->set != NULL)
1604                 g_string_append (flags, "G_PARAM_READABLE | G_PARAM_WRITABLE");
1605         else if (p->get != NULL)
1606                 g_string_append (flags, "G_PARAM_READABLE");
1607         else
1608                 g_string_append (flags, "G_PARAM_WRITABLE");
1609
1610         if (p->get == NULL && p->set == NULL) {
1611                 error_print (GOB_ERROR, p->line_no,
1612                              "Property has no getter nor setter");
1613         }
1614
1615         for (l = p->flags; l != NULL; l = l->next) {
1616                 char *flag = l->data;
1617                 int i;
1618                 if(strcmp (flag, "READABLE") == 0 ||
1619                    strcmp (flag, "WRITABLE") == 0) {
1620                         error_print(GOB_WARN, p->line_no,
1621                                     "READABLE and "
1622                                     "WRITABLE argument flags are "
1623                                     "set automatically");
1624                         continue;
1625                 }
1626                 for(i = 0; argflags[i]; i++) {
1627                         if(strcmp(argflags[i], flag)==0)
1628                                 break;
1629                 }
1630                 /* if we haven't found it in our list */
1631                 if( ! argflags[i]) {
1632                         error_printf(GOB_WARN, p->line_no,
1633                                      "Unknown flag '%s' used, "
1634                                      "perhaps it was misspelled", flag);
1635                 }
1636                 g_string_sprintfa(flags, " | G_PARAM_%s", flag);
1637         }
1638
1639         g_string_append (flags, ")");
1640
1641         if (strcmp (p->gtktype, "CHAR") == 0) {
1642                 out_printf (out, "\tparam_spec = g_param_spec_char\n"
1643                             "\t\t(\"%s\" /* name */,\n"
1644                             "\t\t %s /* nick */,\n"
1645                             "\t\t %s /* blurb */,\n"
1646                             "\t\t %s /* minimum */,\n"
1647                             "\t\t %s /* maximum */,\n"
1648                             "\t\t %s /* default_value */,\n"
1649                             "\t\t %s);\n",
1650                             p->name,
1651                             value_for_print (p->nick, "NULL"),
1652                             value_for_print (p->blurb, "NULL"),
1653                             value_for_print (p->minimum, "-128"),
1654                             value_for_print (p->maximum, "127"),
1655                             value_for_print (p->default_value, "0"),
1656                             flags->str);
1657         } else if (strcmp (p->gtktype, "UCHAR") == 0) {
1658                 out_printf (out, "\tparam_spec = g_param_spec_uchar\n"
1659                             "\t\t(\"%s\" /* name */,\n"
1660                             "\t\t %s /* nick */,\n"
1661                             "\t\t %s /* blurb */,\n"
1662                             "\t\t %s /* minimum */,\n"
1663                             "\t\t %s /* maximum */,\n"
1664                             "\t\t %s /* default_value */,\n"
1665                             "\t\t %s);\n",
1666                             p->name,
1667                             value_for_print (p->nick, "NULL"),
1668                             value_for_print (p->blurb, "NULL"),
1669                             value_for_print (p->minimum, "0"),
1670                             value_for_print (p->maximum, "0xFF"),
1671                             value_for_print (p->default_value, "0"),
1672                             flags->str);
1673         } else if (strcmp (p->gtktype, "BOOLEAN") == 0) {
1674                 out_printf (out, "\tparam_spec = g_param_spec_boolean\n"
1675                             "\t\t(\"%s\" /* name */,\n"
1676                             "\t\t %s /* nick */,\n"
1677                             "\t\t %s /* blurb */,\n"
1678                             "\t\t %s /* default_value */,\n"
1679                             "\t\t %s);\n",
1680                             p->name,
1681                             value_for_print (p->nick, "NULL"),
1682                             value_for_print (p->blurb, "NULL"),
1683                             value_for_print (p->default_value, "FALSE"),
1684                             flags->str);
1685         } else if (strcmp (p->gtktype, "INT") == 0) {
1686                 out_printf (out, "\tparam_spec = g_param_spec_int\n"
1687                             "\t\t(\"%s\" /* name */,\n"
1688                             "\t\t %s /* nick */,\n"
1689                             "\t\t %s /* blurb */,\n"
1690                             "\t\t %s /* minimum */,\n"
1691                             "\t\t %s /* maximum */,\n"
1692                             "\t\t %s /* default_value */,\n"
1693                             "\t\t %s);\n",
1694                             p->name,
1695                             value_for_print (p->nick, "NULL"),
1696                             value_for_print (p->blurb, "NULL"),
1697                             value_for_print (p->minimum, "G_MININT"),
1698                             value_for_print (p->maximum, "G_MAXINT"),
1699                             value_for_print (p->default_value, "0"),
1700                             flags->str);
1701         } else if (strcmp (p->gtktype, "UINT") == 0) {
1702                 out_printf (out, "\tparam_spec = g_param_spec_uint\n"
1703                             "\t\t(\"%s\" /* name */,\n"
1704                             "\t\t %s /* nick */,\n"
1705                             "\t\t %s /* blurb */,\n"
1706                             "\t\t %s /* minimum */,\n"
1707                             "\t\t %s /* maximum */,\n"
1708                             "\t\t %s /* default_value */,\n"
1709                             "\t\t %s);\n",
1710                             p->name,
1711                             value_for_print (p->nick, "NULL"),
1712                             value_for_print (p->blurb, "NULL"),
1713                             value_for_print (p->minimum, "0"),
1714                             value_for_print (p->maximum, "G_MAXUINT"),
1715                             value_for_print (p->default_value, "0"),
1716                             flags->str);
1717         } else if (strcmp (p->gtktype, "LONG") == 0) {
1718                 out_printf (out, "\tparam_spec = g_param_spec_long\n"
1719                             "\t\t(\"%s\" /* name */,\n"
1720                             "\t\t %s /* nick */,\n"
1721                             "\t\t %s /* blurb */,\n"
1722                             "\t\t %s /* minimum */,\n"
1723                             "\t\t %s /* maximum */,\n"
1724                             "\t\t %s /* default_value */,\n"
1725                             "\t\t %s);\n",
1726                             p->name,
1727                             value_for_print (p->nick, "NULL"),
1728                             value_for_print (p->blurb, "NULL"),
1729                             value_for_print (p->minimum, "G_MINLONG"),
1730                             value_for_print (p->maximum, "G_MAXLONG"),
1731                             value_for_print (p->default_value, "0"),
1732                             flags->str);
1733         } else if (strcmp (p->gtktype, "ULONG") == 0) {
1734                 out_printf (out, "\tparam_spec = g_param_spec_ulong\n"
1735                             "\t\t(\"%s\" /* name */,\n"
1736                             "\t\t %s /* nick */,\n"
1737                             "\t\t %s /* blurb */,\n"
1738                             "\t\t %s /* minimum */,\n"
1739                             "\t\t %s /* maximum */,\n"
1740                             "\t\t %s /* default_value */,\n"
1741                             "\t\t %s);\n",
1742                             p->name,
1743                             value_for_print (p->nick, "NULL"),
1744                             value_for_print (p->blurb, "NULL"),
1745                             value_for_print (p->minimum, "0"),
1746                             value_for_print (p->maximum, "G_MAXULONG"),
1747                             value_for_print (p->default_value, "0"),
1748                             flags->str);
1749         } else if (strcmp (p->gtktype, "UNICHAR") == 0) {
1750                 out_printf (out, "\tparam_spec = g_param_spec_unichar\n"
1751                             "\t\t(\"%s\" /* name */,\n"
1752                             "\t\t %s /* nick */,\n"
1753                             "\t\t %s /* blurb */,\n"
1754                             "\t\t %s /* default_value */,\n"
1755                             "\t\t %s);\n",
1756                             p->name,
1757                             value_for_print (p->nick, "NULL"),
1758                             value_for_print (p->blurb, "NULL"),
1759                             value_for_print (p->default_value, "0"),
1760                             flags->str);
1761         } else if (strcmp (p->gtktype, "ENUM") == 0) {
1762                 char *type = make_me_type (p->extra_gtktype,
1763                                            "G_TYPE_ENUM");
1764                 out_printf (out, "\tparam_spec = g_param_spec_enum\n"
1765                             "\t\t(\"%s\" /* name */,\n"
1766                             "\t\t %s /* nick */,\n"
1767                             "\t\t %s /* blurb */,\n"
1768                             "\t\t %s /* enum_type */,\n"
1769                             "\t\t %s /* default_value */,\n"
1770                             "\t\t %s);\n",
1771                             p->name,
1772                             value_for_print (p->nick, "NULL"),
1773                             value_for_print (p->blurb, "NULL"),
1774                             type,
1775                             value_for_print (p->default_value, "0"),
1776                             flags->str);
1777                 g_free (type);
1778         } else if (strcmp (p->gtktype, "FLAGS") == 0) {
1779                 char *type = make_me_type (p->extra_gtktype,
1780                                            "G_TYPE_FLAGS");
1781                 out_printf (out, "\tparam_spec = g_param_spec_flags\n"
1782                             "\t\t(\"%s\" /* name */,\n"
1783                             "\t\t %s /* nick */,\n"
1784                             "\t\t %s /* blurb */,\n"
1785                             "\t\t %s /* flags_type */,\n"
1786                             "\t\t %s /* default_value */,\n"
1787                             "\t\t %s);\n",
1788                             p->name,
1789                             value_for_print (p->nick, "NULL"),
1790                             value_for_print (p->blurb, "NULL"),
1791                             type,
1792                             value_for_print (p->default_value, "0"),
1793                             flags->str);
1794                 g_free (type);
1795         } else if (strcmp (p->gtktype, "FLOAT") == 0) {
1796                 out_printf (out, "\tparam_spec = g_param_spec_float\n"
1797                             "\t\t(\"%s\" /* name */,\n"
1798                             "\t\t %s /* nick */,\n"
1799                             "\t\t %s /* blurb */,\n"
1800                             "\t\t %s /* minimum */,\n"
1801                             "\t\t %s /* maximum */,\n"
1802                             "\t\t %s /* default_value */,\n"
1803                             "\t\t %s);\n",
1804                             p->name,
1805                             value_for_print (p->nick, "NULL"),
1806                             value_for_print (p->blurb, "NULL"),
1807                             value_for_print (p->minimum, "G_MINFLOAT"),
1808                             value_for_print (p->maximum, "G_MAXFLOAT"),
1809                             value_for_print (p->default_value, "0.0"),
1810                             flags->str);
1811         } else if (strcmp (p->gtktype, "DOUBLE") == 0) {
1812                 out_printf (out, "\tparam_spec = g_param_spec_double\n"
1813                             "\t\t(\"%s\" /* name */,\n"
1814                             "\t\t %s /* nick */,\n"
1815                             "\t\t %s /* blurb */,\n"
1816                             "\t\t %s /* minimum */,\n"
1817                             "\t\t %s /* maximum */,\n"
1818                             "\t\t %s /* default_value */,\n"
1819                             "\t\t %s);\n",
1820                             p->name,
1821                             value_for_print (p->nick, "NULL"),
1822                             value_for_print (p->blurb, "NULL"),
1823                             value_for_print (p->minimum, "G_MINDOUBLE"),
1824                             value_for_print (p->maximum, "G_MAXDOUBLE"),
1825                             value_for_print (p->default_value, "0.0"),
1826                             flags->str);
1827         } else if (strcmp (p->gtktype, "STRING") == 0) {
1828                 out_printf (out, "\tparam_spec = g_param_spec_string\n"
1829                             "\t\t(\"%s\" /* name */,\n"
1830                             "\t\t %s /* nick */,\n"
1831                             "\t\t %s /* blurb */,\n"
1832                             "\t\t %s /* default_value */,\n"
1833                             "\t\t %s);\n",
1834                             p->name,
1835                             value_for_print (p->nick, "NULL"),
1836                             value_for_print (p->blurb, "NULL"),
1837                             value_for_print (p->default_value, "NULL"),
1838                             flags->str);
1839         } else if (strcmp (p->gtktype, "PARAM") == 0) {
1840                 char *type = make_me_type (p->extra_gtktype,
1841                                            "G_TYPE_PARAM");
1842                 out_printf (out, "\tparam_spec = g_param_spec_param\n"
1843                             "\t\t(\"%s\" /* name */,\n"
1844                             "\t\t %s /* nick */,\n"
1845                             "\t\t %s /* blurb */,\n"
1846                             "\t\t %s /* param_type */,\n"
1847                             "\t\t %s);\n",
1848                             p->name,
1849                             value_for_print (p->nick, "NULL"),
1850                             value_for_print (p->blurb, "NULL"),
1851                             type,
1852                             flags->str);
1853                 g_free (type);
1854         } else if (strcmp (p->gtktype, "BOXED") == 0) {
1855                 char *type = make_me_type (p->extra_gtktype,
1856                                            "G_TYPE_BOXED");
1857                 out_printf (out, "\tparam_spec = g_param_spec_boxed\n"
1858                             "\t\t(\"%s\" /* name */,\n"
1859                             "\t\t %s /* nick */,\n"
1860                             "\t\t %s /* blurb */,\n"
1861                             "\t\t %s /* boxed_type */,\n"
1862                             "\t\t %s);\n",
1863                             p->name,
1864                             value_for_print (p->nick, "NULL"),
1865                             value_for_print (p->blurb, "NULL"),
1866                             type,
1867                             flags->str);
1868                 g_free (type);
1869         } else if (strcmp (p->gtktype, "POINTER") == 0) {
1870                 out_printf (out, "\tparam_spec = g_param_spec_pointer\n"
1871                             "\t\t(\"%s\" /* name */,\n"
1872                             "\t\t %s /* nick */,\n"
1873                             "\t\t %s /* blurb */,\n"
1874                             "\t\t %s);\n",
1875                             p->name,
1876                             value_for_print (p->nick, "NULL"),
1877                             value_for_print (p->blurb, "NULL"),
1878                             flags->str);
1879         /* FIXME: VALUE_ARRAY */
1880         } else if (strcmp (p->gtktype, "CLOSURE") == 0) {
1881                 out_printf (out, "\tparam_spec = g_param_spec_pointer\n"
1882                             "\t\t(\"%s\" /* name */,\n"
1883                             "\t\t %s /* nick */,\n"
1884                             "\t\t %s /* blurb */,\n"
1885                             "\t\t %s);\n",
1886                             p->name,
1887                             value_for_print (p->nick, "NULL"),
1888                             value_for_print (p->blurb, "NULL"),
1889                             flags->str);
1890         } else if (strcmp (p->gtktype, "OBJECT") == 0) {
1891                 char *type = make_me_type (p->extra_gtktype,
1892                                            "G_TYPE_BOXED");
1893                 out_printf (out, "\tparam_spec = g_param_spec_object\n"
1894                             "\t\t(\"%s\" /* name */,\n"
1895                             "\t\t %s /* nick */,\n"
1896                             "\t\t %s /* blurb */,\n"
1897                             "\t\t %s /* object_type */,\n"
1898                             "\t\t %s);\n",
1899                             p->name,
1900                             value_for_print (p->nick, "NULL"),
1901                             value_for_print (p->blurb, "NULL"),
1902                             type,
1903                             flags->str);
1904                 g_free (type);
1905         } else {
1906                 error_printf (GOB_ERROR, p->line_no,
1907                               "%s type is not supported by properties",
1908                               p->gtktype);
1909         }
1910
1911         s = g_strdup (p->name);
1912         g_strup (s);
1913         out_printf (out, "\tg_object_class_install_property (g_object_class,\n"
1914                     "\t\tPROP_%s,\n"
1915                     "\t\tparam_spec);\n", s);
1916         g_free (s);
1917
1918         g_string_free (flags, TRUE);
1919 }
1920
1921 static void
1922 make_arguments(Class *c)
1923 {
1924         GList *li;
1925         if (get_properties > 0)
1926                 out_printf(out, "\tg_object_class->get_property = ___object_get_property;\n");
1927         if (set_properties > 0)
1928                 out_printf(out, "\tg_object_class->set_property = ___object_set_property;\n");
1929         out_printf (out, "    {\n"
1930                     "\tGParamSpec   *param_spec;\n\n");
1931
1932         for (li = c->nodes; li != NULL; li = li->next) {
1933                 Node *n = li->data;
1934                 if (n->type == PROPERTY_NODE)
1935                         make_property ((Property *)n);
1936                 else if (n->type == ARGUMENT_NODE)
1937                         make_argument ((Argument *)n);
1938         }
1939         out_printf(out, "    }\n");
1940 }
1941
1942 static void
1943 print_initializer(Method *m, Variable *v)
1944 {
1945         char *root;
1946
1947         if(v->initializer == NULL)
1948                 return;
1949
1950         if(v->scope == PRIVATE_SCOPE)
1951                 root = g_strconcat(((FuncArg *)m->args->data)->name,
1952                                    "->_priv", NULL);
1953         else
1954                 root = g_strdup(((FuncArg *)m->args->data)->name);
1955
1956         if(v->initializer_line > 0)
1957                 out_addline_infile(out, v->initializer_line);
1958
1959         out_printf(out, "\t%s->%s = %s;\n",
1960                    root, v->id, v->initializer);
1961
1962         if(v->initializer_line > 0)
1963                 out_addline_outfile(out);
1964
1965         g_free(root);
1966 }
1967
1968 static void
1969 print_destructor (Variable *v)
1970 {
1971         const char *root;
1972
1973         if(v->destructor == NULL)
1974                 return;
1975
1976         if(v->scope == PRIVATE_SCOPE)
1977                 root = "self->_priv";
1978         else
1979                 root = "self";
1980
1981         if(v->destructor_simple) {
1982                 if(v->destructor_line > 0)
1983                         out_addline_infile(out, v->destructor_line);
1984
1985                 out_printf(out, "\tif(%s->%s) { "
1986                            "((*(void (*)(void *))%s)) (%s->%s); "
1987                            "%s->%s = NULL; }\n",
1988                            root, v->id, v->destructor, root, v->id,
1989                            root, v->id);
1990
1991                 if(v->destructor_line > 0)
1992                         out_addline_outfile(out);
1993         } else {
1994                 out_printf(out, "#define %s (%s->%s)\n", v->id, root, v->id);
1995                 out_printf(out, "#define VAR %s\n", v->id);
1996                 out_printf(out, "\t{\n");
1997                 if(v->destructor_line > 0)
1998                         out_addline_infile(out, v->destructor_line);
1999
2000                 out_printf(out, "\t%s}\n", v->destructor);
2001
2002                 if(v->destructor_line > 0)
2003                         out_addline_outfile(out);
2004                 out_printf(out, "\tmemset(&%s, 0, sizeof(%s));\n",
2005                            v->id, v->id);
2006                 out_printf(out, "#undef VAR\n");
2007                 out_printf(out, "#undef %s\n", v->id);
2008         }
2009 }
2010
2011 static void
2012 add_dispose (Class *c)
2013 {
2014         out_printf(out, "\nstatic void\n"
2015                    "___dispose (GObject *obj_self)\n"
2016                    "{\n");
2017         out_printf(out,
2018                    "#define __GOB_FUNCTION__ \"%s::dispose\"\n",
2019                    c->otype);
2020
2021         if (unreftors > 0) {
2022                 out_printf (out, "\t%s *self = %s (obj_self);\n",
2023                             typebase, macrobase);
2024         }
2025
2026         if (dispose_handler != NULL) {
2027                 /* so we get possible bad argument warning */
2028                 if (dispose_handler->line_no > 0)
2029                         out_addline_infile (out, dispose_handler->line_no);
2030                 out_printf (out, "\t___%x_%s_dispose(obj_self);\n",
2031                             (guint)dispose_handler->unique_id, funcbase);
2032                 if (dispose_handler->line_no > 0)
2033                         out_addline_outfile (out);
2034         } else {
2035                 out_printf (out,
2036                             "\tif (G_OBJECT_CLASS (parent_class)->dispose) \\\n"
2037                             "\t\t(* G_OBJECT_CLASS (parent_class)->dispose) (obj_self);\n");
2038         }
2039
2040         if (unreftors > 0) {
2041                 GList *li;
2042                 for(li = ((Class *)class)->nodes;
2043                     li != NULL;
2044                     li = li->next) {
2045                         Node *n = li->data;
2046                         Variable *v = (Variable *)n;
2047                         if (n->type == VARIABLE_NODE &&
2048                             v->scope != CLASS_SCOPE &&
2049                             v->destructor_unref)
2050                                 print_destructor (v);
2051                 }
2052         }
2053
2054         out_printf (out, "\treturn;\n");
2055         if (unreftors > 0)
2056                 out_printf(out, "\tself = NULL;\n");
2057         out_printf(out, "}\n"
2058                    "#undef __GOB_FUNCTION__\n\n");
2059 }
2060
2061 static void
2062 add_finalize (Class *c)
2063 {
2064         out_printf(out,
2065                    "\nstatic void\n"
2066                    "___finalize(GObject *obj_self)\n"
2067                    "{\n");
2068         out_printf(out,
2069                    "#define __GOB_FUNCTION__ \"%s::finalize\"\n",
2070                    c->otype);
2071
2072         if (privates > 0 ||
2073             destructors > 0) {
2074                 out_printf(out, "\t%s *self = %s (obj_self);\n",
2075                            typebase, macrobase);
2076         }
2077         if (privates > 0) {
2078                 out_printf(out, "\tgpointer priv = self->_priv;\n");
2079         }
2080
2081         if(finalize_handler) {
2082                 /* so we get possible bad argument warning */
2083                 if(finalize_handler->line_no > 0)
2084                         out_addline_infile(out, finalize_handler->line_no);
2085                 out_printf(out, "\t___%x_%s_finalize(obj_self);\n",
2086                            (guint)finalize_handler->unique_id, funcbase);
2087                 if(finalize_handler->line_no > 0)
2088                         out_addline_outfile(out);
2089         } else {
2090                 out_printf(out,
2091                            "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
2092                            "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n");
2093         }
2094
2095         if (destructors > 0) {
2096                 GList *li;
2097                 for (li = ((Class *)class)->nodes;
2098                      li != NULL;
2099                      li = li->next) {
2100                         Node *n = li->data;
2101                         Variable *v = (Variable *)n;
2102                         if (n->type == VARIABLE_NODE &&
2103                             v->scope != CLASS_SCOPE &&
2104                             ! v->destructor_unref)
2105                                 print_destructor (v);
2106                 }
2107         }
2108
2109         if (privates > 0) {
2110                 out_printf(out, "\tg_free (priv);\n");
2111         }
2112         out_printf (out, "\treturn;\n");
2113         if (destructors > 0 ||
2114             privates > 0)
2115                 out_printf (out, "\tself = NULL;\n");
2116
2117         out_printf(out, "}\n"
2118                    "#undef __GOB_FUNCTION__\n\n");
2119 }
2120
2121 static void
2122 make_bonobo_object_epv (Class *c, const char *classname)
2123 {
2124         GList *li;
2125         gboolean added_line = FALSE;
2126
2127         for (li = c->nodes; li != NULL; li = li->next) {
2128                 Node *n = li->data;
2129                 Method *m = (Method *)n;
2130                 if(n->type != METHOD_NODE ||
2131                    m->method == OVERRIDE_METHOD)
2132                         continue;
2133
2134                 if (m->bonobo_object_func) {
2135                         if(m->line_no > 0) {
2136                                 out_addline_infile(out, m->line_no);
2137                                 added_line = TRUE;
2138                         } else if (m->line_no == 0 &&
2139                                    added_line) {
2140                                 out_addline_outfile(out);
2141                                 added_line = FALSE;
2142                         }
2143                         out_printf (out, "\t%s->_epv.%s = self_%s;\n",
2144                                     classname, m->id, m->id);
2145                 }
2146         }
2147         if (added_line)
2148                 out_addline_outfile(out);
2149 }
2150
2151 static void
2152 add_inits(Class *c)
2153 {
2154         GList *li;
2155         for(li=c->nodes;li;li=g_list_next(li)) {
2156                 Node *n = li->data;
2157                 Method *m;
2158
2159                 gboolean add_unused_class = FALSE;
2160
2161                 if(n->type != METHOD_NODE)
2162                         continue;
2163                 m = (Method *)n;
2164                 if(m->method == INIT_METHOD) {
2165                         if(m->line_no > 0)
2166                                 out_addline_infile(out, m->line_no);
2167                         print_method(out, "static ", "\n", "", " ", "", "\n",
2168                                      m, FALSE, FALSE, TRUE);
2169                         if(m->line_no > 0)
2170                                 out_addline_outfile(out);
2171                         out_printf(out, "{\n"
2172                                    "#define __GOB_FUNCTION__ \"%s::init\"\n",
2173                                    c->otype);
2174                         if(privates > 0) {
2175                                 out_printf(out, "\t%s->_priv = "
2176                                            "g_new0 (%sPrivate, 1);\n",
2177                                            ((FuncArg *)m->args->data)->name,
2178                                            typebase);
2179                         } else if(always_private_struct) {
2180                                 out_printf(out, "\t%s->_priv = NULL;\n",
2181                                            ((FuncArg *)m->args->data)->name);
2182                         }
2183                         if(initializers > 0) {
2184                                 GList *li;
2185                                 for(li = ((Class *)class)->nodes;
2186                                     li != NULL;
2187                                     li = li->next) {
2188                                         Node *n = li->data;
2189                                         Variable *v = (Variable *)n;
2190                                         if(n->type != VARIABLE_NODE ||
2191                                            v->scope == CLASS_SCOPE)
2192                                                 continue;
2193                                         print_initializer(m, v);
2194                                 }
2195                         }
2196                 } else if(m->method == CLASS_INIT_METHOD) {
2197                         gboolean did_base_obj = FALSE;
2198
2199                         if(m->line_no > 0)
2200                                 out_addline_infile(out, m->line_no);
2201                         print_method(out, "static ", "\n", "", " ", "", "\n",
2202                                      m, FALSE, FALSE, TRUE);
2203                         if(m->line_no > 0)
2204                                 out_addline_outfile(out);
2205                         out_printf(out, "{\n"
2206                                    "#define __GOB_FUNCTION__ \"%s::class_init\"\n",
2207                                    c->otype);
2208                         if (set_properties > 0 ||
2209                             get_properties > 0 ||
2210                             signals > 0 ||
2211                             need_dispose ||
2212                             need_finalize) {
2213                                 out_printf(out,
2214                                            "\tGObjectClass *"
2215                                            "g_object_class = "
2216                                            "(GObjectClass*) %s;\n",
2217                                            ((FuncArg *)m->args->data)->name);
2218                                 add_unused_class = TRUE;
2219                                 did_base_obj = TRUE;
2220                         }
2221
2222                         if (overrides > 0)
2223                                 add_overrides (c,
2224                                                ((FuncArg *)m->args->data)->name,
2225                                                did_base_obj);
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                                                 print_initializer(m, v);
2237                                 }
2238                         }
2239                         
2240                         out_printf(out, "\n\tparent_class = ");
2241                         if(for_cpp)
2242                                 out_printf(out, "(%sClass *)", ptypebase);
2243                         out_printf(out, "g_type_class_ref (%s);\n",
2244                                    pmacrotype);
2245
2246                         if(signals > 0)
2247                                 add_signals(c);
2248
2249                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
2250
2251                         /* if there are no handlers for these things, we
2252                          * need to set them up here */
2253                         if(need_dispose && !dispose_handler)
2254                                 out_printf(out, "\tg_object_class->dispose "
2255                                            "= ___dispose;\n");
2256                         if(need_finalize && !finalize_handler)
2257                                 out_printf(out, "\tg_object_class->finalize = "
2258                                            "___finalize;\n");
2259                         
2260                         if(get_properties > 0 || set_properties > 0)
2261                                 make_arguments(c);
2262
2263                         if (c->bonobo_object_class != NULL) {
2264                                 make_bonobo_object_epv (c, ((FuncArg *)m->args->data)->name);
2265                         }
2266                 } else
2267                         continue;
2268
2269                 if(m->cbuf) {
2270                         out_printf(out, " {\n");
2271                         out_addline_infile(out, m->ccode_line);
2272                         out_printf(out, "%s\n", m->cbuf);
2273                         out_addline_outfile(out);
2274                         out_printf(out, " }\n");
2275                 }
2276                 out_printf(out, "\treturn;\n");
2277                 out_printf(out,
2278                            "\t%s = NULL;\n",
2279                            ((FuncArg *)m->args->data)->name);
2280                 if(add_unused_class) {
2281                         out_printf (out, "\tg_object_class = NULL;\n");
2282                 }
2283                 out_printf(out, "}\n"
2284                            "#undef __GOB_FUNCTION__\n");
2285         }
2286 }
2287
2288 static void
2289 add_argument (Argument *a, gboolean is_set)
2290 {
2291         char *s;
2292         char *cbuf;
2293         char *the_type_lower;
2294         int line_no;
2295
2296         if(is_set) {
2297                 cbuf = a->set;
2298                 line_no = a->set_line;
2299         } else {
2300                 cbuf = a->get;
2301                 line_no = a->get_line;
2302         }
2303         if (cbuf == NULL)
2304                 return;
2305         s = g_strdup(a->name);
2306         g_strup(s);
2307         out_printf(out, "\tcase PROP_%s:\n\t{", s);
2308
2309         the_type_lower = g_strdup (a->gtktype);
2310         g_strdown (the_type_lower);
2311
2312         /* HACK because there is no g_value_set/get for unichar */
2313         if (strcmp (the_type_lower, "unichar") == 0) {
2314                 g_free (the_type_lower);
2315                 the_type_lower = g_strdup ("uint");
2316         }
2317
2318         if (is_set) {
2319                 char *cast;
2320
2321                 if (a->atype != NULL)
2322                         cast = get_type (a->atype, TRUE);
2323                 else
2324                         cast = g_strdup (get_cast (a->gtktype, FALSE));
2325
2326                 out_printf (out, "\t%s ARG = (%s) g_value_get_%s (VAL);\n",
2327                             cast, cast, the_type_lower);
2328
2329                 g_free (cast);
2330         } else if ( ! is_set) {
2331                 char *cast;
2332
2333                 if (a->atype != NULL)
2334                         cast = get_type (a->atype, TRUE);
2335                 else
2336                         cast = g_strdup (get_cast (a->gtktype, FALSE));
2337                 out_printf (out, "\t%s ARG;\n"
2338                             "\tmemset (&ARG, 0, sizeof (%s));\n",
2339                             cast, cast);
2340
2341                 g_free(cast);
2342         }
2343         g_free (s);
2344         out_printf(out, "\t\t{\n");
2345         if (line_no > 0)
2346                 out_addline_infile (out, line_no);
2347         out_printf (out, "%s\n", cbuf);
2348         if (line_no > 0)
2349                 out_addline_outfile (out);
2350         out_printf (out, "\t\t}\n");
2351         if ( ! is_set) {
2352                 if (strcmp (a->gtktype, "OBJECT") == 0)
2353                         out_printf (out, "\t\tg_value_set_%s (VAL, G_OBJECT (ARG));\n",
2354                                     the_type_lower);
2355                 else
2356                         out_printf (out, "\t\t"
2357                                     "g_value_set_%s (VAL, ARG);\n",
2358                                     the_type_lower);
2359         }
2360         g_free (the_type_lower);
2361
2362         if (is_set) {
2363                 out_printf (out, "\t\tif (&ARG) ;\n");
2364         }
2365
2366         out_printf (out, "\t\tbreak;\n");
2367
2368         out_printf (out, "\t}\n");
2369 }
2370
2371 static void
2372 add_property (Property *p, gboolean is_set)
2373 {
2374         const char *cbuf;
2375         char *the_type_lower;
2376         char *name_upper;
2377         int line_no;
2378
2379         if (is_set) {
2380                 cbuf = p->set;
2381                 line_no = p->set_line;
2382         } else {
2383                 cbuf = p->get;
2384                 line_no = p->get_line;
2385         }
2386         if (cbuf == NULL)
2387                 return;
2388
2389         name_upper = g_strdup (p->name);
2390         g_strup (name_upper);
2391         the_type_lower = g_strdup (p->gtktype);
2392         g_strdown (the_type_lower);
2393
2394         out_printf (out, "\tcase PROP_%s:\n", name_upper);
2395
2396         out_printf(out, "\t\t{\n");
2397         if (line_no > 0)
2398                 out_addline_infile (out, line_no);
2399         out_printf (out, "%s\n", cbuf);
2400         if (line_no > 0)
2401                 out_addline_outfile (out);
2402         out_printf (out, "\t\t}\n");
2403
2404         g_free (name_upper);
2405         g_free (the_type_lower);
2406
2407         out_printf (out, "\t\tbreak;\n");
2408 }
2409
2410 static void
2411 add_getset_arg(Class *c, gboolean is_set)
2412 {
2413         GList *li;
2414         out_printf(out, "\nstatic void\n"
2415                    "___object_%s_property (GObject *object,\n"
2416                    "\tguint property_id,\n"
2417                    "\t%sGValue *VAL,\n"
2418                    "\tGParamSpec *pspec)\n"
2419                    "#define __GOB_FUNCTION__ \"%s::%s_property\"\n"
2420                    "{\n"
2421                    "\t%s *self;\n\n"
2422                    "\tself = %s (object);\n\n"
2423                    "\tswitch (property_id) {\n",
2424                    is_set ? "set" : "get",
2425                    is_set ? "const " : "",
2426                    c->otype, is_set ? "set" : "get",
2427                    typebase, macrobase);
2428
2429         for (li = c->nodes; li != NULL; li = li->next) {
2430                 Node *n = li->data;
2431                 if (n->type == PROPERTY_NODE)
2432                         add_property ((Property *)n, is_set);
2433                 else if (n->type == ARGUMENT_NODE)
2434                         add_argument ((Argument *)n, is_set);
2435         }
2436         out_printf (out, "\tdefault:\n"
2437                     "/* Apparently in g++ this is needed, glib is b0rk */\n"
2438                     "#ifndef __PRETTY_FUNCTION__\n"
2439                     "#  undef G_STRLOC\n"
2440                     "#  define G_STRLOC __FILE__ \":\" G_STRINGIFY (__LINE__)\n"
2441                     "#endif\n"
2442                     "\t\tG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);\n"
2443                     "\t\tbreak;\n\t}\n"
2444                     "\treturn;\n\tself = NULL;\n\tVAL = NULL;\n\tpspec = NULL;\n}\n"
2445                     "#undef __GOB_FUNCTION__\n");
2446 }
2447
2448 static void
2449 print_checks (Method *m, FuncArg *fa)
2450 {
2451         GList *li;
2452         gboolean is_void;
2453         gboolean checked_null = FALSE;
2454         is_void = (strcmp(m->mtype->name, "void")==0 &&
2455                    m->mtype->pointer == NULL);
2456         
2457         for(li = fa->checks; li != NULL; li = li->next) {
2458                 Check *ch = li->data;
2459                 char *s;
2460                 /* point to the method prot in .gob for failed checks */
2461                 if(m->line_no > 0)
2462                         out_addline_infile(out, m->line_no);
2463                 if(is_void)
2464                         out_printf(out, "\tg_return_if_fail (");
2465                 else
2466                         out_printf(out, "\tg_return_val_if_fail (");
2467                 switch(ch->chtype) {
2468                 case NULL_CHECK:
2469                         out_printf(out, "%s != NULL", fa->name);
2470                         checked_null = TRUE;
2471                         break;
2472                 case TYPE_CHECK:
2473                         s = make_pre_macro(fa->atype->name, "IS");
2474                         if(checked_null)
2475                                 out_printf(out, "%s (%s)", s, fa->name);
2476                         else
2477                                 /* if not check null, null may be valid */
2478                                 out_printf(out, "!(%s) || %s (%s)", fa->name,
2479                                            s, fa->name);
2480                         g_free(s);
2481                         break;
2482                 case LT_CHECK:
2483                         out_printf(out, "%s < %s", fa->name, ch->number);
2484                         break;
2485                 case GT_CHECK:
2486                         out_printf(out, "%s > %s", fa->name, ch->number);
2487                         break;
2488                 case LE_CHECK:
2489                         out_printf(out, "%s <= %s", fa->name, ch->number);
2490                         break;
2491                 case GE_CHECK:
2492                         out_printf(out, "%s >= %s", fa->name, ch->number);
2493                         break;
2494                 case EQ_CHECK:
2495                         out_printf(out, "%s == %s", fa->name, ch->number);
2496                         break;
2497                 case NE_CHECK:
2498                         out_printf(out, "%s != %s", fa->name, ch->number);
2499                         break;
2500                 }
2501                 if(is_void)
2502                         out_printf(out, ");\n");
2503                 else {
2504                         out_printf(out, ", (");
2505                         print_type(out, m->mtype, TRUE);
2506                         out_printf(out, ")%s);\n",
2507                                 m->onerror?m->onerror:"0");
2508                 }
2509         }
2510 }
2511
2512 static void
2513 print_preconditions(Method *m)
2514 {
2515         GList *li;
2516         
2517         for(li=m->args;li;li=g_list_next(li)) {
2518                 FuncArg *fa = li->data;
2519                 if(fa->checks)
2520                         print_checks(m, fa);
2521         }
2522         if(m->line_no>0)
2523                 out_addline_outfile(out);
2524 }
2525
2526 static void
2527 print_method_body(Method *m, int pre)
2528 {
2529         if (m->line_no > 0)
2530                 out_addline_outfile(out);
2531         out_printf(out, "{\n"
2532                    "#define __GOB_FUNCTION__ \"%s::%s\"\n",
2533                    ((Class *)class)->otype,
2534                    m->id);
2535         if(pre)
2536                 print_preconditions(m);
2537
2538         /* Note: the trailing }'s are on one line, this is so
2539            that we get the no return warning correctly and point to
2540            the correct line in the .gob file, yes this is slightly
2541            ugly in the .c file, but that is not supposed to be
2542            human readable anyway. */
2543         if(m->cbuf) {
2544                 out_printf(out, "{\n");
2545                 if(m->ccode_line>0)
2546                         out_addline_infile(out, m->ccode_line);
2547                 out_printf(out, "\t%s}", m->cbuf);
2548         }
2549
2550         /* Note, there is no \n between the last } and this } so that
2551          * errors/warnings reported on the end of the body get pointed to the
2552          * right line in the .gob source */
2553         out_printf(out, "}\n");
2554
2555         if(m->cbuf)
2556                 out_addline_outfile(out);
2557         out_printf(out, "#undef __GOB_FUNCTION__\n");
2558 }
2559
2560 static void
2561 put_signal_args (Method *m)
2562 {
2563         GList *li;
2564         GList *ali;
2565         int i;
2566
2567         if (m->args->next == NULL)
2568                 return;
2569
2570         for (ali = m->gtktypes->next, li = m->args->next, i = 1;
2571              li != NULL && ali != NULL;
2572              li = li->next, ali = ali->next, i++) {
2573                 FuncArg *fa = li->data;
2574                 char *cast = g_strdup (get_cast (ali->data, FALSE));
2575                 /* FIXME: This code is so fucking ugly it hurts */
2576                 gboolean do_static = 
2577                         (strcmp ((char *)ali->data, "STRING") == 0 ||
2578                          strcmp ((char *)ali->data, "BOXED") == 0);
2579                 char *set_func;
2580
2581                 if (cast == NULL) {
2582                         cast = get_type (fa->atype, TRUE);
2583                 }
2584                 /* we should have already proved before that
2585                    the we know all the types */
2586                 g_assert (cast != NULL);
2587
2588                 out_printf (out,
2589                             "\t___param_values[%d].g_type = 0;\n"
2590                             "\tg_value_init (&___param_values[%d], G_TYPE_%s);\n",
2591                             i, i, (char *)ali->data);
2592
2593                 if (strcmp (ali->data, "UNICHAR") == 0)
2594                         /* hack because glib is braindamaged */
2595                         set_func = g_strdup ("g_value_set_uint");
2596                 else
2597                         set_func = g_strdup_printf ("g_value_set%s_%s",
2598                                                     do_static ? "_static" : "",
2599                                                     (char *)ali->data);
2600                 g_strdown (set_func);
2601
2602                 out_printf (out, "\t%s (&___param_values[%d], (%s) %s);\n\n",
2603                             set_func, i, cast, fa->name);
2604
2605                 g_free (set_func);
2606                 g_free (cast);
2607         }
2608 }
2609
2610 static void
2611 clear_signal_args (Method *m)
2612 {
2613         GList *li;
2614         int i;
2615
2616         out_printf (out, "\n\tg_value_unset (&___param_values[0]);\n");
2617
2618         if (m->args->next == NULL)
2619                 return;
2620
2621         for (li = m->args->next, i = 1;
2622              li != NULL;
2623              li = li->next, i++) {
2624                 out_printf (out,
2625                             "\tg_value_unset (&___param_values[%d]);\n", i);
2626         }
2627 }
2628
2629 static char *
2630 get_arg_names_for_macro (Method *m)
2631 {
2632         const char *sep;
2633         GList *li;
2634         GString *gs = g_string_new(NULL);
2635         sep = "";
2636         for(li=m->args;li;li=g_list_next(li)) {
2637                 FuncArg *arg = li->data;
2638                 g_string_sprintfa (gs, "%s___%s", sep, arg->name);
2639                 sep = ",";
2640         }
2641         return g_string_free (gs, FALSE);
2642 }
2643
2644 static void
2645 put_method(Method *m)
2646 {
2647         char *s, *args, *doc;
2648         gboolean is_void;
2649         is_void = (strcmp(m->mtype->name, "void")==0 &&
2650                    m->mtype->pointer == NULL);
2651         out_printf(out, "\n");
2652         if(m->method != OVERRIDE_METHOD) {
2653                 doc = get_gtk_doc(m->id);
2654                 if(doc) {
2655                         out_printf(out, "%s", doc);
2656                         g_free(doc);
2657                 }
2658         }
2659         switch(m->method) {
2660         case REGULAR_METHOD:
2661                 if(m->line_no > 0)
2662                         out_addline_infile(out, m->line_no);
2663                 if(m->scope == PRIVATE_SCOPE)
2664                         print_method(out, "static ", "\n", "", " ", "", "\n",
2665                                      m, FALSE, FALSE, TRUE);
2666                 else /* PUBLIC, PROTECTED */
2667                         print_method(out, "", "\n", "", " ", "", "\n",
2668                                      m, FALSE, FALSE, TRUE);
2669                 print_method_body(m, TRUE);
2670                 /* the outfile line was added above */
2671                 break;
2672         case SIGNAL_FIRST_METHOD:
2673         case SIGNAL_LAST_METHOD:
2674                 if(m->line_no > 0)
2675                         out_addline_infile(out, m->line_no);
2676                 if(m->scope == PRIVATE_SCOPE)
2677                         print_method(out, "static ", "\n", "", " ", "", "\n",
2678                                      m, FALSE, FALSE, TRUE);
2679                 else /* PUBLIC, PROTECTED */
2680                         print_method(out, "", "\n", "", " ", "", "\n",
2681                                      m, FALSE, FALSE, TRUE);
2682                 out_addline_outfile (out);
2683
2684                 out_printf (out, "{\n");
2685
2686                 out_printf (out,
2687                             "\tGValue ___param_values[%d];\n"
2688                             "\tGValue ___return_val = {0};\n\n",
2689                             g_list_length (m->args));
2690
2691                 print_preconditions (m);
2692
2693                 out_printf (out,
2694                             "\n\t___param_values[0].g_type = 0;\n"
2695                             "\tg_value_init (&___param_values[0], G_TYPE_FROM_INSTANCE (%s));\n"
2696                             "\tg_value_set_instance (&___param_values[0], (gpointer) %s);\n\n",
2697                             ((FuncArg *)m->args->data)->name,
2698                             ((FuncArg *)m->args->data)->name);
2699
2700                 put_signal_args (m);
2701
2702                 if (strcmp (m->gtktypes->data, "NONE") != 0) {
2703                         const char *defret = NULL;
2704
2705                         out_printf (out, "\tg_value_init (&___return_val, G_TYPE_%s);\n",
2706                                     (char *)m->gtktypes->data);
2707
2708                         if (m->defreturn != NULL)
2709                                 defret = m->defreturn;
2710                         else if (m->onerror != NULL)
2711                                 defret = m->onerror;
2712
2713                         if (defret != NULL) {
2714                                 char *set_func;
2715                                 /* FIXME: This code is so fucking ugly it hurts */
2716                                 gboolean do_static = 
2717                                         (strcmp ((char *)m->gtktypes->data, "STRING") == 0 ||
2718                                          strcmp ((char *)m->gtktypes->data, "BOXED") == 0);
2719                                 char *cast = g_strdup (get_cast (m->gtktypes->data, FALSE));
2720                                 if (cast == NULL)
2721                                         cast = get_type (m->mtype, TRUE);
2722
2723                                 if (strcmp (m->gtktypes->data, "UNICHAR") == 0)
2724                                         /* hack because glib is braindamaged */
2725                                         set_func = g_strdup ("g_value_set_uint");
2726                                 else
2727                                         set_func = g_strdup_printf ("g_value_set%s_%s",
2728                                                                     do_static ? "_static" : "",
2729                                                                     (char *)m->gtktypes->data);
2730                                 g_strdown (set_func);
2731
2732                                 out_printf (out, "\t%s (&___return_val, (%s) (%s));\n",
2733                                             set_func, cast, defret);
2734
2735                                 g_free (set_func);
2736                                 g_free (cast);
2737                         }
2738                         out_printf (out, "\n");
2739                 }
2740
2741                 s = g_strdup (m->id);
2742                 g_strup (s);
2743
2744                 out_printf(out, "\tg_signal_emitv (___param_values,\n"
2745                            "\t\tobject_signals[%s_SIGNAL],\n"
2746                            "\t\t0 /* detail */,\n"
2747                            "\t\t&___return_val);\n", s);
2748
2749                 g_free (s);
2750
2751                 clear_signal_args (m);
2752
2753                 if (strcmp (m->gtktypes->data, "NONE") != 0) {
2754                         char *cast = g_strdup (get_cast (m->gtktypes->data, FALSE));
2755                         char *getfunc;
2756                         /* Hack because glib is very very braindead */
2757                         gboolean do_dup = 
2758                                 (strcmp ((char *)m->gtktypes->data, "STRING") == 0 ||
2759                                  strcmp ((char *)m->gtktypes->data, "BOXED") == 0 ||
2760                                  strcmp ((char *)m->gtktypes->data, "OBJECT") == 0 ||
2761                                  strcmp ((char *)m->gtktypes->data, "PARAM") == 0);
2762
2763                         if (strcmp (m->gtktypes->data, "UNICHAR") == 0)
2764                                 /* hack because glib is braindamaged */
2765                                 getfunc = g_strdup ("g_value_get_uint");
2766                         else
2767                                 getfunc = g_strdup_printf ("g_value_%s_%s",
2768                                                            do_dup ? "dup" : "get",
2769                                                            (char *)m->gtktypes->data);
2770                         g_strdown (getfunc);
2771
2772                         if (cast == NULL)
2773                                 cast = get_type (m->mtype, TRUE);
2774
2775                         out_printf (out,
2776                                     "\n\t{\n"
2777                                     "\t\t");
2778                         print_type (out, m->mtype, TRUE);
2779                         out_printf (out,
2780                                     " ___ret = (%s) %s (&___return_val);\n"
2781                                     "\t\tg_value_unset (&___return_val);\n"
2782                                     "\t\treturn ___ret;\n"
2783                                     "\t}\n",
2784                                     cast, getfunc);
2785
2786                         g_free (cast);
2787                         g_free (getfunc);
2788                 }
2789                 out_printf(out, "}\n");
2790
2791                 if(!m->cbuf)
2792                         break;
2793                 if(m->line_no > 0)
2794                         out_addline_infile(out, m->line_no);
2795                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
2796                              m, FALSE, FALSE, TRUE);
2797                 print_method_body(m, FALSE);
2798                 /* the outfile line was added above */
2799                 break;
2800         case VIRTUAL_METHOD:
2801                 if(m->line_no > 0)
2802                         out_addline_infile(out, m->line_no);
2803                 if(m->scope==PRIVATE_SCOPE)
2804                         print_method(out, "static ", "\n", "", " ", "", "\n",
2805                                      m, FALSE, FALSE, TRUE);
2806                 else /* PUBLIC, PROTECTED */
2807                         print_method(out, "", "\n", "", " ", "", "\n",
2808                                      m, FALSE, FALSE, TRUE);
2809                 out_addline_outfile(out);
2810                 out_printf(out, "{\n"
2811                         "\t%sClass *klass;\n", typebase);
2812                 print_preconditions(m);
2813                 out_printf(out, "\tklass = %s_GET_CLASS(%s);\n\n"
2814                         "\tif(klass->%s)\n",
2815                         macrobase, ((FuncArg *)m->args->data)->name,
2816                         m->id);
2817                 if(strcmp(m->mtype->name, "void") == 0 &&
2818                    m->mtype->pointer == NULL) {
2819                         GList *li;
2820                         out_printf(out, "\t\t(*klass->%s)(%s",
2821                                    m->id,
2822                                    ((FuncArg *)m->args->data)->name);
2823                         for(li=m->args->next;li;li=g_list_next(li)) {
2824                                 FuncArg *fa = li->data;
2825                                 out_printf(out, ",%s", fa->name);
2826                         }
2827                         out_printf(out, ");\n}\n");
2828                 } else {
2829                         GList *li;
2830                         out_printf(out, "\t\treturn (*klass->%s)(%s",
2831                                    m->id,
2832                                    ((FuncArg *)m->args->data)->name);
2833                         for(li=m->args->next;li;li=g_list_next(li)) {
2834                                 FuncArg *fa = li->data;
2835                                 out_printf(out, ",%s", fa->name);
2836                         }
2837                         out_printf(out, ");\n"
2838                                 "\telse\n"
2839                                 "\t\treturn (");
2840                         print_type(out, m->mtype, TRUE);
2841                         if(m->defreturn)
2842                                 out_printf(out, ")(%s);\n}\n", m->defreturn);
2843                         else if(m->onerror)
2844                                 out_printf(out, ")(%s);\n}\n", m->onerror);
2845                         else
2846                                 out_printf(out, ")(0);\n}\n");
2847                 }
2848
2849                 if(!m->cbuf)
2850                         break;
2851                 if(m->line_no > 0)
2852                         out_addline_infile(out, m->line_no);
2853                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
2854                              m, FALSE, FALSE, TRUE);
2855                 print_method_body(m, FALSE);
2856                 /* the outfile line was added above */
2857                 break;
2858         case OVERRIDE_METHOD:
2859                 if(!m->cbuf)
2860                         break;
2861                 if(m->line_no > 0)
2862                         out_addline_infile(out, m->line_no);
2863                 s = g_strdup_printf("\n___%x_", (guint)m->unique_id);
2864                 print_method(out, "static ", s, "", " ", "", "\n",
2865                              m, FALSE, FALSE, FALSE);
2866                 g_free(s);
2867                 out_addline_outfile(out);
2868                 s = replace_sep(m->otype, '_');
2869                 g_strup(s);
2870                 args = get_arg_names_for_macro(m);
2871                 if(is_void) {
2872                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
2873                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
2874                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n",
2875                                    args, s, m->id, s, m->id, args);
2876                 } else {
2877                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
2878                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
2879                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n"
2880                                    "\t\t(",
2881                                    args, s, m->id, s, m->id, args);
2882                         out_printf(out, "(");
2883                         print_type(out, m->mtype, TRUE);
2884                         out_printf(out, ")%s))\n",
2885                                    m->onerror?m->onerror:"0");
2886                 }
2887                 g_free(args);
2888                 g_free(s);
2889                 print_method_body(m, TRUE);
2890                 /* the outfile line was added above */
2891                 out_printf(out, "#undef PARENT_HANDLER\n");
2892                 break;
2893         default:
2894                 break;
2895         }
2896 }
2897
2898 static void
2899 open_files(void)
2900 {
2901         char *outfile, *outfileh, *outfileph;
2902
2903         if ( ! for_cpp)
2904                 outfile = g_strconcat (filebase, ".c", NULL);
2905         else
2906                 outfile = g_strconcat (filebase, ".cc", NULL);
2907         if (no_touch_headers)
2908                 outfileh = g_strconcat ("#gob#", filebase, ".h#gob#", NULL);
2909         else
2910                 outfileh = g_strconcat (filebase, ".h", NULL);
2911
2912         if ((privates > 0 || protecteds > 0 ||
2913              private_header == PRIVATE_HEADER_ALWAYS) &&
2914             private_header != PRIVATE_HEADER_NEVER)
2915                 outfileph = g_strconcat (filebase, "-private.h", NULL);
2916         else
2917                 outfileph = NULL;
2918
2919         
2920         if (no_write) {
2921                 devnull = fopen ("/dev/null", "w");
2922                 if (devnull == NULL)
2923                         g_error ("Cannot open null device");
2924                 out = devnull;
2925                 outh = devnull;
2926                 if (outfileph != NULL)
2927                         outph = devnull;
2928         } else {
2929                 out = fopen (outfile, "w");
2930                 if (out == NULL) {
2931                         g_error ("Cannot open outfile: %s", outfile);
2932                 }
2933                 outh = fopen (outfileh, "w");
2934                 if (outh == NULL)
2935                         g_error ("Cannot open outfile: %s", outfileh);
2936                 if (outfileph != NULL) {
2937                         outph = fopen (outfileph, "w");
2938                         if (outph == NULL)
2939                                 g_error ("Cannot open outfile: %s", outfileh);
2940                 }
2941         }
2942 }
2943
2944 static void
2945 put_argument_nongnu_wrappers (Class *c)
2946 {
2947         GList *li;
2948
2949         if (get_properties < 0 && set_properties < 0)
2950                 return;
2951
2952         for (li = c->nodes; li != NULL; li = li->next) {
2953                 Node *n = li->data;
2954                 const char *name, *gtktype;
2955                 gboolean get, set;
2956                 Type *atype;
2957                 char *aname;
2958                 char *cast;
2959
2960                 if (n->type == ARGUMENT_NODE) {
2961                         Argument *a = (Argument *)n;
2962                         name = a->name;
2963                         gtktype = a->gtktype;
2964                         atype = a->atype;
2965                         get = a->get != NULL;
2966                         set = a->set != NULL;
2967                 } else if (n->type == PROPERTY_NODE) {
2968                         Property *p = (Property *)n;
2969                         name = p->name;
2970                         gtktype = p->gtktype;
2971                         atype = p->ptype;
2972                         get = p->get != NULL;
2973                         set = p->set != NULL;
2974                 } else {
2975                         continue;
2976                 }
2977
2978                 aname = g_strdup (name);
2979                 g_strup (aname);
2980
2981                 if (atype != NULL)
2982                         cast = get_type (atype, TRUE);
2983                 else
2984                         cast = g_strdup (get_cast (gtktype, TRUE));
2985
2986                 if (cast != NULL) {
2987                         if (set)
2988                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
2989                                             "\"%s\",(%s)(arg)\n",
2990                                             macrobase, aname, name, cast);
2991                         if (get)
2992                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
2993                                             "\"%s\",(%s*)(arg)\n",
2994                                             macrobase, aname, name, cast);
2995                 } else {
2996                         if(set)
2997                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
2998                                             "\"%s\",(arg)\n",
2999                                             macrobase, aname, name);
3000                         if(get)
3001                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3002                                             "\"%s\",(arg)\n",
3003                                             macrobase, aname, name);
3004                 }
3005                 g_free (cast);
3006                 g_free (aname);
3007         }
3008 }
3009
3010 static void
3011 put_argument_gnu_wrappers(Class *c)
3012 {
3013         GList *li;
3014
3015         if(get_properties < 0 && set_properties < 0)
3016                 return;
3017
3018         for (li = c->nodes; li != NULL; li = li->next) {
3019                 Node *n = li->data;
3020                 const char *name, *gtktype;
3021                 gboolean get, set;
3022                 Type *atype;
3023                 char *aname;
3024                 char *cast;
3025
3026                 if (n->type == ARGUMENT_NODE) {
3027                         Argument *a = (Argument *)n;
3028                         name = a->name;
3029                         gtktype = a->gtktype;
3030                         atype = a->atype;
3031                         get = a->get != NULL;
3032                         set = a->set != NULL;
3033                 } else if (n->type == PROPERTY_NODE) {
3034                         Property *p = (Property *)n;
3035                         name = p->name;
3036                         gtktype = p->gtktype;
3037                         atype = p->ptype;
3038                         get = p->get != NULL;
3039                         set = p->set != NULL;
3040                 } else {
3041                         continue;
3042                 }
3043
3044                 aname = g_strdup (name);
3045                 g_strup (aname);
3046
3047                 if (atype != NULL)
3048                         cast = get_type (atype, TRUE);
3049                 else
3050                         cast = g_strdup (get_cast (gtktype, TRUE));
3051
3052                 if (cast != NULL) {
3053                         if (set)
3054                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3055                                            "\"%s\",({%sz = (arg); z;})\n",
3056                                            macrobase, aname, name, cast);
3057                         if (get)
3058                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3059                                            "\"%s\",({%s*z = (arg); z;})\n",
3060                                            macrobase, aname, name, cast);
3061                 } else {
3062                         if (set)
3063                                 out_printf (outh, "#define %s_PROP_%s(arg)    \t"
3064                                            "\"%s\",(arg)\n",
3065                                            macrobase, aname, name);
3066                         if (get)
3067                                 out_printf (outh, "#define %s_GET_PROP_%s(arg)\t"
3068                                            "\"%s\",(arg)\n",
3069                                            macrobase, aname, name);
3070                 }
3071                 g_free (cast);
3072                 g_free (aname);
3073         }
3074 }
3075
3076 static void
3077 print_ccode_block(CCode *cc)
3078 {
3079         FILE *fp;
3080         switch(cc->cctype) {
3081         case HT_CCODE:
3082                 /* HT code is printed exactly like normal header
3083                    code but is printed before */
3084         case H_CCODE:
3085                 fp = outh;
3086                 out_printf(fp, "\n");
3087                 break;
3088         case AT_CCODE:
3089                 /* AT code is printed exactly like normal 'all'
3090                    code but is printed before */
3091         case A_CCODE:
3092                 if(outph) {
3093                         out_printf(outph, "\n");
3094                         out_printf(outph, "%s\n", cc->cbuf);
3095                         out_addline_infile(outph, cc->line_no);
3096                         out_addline_outfile(outph);
3097                 }
3098                 out_printf(outh, "\n");
3099                 out_printf(outh, "%s\n", cc->cbuf);
3100                 fp = out;
3101                 out_printf(fp, "\n");
3102                 out_addline_infile(fp, cc->line_no);
3103                 break;
3104         default:
3105         case C_CCODE:
3106                 fp = out;
3107                 out_printf(fp, "\n");
3108                 out_addline_infile(fp, cc->line_no);
3109                 break;
3110         case PH_CCODE:
3111                 if(outph)
3112                         fp = outph;
3113                 else
3114                         fp = out;
3115                 out_printf(fp, "\n");
3116                 out_addline_infile(fp, cc->line_no);
3117                 break;
3118         }
3119         out_printf(fp, "%s\n", cc->cbuf);
3120         if(cc->cctype == C_CCODE ||
3121            cc->cctype == A_CCODE ||
3122            cc->cctype == AT_CCODE ||
3123            cc->cctype == PH_CCODE)
3124                 out_addline_outfile(fp);
3125 }
3126
3127 static void
3128 print_class_block(Class *c)
3129 {
3130         GList *li;
3131         char *s;
3132         gboolean printed_private = FALSE;
3133
3134         if(any_special) {
3135                 out_printf(out, "/* utility types we may need */\n");
3136                 if(special_array[SPECIAL_2POINTER])
3137                         out_printf(out, "typedef struct { "
3138                                    "gpointer a; gpointer b; "
3139                                    "} ___twopointertype;\n");
3140                 if(special_array[SPECIAL_3POINTER])
3141                         out_printf(out, "typedef struct { "
3142                                    "gpointer a; gpointer b; "
3143                                    "gpointer c; "
3144                                    "} ___threepointertype;\n");
3145                 if(special_array[SPECIAL_INT_POINTER])
3146                         out_printf(out, "typedef struct { "
3147                                    "gint a; gpointer b; "
3148                                    "} ___intpointertype;\n");
3149                 out_printf(out, "\n");
3150         }
3151
3152         out_printf(outh, "\n/*\n"
3153                    " * Type checking and casting macros\n"
3154                    " */\n");
3155         out_printf(outh, "#define %s\t"
3156                    "(%s_get_type())\n",
3157                    macrotype, funcbase);
3158         out_printf(outh, "#define %s(obj)\t"
3159                    "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s)\n",
3160                    macrobase, funcbase, typebase);
3161         out_printf(outh, "#define %s_CONST(obj)\t"
3162                    "G_TYPE_CHECK_INSTANCE_CAST((obj), %s_get_type(), %s const)\n",
3163                    macrobase, funcbase, typebase); 
3164         out_printf(outh, "#define %s_CLASS(klass)\t"
3165                    "G_TYPE_CHECK_CLASS_CAST((klass), %s_get_type(), %sClass)\n",
3166                    macrobase, funcbase, typebase);
3167         out_printf(outh, "#define %s(obj)\t"
3168                    "G_TYPE_CHECK_INSTANCE_TYPE((obj), %s_get_type ())\n\n",
3169                    macrois, funcbase);
3170         out_printf(outh,
3171                    "#define %s_GET_CLASS(obj)\t"
3172                    "G_TYPE_INSTANCE_GET_CLASS((obj), %s_get_type(), %sClass)\n",
3173                    macrobase, funcbase, typebase);
3174
3175         if ( ! no_self_alias) {
3176                 out_printf(out, "/* self casting macros */\n");
3177                 out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
3178                 out_printf(out, "#define SELF_CONST(x) %s_CONST(x)\n", macrobase);
3179                 out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
3180                 out_printf(out, "#define TYPE_SELF %s\n", macrotype);
3181                 out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n",
3182                            macrobase);
3183                 out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n",
3184                            macrobase);
3185
3186                 out_printf(out, "/* self typedefs */\n");
3187                 out_printf(out, "typedef %s Self;\n", typebase);
3188                 out_printf(out, "typedef %sClass SelfClass;\n\n", typebase);
3189         }
3190
3191         if (privates > 0 ||
3192             always_private_struct) {
3193                 out_printf (outh, "\n/* Private structure type */\n");
3194                 out_printf (outh, "typedef struct _%sPrivate %sPrivate;\n",
3195                            typebase, typebase);
3196                 if (privates == 0)
3197                         out_printf (outh, "/* There are no privates, this "
3198                                     "structure is thus never defined */\n");
3199         }
3200
3201         out_printf (outh, "\n/*\n"
3202                     " * Main object structure\n"
3203                     " */\n");
3204         s = replace_sep (c->otype, '_');
3205         g_strup (s);
3206         out_printf (outh, "#ifndef __TYPEDEF_%s__\n"
3207                     "#define __TYPEDEF_%s__\n", s, s);
3208         g_free (s);
3209         out_printf (outh, "typedef struct _%s %s;\n"
3210                     "#endif\n", typebase, typebase);
3211         out_printf (outh, "struct _%s {\n\t%s __parent__;\n",
3212                     typebase, ptypebase);
3213         for (li = c->nodes; li; li=li->next) {
3214                 static gboolean printed_public = FALSE;
3215                 Node *n = li->data;
3216                 Variable *v = (Variable *)n;
3217                 if(n->type == VARIABLE_NODE &&
3218                    v->scope == PUBLIC_SCOPE) {
3219                         if( ! printed_public) {
3220                                 out_printf(outh, "\t/*< public >*/\n");
3221                                 printed_public = TRUE;
3222                         }
3223                         put_variable((Variable *)n, outh);
3224                 }
3225         }
3226         /* put protecteds always AFTER publics */
3227         for (li = c->nodes; li != NULL; li = li->next) {
3228                 Node *n = li->data;
3229                 Variable *v = (Variable *)n;
3230                 if (n->type == VARIABLE_NODE &&
3231                     v->scope == PROTECTED_SCOPE) {
3232                         if ( ! printed_private) {
3233                                 out_printf (outh, "\t/*< private >*/\n");
3234                                 printed_private = TRUE;
3235                         }
3236                         put_variable ((Variable *)n, outh);
3237                 }
3238         }
3239         if (privates > 0 ||
3240             always_private_struct) {
3241                 if ( ! printed_private)
3242                         out_printf (outh, "\t/*< private >*/\n");
3243                 out_printf (outh, "\t%sPrivate *_priv;\n", typebase);
3244         }
3245         out_printf (outh, "};\n");
3246
3247         if (privates > 0) {
3248                 FILE *outfp;
3249
3250                 /* if we are to stick this into the private
3251                    header, if not stick it directly into the
3252                    C file */
3253                 if (outph != NULL) 
3254                         outfp = outph;
3255                 else
3256                         outfp = out;
3257
3258                 out_printf (outfp, "struct _%sPrivate {\n",
3259                             typebase);
3260                 for(li=c->nodes; li; li=li->next) {
3261                         Node *n = li->data;
3262                         Variable *v = (Variable *)n;
3263                         if(n->type == VARIABLE_NODE &&
3264                            v->scope == PRIVATE_SCOPE) {
3265                                 out_addline_infile(outfp, v->line_no);
3266                                 put_variable(v, outfp);
3267                         }
3268                 }
3269                 out_addline_outfile(outfp);
3270                 out_printf(outfp, "};\n");
3271         }
3272
3273         out_printf(outh, "\n/*\n"
3274                    " * Class definition\n"
3275                    " */\n");
3276         out_printf(outh, "typedef struct _%sClass %sClass;\n",
3277                    typebase, typebase);
3278         out_printf(outh,
3279                    "struct _%sClass {\n\t%sClass __parent__;\n",
3280                    typebase, ptypebase);
3281         for(li = c->nodes; li != NULL; li = li->next) {
3282                 Node *n = li->data;
3283                 if(n->type == METHOD_NODE)
3284                         put_vs_method((Method *)n);
3285         }
3286         /* If BonoboX type class put down the epv */
3287         if (c->bonobo_object_class != NULL) {
3288                 out_printf (outh,
3289                             "\t/* Bonobo object epv */\n"
3290                             "\tPOA_%s__epv _epv;\n",
3291                             c->bonobo_object_class);
3292         }
3293         /* put class scope variables */
3294         for (li = c->nodes; li != NULL; li = li->next) {
3295                 Node *n = li->data;
3296                 Variable *v = (Variable *)n;
3297                 if (n->type == VARIABLE_NODE &&
3298                     v->scope == CLASS_SCOPE)
3299                         put_variable ((Variable *)n, outh);
3300         }
3301         out_printf (outh, "};\n\n");
3302
3303         out_printf (out, "/* here are local prototypes */\n");
3304         if (set_properties > 0) {
3305                 out_printf (out, "static void ___object_set_property "
3306                             "(GObject *object, guint property_id, "
3307                             "const GValue *value, GParamSpec *pspec);\n");
3308         }
3309         if (get_properties > 0) {
3310                 out_printf (out, "static void ___object_get_property "
3311                             "(GObject *object, guint property_id, "
3312                             "GValue *value, GParamSpec *pspec);\n");
3313         }
3314
3315         out_printf (outh, "\n/*\n"
3316                     " * Public methods\n"
3317                     " */\n");
3318
3319         if ( ! overrode_get_type) {
3320                 out_printf (outh, "GType\t%s_get_type\t(void);\n", funcbase);
3321         }
3322
3323         for(li = c->nodes; li != NULL; li = li->next) {
3324                 Node *n = li->data;
3325                 if(n->type == METHOD_NODE) {
3326                         put_pub_method((Method *)n);
3327                         put_prot_method((Method *)n);
3328                         put_priv_method_prot((Method *)n);
3329                 }
3330         }
3331
3332         /* this idea is less and less apealing to me */
3333         if (signals > 0) {
3334                 out_printf (outh, "\n/*\n"
3335                             " * Signal connection wrapper macros\n"
3336                             " */\n");
3337                 if( ! no_gnu) {
3338                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
3339                         put_signal_macros (c, TRUE);
3340                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
3341                         put_signal_macros (c, FALSE);
3342                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n");
3343                 } else {
3344                         put_signal_macros (c, FALSE);
3345                         out_printf(outh, "\n");
3346                 }
3347
3348                 out_printf (out, "\n/*\n"
3349                             " * Signal connection wrapper macro shortcuts\n"
3350                             " */\n");
3351                 put_local_signal_macros (c);
3352                 out_printf(outh, "\n");
3353         }
3354
3355         /* argument wrapping macros */
3356         if(get_properties > 0 || set_properties > 0) {
3357                 out_printf(outh, "\n/*\n"
3358                            " * Argument wrapping macros\n"
3359                            " */\n");
3360                 if( ! no_gnu) {
3361                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
3362                         put_argument_gnu_wrappers(c);
3363                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
3364                         put_argument_nongnu_wrappers(c);
3365                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
3366                 } else {
3367                         put_argument_nongnu_wrappers(c);
3368                 }
3369         }
3370
3371         if(signals > 0) {
3372                 for(li = c->nodes; li != NULL; li = li->next) {
3373                         Node *n = li->data;
3374                         if(n->type == METHOD_NODE)
3375                                 add_signal_prots((Method *)n);
3376                 }
3377         }
3378
3379         add_enums (c);
3380
3381         if(any_method_to_alias(c)) {
3382                 if( ! no_gnu) {
3383                         out_printf(out, "/* Short form macros */\n");
3384                         out_printf(out, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
3385                         make_method_gnu_aliases(c);
3386                         out_printf(out, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n");
3387                 }
3388                 make_method_nongnu_aliases(c);
3389         }
3390
3391         add_interface_inits (c);
3392
3393         if ( ! overrode_get_type) {
3394                 if (c->bonobo_object_class != NULL)
3395                         add_bonobo_object_get_type ();
3396                 else
3397                         add_get_type ();
3398         }
3399
3400         out_printf (out, "/* a macro for creating a new object of our type */\n");
3401         out_printf (out,
3402                     "#define GET_NEW ((%s *)g_object_new(%s_get_type(), NULL))\n\n",
3403                     typebase, funcbase);
3404
3405         out_printf (out, "/* a function for creating a new object of our type */\n");
3406         out_printf (out, "#include <stdarg.h>\n");
3407         out_printf (out,
3408                     "static %s * GET_NEW_VARG (const char *first, ...)%s;\n"
3409                     "static %s *\nGET_NEW_VARG (const char *first, ...)\n"
3410                     "{\n\t%s *ret;\n\tva_list ap;\n"
3411                     "\tva_start (ap, first);\n"
3412                     "\tret = (%s *)g_object_new_valist (%s_get_type (), "
3413                     "first, ap);\n"
3414                     "\tva_end (ap);\n"
3415                     "\treturn ret;\n}\n\n",
3416                     typebase,
3417                     no_gnu ? "" : " G_GNUC_UNUSED",
3418                     typebase, typebase, typebase, funcbase);
3419
3420         if (need_dispose)
3421                 add_dispose (c);
3422
3423         if (need_finalize)
3424                 add_finalize (c);
3425
3426         add_inits(c);
3427
3428         if(set_properties > 0) {
3429                 add_getset_arg(c, TRUE);
3430         }
3431
3432         if(get_properties > 0) {
3433                 add_getset_arg(c, FALSE);
3434         }
3435
3436         for(li = c->nodes; li != NULL; li = li->next) {
3437                 Node *n = li->data;
3438                 if(n->type == METHOD_NODE)
3439                         put_method((Method *)n);
3440         }
3441
3442         add_bad_hack_to_avoid_unused_warnings(c);
3443 }
3444
3445 static void
3446 print_useful_macros(void)
3447 {
3448         int major = 0, minor = 0, pl = 0;
3449
3450         /* Version stuff */
3451         sscanf (VERSION, "%d.%d.%d", &major, &minor, &pl);
3452         out_printf (out, "#define GOB_VERSION_MAJOR %d\n", major);
3453         out_printf (out, "#define GOB_VERSION_MINOR %d\n", minor);
3454         out_printf (out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
3455
3456         /* Useful priv macro thingie */
3457         /* FIXME: this should be done the same way that priv is, as a var,
3458          * not a define */
3459         out_printf (out, "#define selfp (self->_priv)\n\n");
3460 }
3461
3462 static void
3463 print_more_useful_macros (void)
3464 {
3465         if (no_gnu) {
3466                 out_printf (out, "#define ___GOB_LIKELY(expr) (expr)\n");
3467                 out_printf (out, "#define ___GOB_UNLIKELY(expr) (expr)\n");
3468         } else {
3469                 out_printf (out, "#ifdef G_LIKELY\n");
3470                 out_printf (out, "#define ___GOB_LIKELY(expr) G_LIKELY(expr)\n");
3471                 out_printf (out, "#define ___GOB_UNLIKELY(expr) G_UNLIKELY(expr)\n");
3472                 out_printf (out, "#else /* ! G_LIKELY */\n");
3473                 out_printf (out, "#define ___GOB_LIKELY(expr) (expr)\n");
3474                 out_printf (out, "#define ___GOB_UNLIKELY(expr) (expr)\n");
3475                 out_printf (out, "#endif /* G_LIKELY */\n");
3476         }
3477 }
3478
3479 static void
3480 print_file_comments(void)
3481 {
3482         time_t curtime;
3483         time(&curtime);
3484         out_printf(outh, "/* Generated by GOB (v%s)"
3485                    "   (do not edit directly) */\n\n", VERSION);
3486         if(outph)
3487                 out_printf(outph, "/* Generated by GOB (v%s)"
3488                            "   (do not edit directly) */\n\n", VERSION);
3489         out_printf(out, "/* Generated by GOB (v%s) on %s"
3490                    "   (do not edit directly) */\n\n",
3491                    VERSION, ctime(&curtime));
3492
3493         out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
3494 }
3495
3496 static void
3497 print_includes(void)
3498 {
3499         gboolean found_header;
3500         char *p;
3501
3502         /* We may need string.h for memset */
3503         if(destructors > 0 &&
3504            ! g_list_find_custom(include_files, "string.h", (GCompareFunc)strcmp)) {
3505                 out_printf(out, "#include <string.h> /* memset() */\n\n");
3506         }
3507
3508         p = g_strconcat(filebase, ".h", NULL);
3509         found_header = TRUE;
3510         if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
3511                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
3512                 found_header = FALSE;
3513         }
3514         g_free(p);
3515
3516         /* if we are creating a private header see if it was included */
3517         if(outph) {
3518                 p = g_strconcat(filebase, "-private.h", NULL);
3519                 if( ! g_list_find_custom(include_files, p,
3520                                          (GCompareFunc)strcmp)) {
3521                         out_printf(out, "#include \"%s-private.h\"\n\n",
3522                                    filebase);
3523                         if(found_header)
3524                                 error_printf(GOB_WARN, 0,
3525                                             "Implicit private header include "
3526                                             "added to top of\n"
3527                                             "\tsource file, while public "
3528                                             "header is at a custom location, "
3529                                             "you should\n"
3530                                             "\texplicitly include "
3531                                             "the private header below the "
3532                                             "public one.");
3533                 }
3534                 g_free(p);
3535         }
3536 }
3537
3538 static void
3539 print_header_prefixes(void)
3540 {
3541         char *p;
3542
3543         p = replace_sep(((Class *)class)->otype, '_');
3544         g_strup(p);
3545         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
3546         if(outph)
3547                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
3548                            "#define __%s_PRIVATE_H__\n\n"
3549                            "#include \"%s.h\"\n\n", p, p, filebase);
3550         g_free(p);
3551
3552         if( ! no_extern_c) {
3553                 out_printf(outh, "#ifdef __cplusplus\n"
3554                            "extern \"C\" {\n"
3555                            "#endif /* __cplusplus */\n\n");
3556                 if(outph)
3557                         out_printf(outph, "#ifdef __cplusplus\n"
3558                                    "extern \"C\" {\n"
3559                                    "#endif /* __cplusplus */\n\n");
3560         }
3561 }
3562
3563 static void
3564 print_header_postfixes(void)
3565 {
3566         if( ! no_extern_c)
3567                 out_printf(outh, "\n#ifdef __cplusplus\n"
3568                            "}\n"
3569                            "#endif /* __cplusplus */\n");
3570         out_printf(outh, "\n#endif\n");
3571         if(outph) {
3572                 if( ! no_extern_c)
3573                         out_printf(outph, "\n#ifdef __cplusplus\n"
3574                                    "}\n"
3575                                    "#endif /* __cplusplus */\n");
3576                 out_printf(outph, "\n#endif\n");
3577         }
3578 }
3579
3580 static void
3581 print_all_top(void)
3582 {
3583         GList *li;
3584
3585         /* print the AT_CCODE blocks */
3586         for(li = nodes; li != NULL; li = li->next) {
3587                 Node *node = li->data;
3588                 if(node->type == CCODE_NODE) {
3589                         CCode *cc = (CCode *)node;
3590                         if(cc->cctype == AT_CCODE)
3591                                 print_ccode_block((CCode *)node);
3592                 }
3593         }
3594 }
3595
3596 static void
3597 print_header_top(void)
3598 {
3599         GList *li;
3600
3601         /* mandatory includes */
3602         out_printf (outh, "#include <glib.h>\n");
3603         out_printf (outh, "#include <glib-object.h>\n");
3604
3605         /* print the HT_CCODE blocks */
3606         for (li = nodes; li != NULL; li = li->next) {
3607                 Node *node = li->data;
3608                 if (node->type == CCODE_NODE) {
3609                         CCode *cc = (CCode *)node;
3610                         if (cc->cctype == HT_CCODE)
3611                                 print_ccode_block ((CCode *)node);
3612                 }
3613         }
3614 }
3615
3616 static void
3617 print_enum (EnumDef *enode)
3618 {
3619         GList *li;
3620         char *funcprefix;
3621         char *type;
3622         char *str;
3623
3624         funcprefix = replace_sep (enode->etype, '_');
3625         g_strdown (funcprefix);
3626         out_printf (out, "static const GEnumValue _%s_values[] = {\n",
3627                     funcprefix);
3628         type = remove_sep (enode->etype);
3629
3630         out_printf (outh, "\ntypedef enum {\n");
3631
3632         for (li = enode->values; li != NULL; li = li->next) {
3633                 EnumValue *value = li->data; 
3634                 char *p;
3635                 char *sname = g_strdown (g_strdup (value->name));
3636
3637                 while ((p = strchr (sname, '_')) != NULL)
3638                         *p = '-';
3639
3640                 out_printf (outh, "\t%s_%s", enode->prefix, value->name);
3641                 if (value->value != NULL)
3642                         out_printf (outh, " = %s", value->value);
3643                 if (li->next != NULL)
3644                         out_printf (outh, ",\n");
3645                 else
3646                         out_printf (outh, "\n");
3647
3648                 out_printf (out, "\t{ %s_%s, \"%s_%s\", \"%s\" },\n",
3649                             enode->prefix, value->name,
3650                             enode->prefix, value->name,
3651                             sname);
3652
3653                 g_free (sname);
3654         }
3655
3656         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
3657
3658         out_printf (outh, "} %s;\n", type);
3659
3660         str = make_pre_macro (enode->etype, "TYPE");
3661         out_printf (outh, "#define %s ", str);
3662         g_free (str);
3663
3664         out_printf (outh, "%s_get_type()\n", funcprefix);
3665         out_printf (outh, "GType %s_get_type (void);\n\n", funcprefix);
3666
3667         out_printf (out,
3668                     "GType\n%s_get_type (void)\n"
3669                     "{\n"
3670                     "\tstatic GType type = 0;\n"
3671                     "\tif ___GOB_UNLIKELY(type == 0)\n"
3672                     "\t\ttype = g_enum_register_static (\"%s\", _%s_values);\n"
3673                     "\treturn type;\n"
3674                     "}\n\n",
3675                     funcprefix, type, funcprefix);
3676
3677         g_free (funcprefix);
3678         g_free (type);
3679 }
3680
3681 static void
3682 print_flags (Flags *fnode)
3683 {
3684         GList *li;
3685         char *funcprefix;
3686         char *type;
3687         char *str;
3688         int i;
3689
3690         funcprefix = replace_sep (fnode->ftype, '_');
3691         g_strdown (funcprefix);
3692         out_printf (out, "static const GFlagsValue _%s_values[] = {\n",
3693                     funcprefix);
3694         type = remove_sep (fnode->ftype);
3695
3696         out_printf (outh, "\ntypedef enum {\n");
3697
3698         for (i = 0, li = fnode->values; li != NULL; i++, li = li->next) {
3699                 const char *name = li->data; 
3700                 char *p;
3701                 char *sname = g_strdown (g_strdup (name));
3702
3703                 while ((p = strchr (sname, '_')) != NULL)
3704                         *p = '-';
3705
3706                 out_printf (outh, "\t%s_%s = 1<<%d",
3707                             fnode->prefix, name, i);
3708                 if (li->next != NULL)
3709                         out_printf (outh, ",\n");
3710                 else
3711                         out_printf (outh, "\n");
3712
3713                 out_printf (out, "\t{ %s_%s, \"%s_%s\", \"%s\" },\n",
3714                             fnode->prefix, name,
3715                             fnode->prefix, name,
3716                             sname);
3717
3718                 g_free (sname);
3719         }
3720
3721         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
3722
3723         out_printf (outh, "} %s;\n", type);
3724
3725         str = make_pre_macro (fnode->ftype, "TYPE");
3726         out_printf (outh, "#define %s ", str);
3727         g_free (str);
3728
3729         out_printf (outh, "%s_get_type()\n", funcprefix);
3730         out_printf (outh, "GType %s_get_type (void);\n\n", funcprefix);
3731
3732         out_printf (out,
3733                     "GType\n%s_get_type (void)\n"
3734                     "{\n"
3735                     "\tstatic GType type = 0;\n"
3736                     "\tif ___GOB_UNLIKELY(type == 0)\n"
3737                     "\t\ttype = g_flags_register_static (\"%s\", _%s_values);\n"
3738                     "\treturn type;\n"
3739                     "}\n\n",
3740                     funcprefix, type, funcprefix);
3741
3742         g_free (funcprefix);
3743         g_free (type);
3744 }
3745
3746 static void
3747 print_error (Error *enode)
3748 {
3749         GList *li;
3750         char *funcprefix;
3751         char *type;
3752         char *str;
3753
3754         funcprefix = replace_sep (enode->etype, '_');
3755         g_strdown (funcprefix);
3756         out_printf (out, "static const GEnumValue _%s_values[] = {\n",
3757                     funcprefix);
3758         type = remove_sep (enode->etype);
3759
3760         out_printf (outh, "\ntypedef enum {\n");
3761
3762         for (li = enode->values; li != NULL; li = li->next) {
3763                 const char *name = li->data;
3764                 char *p;
3765                 char *sname = g_strdown (g_strdup (name));
3766
3767                 while ((p = strchr (sname, '_')) != NULL)
3768                         *p = '-';
3769
3770                 out_printf (outh, "\t%s_%s", enode->prefix, name);
3771                 if (li->next != NULL)
3772                         out_printf (outh, ",\n");
3773                 else
3774                         out_printf (outh, "\n");
3775
3776                 out_printf (out, "\t{ %s_%s, \"%s_%s\", \"%s\" },\n",
3777                             enode->prefix, name,
3778                             enode->prefix, name,
3779                             sname);
3780
3781                 g_free (sname);
3782         }
3783
3784         out_printf (out, "\t{ 0, NULL, NULL }\n};\n\n");
3785
3786         out_printf (outh, "} %s;\n", type);
3787
3788         str = make_pre_macro (enode->etype, "TYPE");
3789         out_printf (outh, "#define %s ", str);
3790         g_free (str);
3791
3792         out_printf (outh, "%s_get_type ()\n", funcprefix);
3793         out_printf (outh, "GType %s_get_type (void);\n\n", funcprefix);
3794
3795         out_printf (out,
3796                     "GType\n%s_get_type (void)\n"
3797                     "{\n"
3798                     "\tstatic GType type = 0;\n"
3799                     "\tif ___GOB_UNLIKELY(type == 0)\n"
3800                     "\t\ttype = g_enum_register_static (\"%s\", _%s_values);\n"
3801                     "\treturn type;\n"
3802                     "}\n\n",
3803                     funcprefix, type, funcprefix);
3804
3805         out_printf (outh, "#define %s %s_quark ()\n", enode->prefix, funcprefix);
3806         out_printf (outh, "GQuark %s_quark (void);\n\n", funcprefix);
3807
3808         str = replace_sep (enode->etype, '-');
3809         g_strdown (str);
3810
3811         out_printf (out,
3812                     "GQuark\n%s_quark (void)\n"
3813                     "{\n"
3814                     "\tstatic GQuark q = 0;\n"
3815                     "\tif (q == 0)\n"
3816                     "\t\tq = g_quark_from_static_string (\"%s\");\n"
3817                     "\treturn q;\n"
3818                     "}\n\n",
3819                     funcprefix, str);
3820
3821         g_free (str);
3822
3823         g_free (funcprefix);
3824         g_free (type);
3825 }
3826
3827 static void
3828 generate_outfiles(void)
3829 {
3830         GList *li;
3831
3832         print_file_comments();
3833
3834         print_all_top();
3835
3836         print_header_top();
3837
3838         print_header_prefixes();
3839
3840         print_useful_macros();
3841
3842         print_includes();
3843
3844         print_more_useful_macros ();
3845
3846         for (li = nodes; li != NULL; li = li->next) {
3847                 Node *node = li->data;
3848                 if (node->type == CCODE_NODE) {
3849                         CCode *cc = (CCode *)node;
3850                         if (cc->cctype != HT_CCODE &&
3851                             cc->cctype != AT_CCODE)
3852                                 print_ccode_block ((CCode *)node);
3853                 } else if (node->type == CLASS_NODE) {
3854                         print_class_block ((Class *)node);
3855                 } else if (node->type == ENUMDEF_NODE) {
3856                         print_enum ((EnumDef *)node);
3857                 } else if (node->type == FLAGS_NODE) {
3858                         print_flags ((Flags *)node);
3859                 } else if (node->type == ERROR_NODE) {
3860                         print_error ((Error *)node);
3861                 } else {
3862                         g_assert_not_reached();
3863                 }
3864         }
3865
3866         print_header_postfixes();
3867 }
3868
3869 static void
3870 print_help(void)
3871 {
3872         fprintf(stderr, "Gob version %s\n\n", VERSION);
3873         fprintf(stderr, "gob [options] file.gob\n\n");
3874         fprintf(stderr, "Options:\n"
3875                 "\t--help,-h,-?            Display this help\n"
3876                 "\t--version               Display version\n"
3877                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
3878                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
3879                 "\t--for-cpp               Create C++ files\n"
3880                 "\t--no-extern-c           Never print extern \"C\" into the "
3881                                           "header\n"
3882                 "\t--no-gnu                Never use GNU extentions\n"
3883                 "\t--no-touch-headers      Don't touch headers unless they "
3884                                           "really changed\n"
3885                 "\t--always-private-header Always create a private header "
3886                                           "file,\n"
3887                 "\t                        even if it would be empty "
3888                                           "[default]\n"
3889                 "\t--ondemand-private-header Create private header only when "
3890                                           "needed\n"
3891                 "\t--no-private-header     Don't create a private header, "
3892                                           "put private\n"
3893                 "\t                        structure and protected "
3894                                           "prototypes inside c file\n"
3895                 "\t--always-private-struct Always create a private pointer "
3896                                           "in\n"
3897                 "\t                        the object structure\n"
3898                 "\t--m4                    Preprocess source with m4. "
3899                                           "Following args will\n"
3900                 "\t                        be passed to m4\n"
3901                 "\t--m4-dir                Print directory that will be "
3902                                           "searched for m4\n"
3903                 "\t                        files\n"
3904                 "\t--no-write,-n           Don't write output files, just "
3905                                           "check syntax\n"
3906                 "\t--no-lines              Don't print '#line' to output\n"
3907                 "\t--no-self-alias         Don't create self type and macro "
3908                                           "aliases\n"
3909                 "\t--no-kill-underscores   Ignored for compatibility\n");
3910 }
3911
3912 static void
3913 parse_options(int argc, char *argv[])
3914 {
3915         int i;
3916         int got_file = FALSE;
3917         int no_opts = FALSE;
3918         int m4_opts = FALSE; /* if we are just passing on args to m4 */
3919
3920         filename = NULL;
3921
3922         for(i = 1 ; i < argc; i++) {
3923                 if(m4_opts) {
3924                         char *new_commandline;
3925                         g_assert(m4_commandline!=NULL);
3926
3927                         /* check whether this one looks like the filename */
3928                         if((!strcmp(argv[i],"-") || argv[i][0] != '-') 
3929                            && !got_file) {
3930                                 const gchar *m4_flags=use_m4_clean?"":M4_FLAGS;
3931                                 filename = argv[i];
3932                                 got_file = TRUE;
3933                                 
3934                                 /* insert flags before the filename */
3935                                 new_commandline=g_strconcat(m4_commandline,
3936                                                             " ",
3937                                                             m4_flags, 
3938                                                             " ",
3939                                                             argv[i],
3940                                                             NULL);
3941                         }
3942
3943                         /* just an ordinary option */
3944                         else                      
3945                           new_commandline=g_strconcat(m4_commandline,
3946                                                       " ",
3947                                                       argv[i],
3948                                                       NULL);
3949
3950                         /* free old commandline */
3951                         g_free(m4_commandline);
3952                         m4_commandline=new_commandline;
3953
3954                 } else if(no_opts ||
3955                    argv[i][0] != '-') {
3956                         /*must be a file*/
3957                         if(got_file) {
3958                                 fprintf(stderr, "Specify only one file!\n");
3959                                 print_help();
3960                                 exit(1);
3961                         }
3962                         filename = argv[i];
3963                         got_file = TRUE;
3964                 } else if(strcmp(argv[i], "--help")==0) {
3965                         print_help();
3966                         exit(0);
3967                 } else if(strcmp(argv[i], "--version")==0) {
3968                         fprintf(stderr, "Gob version %s\n", VERSION);
3969                         exit(0);
3970                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
3971                         exit_on_warn = TRUE;
3972                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
3973                         exit_on_warn = FALSE;
3974                 } else if(strcmp(argv[i], "--for-cpp")==0) {
3975                         for_cpp = TRUE;
3976                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
3977                         no_touch_headers = TRUE;
3978                 } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
3979                         private_header = PRIVATE_HEADER_ONDEMAND;
3980                 } else if(strcmp(argv[i], "--always-private-header")==0) {
3981                         private_header = PRIVATE_HEADER_ALWAYS;
3982                 } else if(strcmp(argv[i], "--no-private-header")==0) {
3983                         private_header = PRIVATE_HEADER_NEVER;
3984                 } else if(strcmp(argv[i], "--no-gnu")==0) {
3985                         no_gnu = TRUE;
3986                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
3987                         no_extern_c = TRUE;
3988                 } else if(strcmp(argv[i], "--no-write")==0) {
3989                         no_write = TRUE;
3990                 } else if(strcmp(argv[i], "--no-lines")==0) {
3991                         no_lines = TRUE;
3992                 } else if(strcmp(argv[i], "--no-self-alias")==0) {
3993                         no_self_alias = TRUE;
3994                 } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
3995                         /* no op */;
3996                 } else if(strcmp(argv[i], "--always-private-struct")==0) {
3997                         always_private_struct = TRUE;
3998                 } else if(strcmp(argv[i], "--m4-dir")==0) {
3999                         printf("%s\n",M4_INCLUDE_DIR);
4000                         exit(0);
4001                 } else if(strcmp(argv[i], "--m4")==0) {
4002                         use_m4 = TRUE;
4003                         use_m4_clean=FALSE;
4004                         m4_opts = TRUE;
4005                         m4_commandline=g_strdup(M4_COMMANDLINE);
4006                 } else if(strcmp(argv[i], "--m4-clean")==0) {
4007                         use_m4 = TRUE;
4008                         use_m4_clean=TRUE;
4009                         m4_opts = TRUE;
4010                         m4_commandline=g_strdup(M4_COMMANDLINE);
4011                 } else if(strcmp(argv[i], "--")==0) {
4012                         /*further arguments are files*/
4013                         no_opts = TRUE;
4014                 } else if(strncmp(argv[i], "--", 2)==0) {
4015                         /*unknown long option*/
4016                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
4017                         print_help();
4018                         exit(1);
4019                 } else {
4020                         /*by now we know we have a string starting with
4021                           - which is a short option string*/
4022                         char *p;
4023                         for(p = argv[i] + 1; *p; p++) {
4024                                 switch(*p) {
4025                                 case 'w':
4026                                         exit_on_warn=TRUE;
4027                                         break;
4028                                 case 'n':
4029                                         no_write = TRUE;
4030                                         break;
4031                                 case 'h':
4032                                 case '?':
4033                                         print_help();
4034                                         exit(0);
4035                                 default:
4036                                         fprintf(stderr,
4037                                                 "Unknown option '%c'!\n", *p);
4038                                         print_help();
4039                                         exit(1);
4040                                 }
4041                         }
4042                 }
4043         }
4044
4045 #if 0
4046         /* if we are using m4, and got no filename, append m4 flags now */
4047         if(!got_file && use_m4 && !use_m4_clean) {
4048                 char *new_commandline;
4049                 new_commandline=g_strconcat(m4_commandline,
4050                                             " ",
4051                                             M4_FLAGS,
4052                                             NULL);
4053                 g_free(m4_commandline);
4054                 m4_commandline=new_commandline;
4055         }
4056 #endif
4057 }
4058
4059 /* this is a somewhat ugly hack, but it appears to work */
4060 static void
4061 compare_and_move_header(void)
4062 {
4063         char *hfnew = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
4064         char *hf = g_strconcat(filebase, ".h", NULL);
4065         struct stat s;
4066         if(stat(hf, &s) == 0) {
4067                 char *s;
4068                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
4069                 if(system(s) == 0) {
4070                         if(unlink(hfnew) != 0)
4071                                 error_printf(GOB_ERROR, 0,
4072                                              "Can't remove new header file");
4073                         g_free(hfnew);
4074                         g_free(hf);
4075                         g_free(s);
4076                         return;
4077                 }
4078                 g_free(s);
4079                 if(unlink(hf) != 0)
4080                         error_printf(GOB_ERROR, 0,
4081                                      "Can't remove old header file");
4082         }
4083         if(rename(hfnew, hf) != 0)
4084                 error_printf(GOB_ERROR, 0,
4085                              "Can't rename new header file");
4086         g_free(hfnew);
4087         g_free(hf);
4088 }
4089
4090 int
4091 main(int argc, char *argv[])
4092 {
4093         parse_options(argc, argv);
4094         
4095         if(use_m4) {
4096                 yyin = popen(m4_commandline, "r");
4097                 if(!yyin) {
4098                         fprintf(stderr, "Error: can't open pipe from '%s'\n",
4099                                 m4_commandline);
4100                         exit(1);
4101                 }
4102         } else if(filename) {
4103                 yyin = fopen(filename, "r");
4104                 if(!yyin) {
4105                         fprintf(stderr, "Error: can't open file '%s'\n",
4106                                 filename);
4107                         exit(1);
4108                 }
4109         }
4110
4111         if(filename==NULL)
4112                 filename = "stdin";
4113
4114         /* This is where parsing is done */
4115         /*yydebug = 1;*/
4116         if(yyparse() != 0)
4117                 g_error("Parsing errors, quitting");
4118
4119         /* close input file */
4120         if(use_m4) pclose(yyin);
4121         else fclose(yyin);
4122         yyin=stdin;
4123
4124         if( ! class)
4125                 error_print(GOB_ERROR, 0, " no class defined");
4126         
4127
4128         exit_on_error = FALSE;
4129
4130         signals = count_signals ((Class *)class);
4131         set_properties = count_set_properties ((Class *)class) +
4132                 count_set_arguments ((Class *)class);
4133         get_properties = count_get_properties ((Class *)class) +
4134                 count_get_arguments ((Class *)class);
4135         overrides = count_overrides ((Class *)class);
4136         privates = count_privates ((Class *)class);
4137         protecteds = count_protecteds ((Class *)class);
4138         unreftors = count_unreftors ((Class *)class);
4139         destructors = count_destructors ((Class *)class);
4140         initializers = count_initializers ((Class *)class);
4141         overrode_get_type = find_get_type ((Class *)class);
4142
4143         make_bases ();
4144         make_inits ((Class *)class);
4145         if(unreftors > 0) {
4146                 need_dispose = TRUE;
4147                 find_dispose ((Class *)class);
4148         }
4149         if (destructors > 0 ||
4150             privates > 0) {
4151                 need_finalize = TRUE;
4152                 find_finalize ((Class *)class);
4153         }
4154         check_bad_symbols ((Class *)class);
4155         check_duplicate_symbols ((Class *)class);
4156         check_duplicate_overrides ((Class *)class);
4157         check_duplicate_signals_args ((Class *)class);
4158         check_public_new ((Class *)class);
4159         check_vararg ((Class *)class);
4160         check_firstarg ((Class *)class);
4161         check_nonvoidempty ((Class *)class);
4162         check_signal_args ((Class *)class);
4163         check_property_types ((Class *)class);
4164         check_argument_types ((Class *)class);
4165         check_func_arg_checks ((Class *)class);
4166
4167         exit_on_error = TRUE;
4168         
4169         if (got_error)
4170                 exit (1);
4171
4172         any_special = setup_special_array ((Class *)class, special_array);
4173
4174         open_files ();
4175         
4176         generate_outfiles ();
4177
4178         if (devnull) {
4179                 fclose (devnull);
4180         } else {
4181                 fclose (out);
4182                 fclose (outh);
4183                 if (outph)
4184                         fclose (outph);
4185         }
4186
4187         if (no_touch_headers &&
4188             ! no_write)
4189                 compare_and_move_header ();
4190         
4191         return 0;
4192 }