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