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