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