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