]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
Release 1.0.12
[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  *
5  * Author: George Lebl
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the  Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20  * USA.
21  */
22
23 #include "config.h"
24 #include <glib.h>
25 #include <time.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31
32 #include "treefuncs.h"
33 #include "parse.h"
34 #include "out.h"
35 #include "util.h"
36 #include "checks.h"
37
38 #include "main.h"
39
40 char *filename = NULL;
41
42 int yyparse(void);
43
44 extern int yydebug;
45 extern FILE * yyin;
46 extern Node *class;
47 extern GList *nodes;
48
49 extern GList *include_files;
50
51 extern GHashTable *gtk_doc_hash;
52
53 char *filebase;
54 static char *funcbase;
55 static char *pfuncbase;
56 static char *macrobase;
57 static char *macrois;
58 static char *macrotype;
59 static char *typebase;
60 static char *ptypebase;
61
62 static int signals = 0; /* number of signals */
63 static int set_arguments = 0; /* number of named (set) arguments */
64 static int get_arguments = 0; /* number of named (get) arguments */
65 static int overrides = 0; /* number of override methods */
66 static int privates = 0; /* number of private data members */
67 static int protecteds = 0; /* number of protected methods */
68 static int destructors = 0; /* number of variable destructors */
69 static int initializers = 0; /* number of variable initializers */
70 static gboolean overrode_get_type = FALSE; /* provided your won _get_type */
71
72 static gboolean made_aliases = FALSE;  /* if we made any shorthand aliases
73                                           and need the REALLY UGLY HACK to
74                                           avoid warnings */
75
76 /* the special variable types we need to define */
77 static gboolean special_array[SPECIAL_LAST] = {0};
78 static gboolean any_special = FALSE;
79
80 static gboolean need_destroy = FALSE;
81 static Method * destroy_handler = NULL;
82
83 static gboolean need_finalize = FALSE;
84 static Method * finalize_handler = NULL;
85
86 FILE *out = NULL;
87 FILE *outh = NULL;
88 FILE *outph = NULL;
89 FILE *devnull = NULL;
90
91 gboolean no_touch_headers = FALSE;
92 gboolean for_cpp = FALSE;
93 gboolean no_gnu = FALSE;
94 gboolean exit_on_warn = FALSE;
95 gboolean exit_on_error = TRUE;
96 gboolean got_error = FALSE;
97 gint private_header = PRIVATE_HEADER_ONDEMAND;
98 gboolean no_extern_c = FALSE;
99 gboolean no_write = FALSE;
100 gboolean no_lines = FALSE;
101 gboolean no_self_alias = FALSE;
102 gboolean no_kill_underscores = FALSE;
103 gboolean always_private_struct = FALSE;
104
105 gboolean use_m4 = FALSE; /* preprocess sources with m4 */
106 gboolean use_m4_clean = FALSE; /* preprocess sources with m4, no m4 flags */
107 char *m4_commandline = NULL;
108 #define M4_INCLUDE_DIR  PKGDATADIR "/m4"
109 #define M4_BASE_FILENAME "gobm4.m4"
110 #define M4_FLAGS "-P -s -I" M4_INCLUDE_DIR  " -DGOBM4_GOB_VERSION=" VERSION " " M4_BASE_FILENAME
111 #define M4_COMMANDLINE "m4"
112
113 int method_unique_id = 1;
114
115 static void
116 make_bases(void)
117 {
118         filebase = replace_sep(((Class *)class)->otype, '-');
119         g_strdown(filebase);
120
121         funcbase = replace_sep(((Class *)class)->otype, '_');
122         g_strdown(funcbase);
123
124         pfuncbase = replace_sep(((Class *)class)->ptype, '_');
125         g_strdown(pfuncbase);
126
127         macrobase = replace_sep(((Class *)class)->otype, '_');
128         g_strup(macrobase);
129         
130         macrois = make_pre_macro(((Class *)class)->otype, "IS");
131         macrotype = make_pre_macro(((Class *)class)->otype, "TYPE");
132
133         typebase = remove_sep(((Class *)class)->otype);
134
135         ptypebase = remove_sep(((Class *)class)->ptype);
136 }
137
138 static char *
139 get_type(const Type *t, gboolean postfix_to_stars)
140 {
141         char *s;
142         int i;
143         int extra;
144         GString *gs;
145
146         s = remove_sep(t->name);
147         gs = g_string_new(s);
148         g_free(s);
149
150         extra = 0;
151         if(postfix_to_stars) {
152                 const char *p;
153                 /*XXX: this is ugly perhaps we can do this whole postfix thing
154                   in a nicer way, we just count the number of '[' s and from
155                   that we deduce the number of dimensions, so that we can print
156                   that many stars */
157                 for(p=t->postfix; p && *p; p++)
158                         if(*p == '[') extra++;
159         }
160         g_string_append_c(gs, ' ');
161
162         if(t->pointer) {
163                 g_string_append(gs, t->pointer);
164                 for(i=0; i < extra; i++)
165                         g_string_append_c(gs, '*');
166                 g_string_append_c(gs, ' ');
167         }
168         
169         s = gs->str;
170         g_string_free(gs, FALSE);
171         return s;
172 }
173
174 static char *
175 get_gtk_doc(const char *id)
176 {
177         char *val;
178
179         if(!gtk_doc_hash)
180                 return NULL;
181
182         val = g_hash_table_lookup(gtk_doc_hash, id);
183         if(val)
184                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
185                                        funcbase, get_real_id(id), val);
186         val = g_hash_table_lookup(gtk_doc_hash, get_real_id(id));
187         if(val)
188                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
189                                        funcbase, get_real_id(id), val);
190         return NULL;
191 }
192
193 static void
194 print_type(FILE *fp, const Type *t, gboolean postfix_to_stars)
195 {
196         char *s;
197
198         s = get_type(t, postfix_to_stars);
199         out_printf(fp, "%s", s); 
200         g_free(s);
201 }
202
203
204 static void
205 print_method (FILE *fp,
206               const char *typeprefix,
207               const char *nameprefix,
208               const char *subnameprefix,
209               const char *namepostfix,
210               const char *afterargs,
211               const char *postfix,
212               const Method *m,
213               gboolean one_arg_per_line,
214               gboolean no_funcbase,
215               gboolean kill_underscore)
216 {
217         GList *li;
218         const char *id;
219
220         out_printf(fp, "%s", typeprefix); 
221         print_type(fp, m->mtype, TRUE);
222
223         if(kill_underscore)
224                 id = get_real_id(m->id);
225         else
226                 id = m->id;
227
228         if(no_funcbase)
229                 out_printf(fp, "%s%s%s%s(",
230                            nameprefix, subnameprefix, id, namepostfix); 
231         else
232                 out_printf(fp, "%s%s_%s%s%s(",
233                            nameprefix, funcbase, subnameprefix, id,
234                            namepostfix); 
235         
236         if(m->args) {
237                 for(li=m->args; li; li=g_list_next(li)) {
238                         FuncArg *arg = li->data;
239                         print_type(fp, arg->atype, FALSE);
240                         if(li->next)
241                                 out_printf(fp, "%s%s,%s", arg->name,
242                                            arg->atype->postfix ?
243                                            arg->atype->postfix : "",
244                                            one_arg_per_line ? "\n\t\t\t\t\t" : " ");
245                         else
246                                 out_printf(fp, "%s%s", arg->name,
247                                            arg->atype->postfix ?
248                                            arg->atype->postfix : ""); 
249                 }
250                 if(m->vararg)
251                         out_printf(fp, ",%s...",
252                                    one_arg_per_line ? "\n\t\t\t\t\t" : " "); 
253         } else {
254                 out_printf(fp, "void"); 
255         }
256         out_printf(fp, "%s)%s", afterargs, postfix); 
257 }
258
259 static gboolean
260 any_method_to_alias(Class *c)
261 {
262         GList *li;
263         
264         for(li=c->nodes;li;li=g_list_next(li)) {
265                 Node *node = li->data;
266                 if(node->type == METHOD_NODE) {
267                         Method *m = (Method *)node;
268                         
269                         if(m->method == INIT_METHOD ||
270                            m->method == CLASS_INIT_METHOD ||
271                            m->method == OVERRIDE_METHOD)
272                                 continue;
273
274                         return TRUE;
275                 }
276         }
277         return FALSE;
278 }
279
280
281 /* just the vararg macros, we use the same func pointers for these as in non-gnu */
282 static void
283 make_method_gnu_aliases(Class *c)
284 {
285         GList *li;
286         
287         for(li = c->nodes; li != NULL; li = li->next) {
288                 Node *node = li->data;
289                 if(node->type == METHOD_NODE) {
290                         Method *m = (Method *)node;
291                         
292                         if(m->method == INIT_METHOD ||
293                            m->method == CLASS_INIT_METHOD ||
294                            m->method == OVERRIDE_METHOD)
295                                 continue;
296
297                         /* in C++ mode don't alias new */
298                         if(for_cpp && strcmp(m->id, "new")==0)
299                                 continue;
300
301                         if(m->args != NULL)
302                                 out_printf(out, "#define %s(args...) "
303                                            "%s_%s(args)\n", m->id,
304                                            funcbase, get_real_id(m->id));
305                         else
306                                 out_printf(out, "#define %s() "
307                                            "%s_%s()\n", m->id,
308                                            funcbase, get_real_id(m->id));
309
310                         /* for compatibility with gob2 */
311                         if(m->args != NULL)
312                                 out_printf(out, "#define self_%s(args...) "
313                                            "%s_%s(args)\n", m->id,
314                                            funcbase, get_real_id(m->id));
315                         else
316                                 out_printf(out, "#define self_%s() "
317                                            "%s_%s()\n", m->id,
318                                            funcbase, get_real_id(m->id));
319                 }
320         }
321 }
322
323 static void
324 make_method_nongnu_aliases(Class *c)
325 {
326         GList *li;
327
328         gboolean local_made_aliases = FALSE;
329         
330         for(li=c->nodes; li; li=g_list_next(li)) {
331                 Node *node = li->data;
332                 if(node->type == METHOD_NODE) {
333                         Method *m = (Method *)node;
334                         
335                         if(m->method == INIT_METHOD ||
336                            m->method == CLASS_INIT_METHOD ||
337                            m->method == OVERRIDE_METHOD)
338                                 continue;
339
340                         /* in C++ mode don't alias new */
341                         if(for_cpp && strcmp(m->id, "new")==0)
342                                 continue;
343
344                         if( ! local_made_aliases)
345                                 out_printf(out, "\n/* Short form pointers */\n");
346
347                         print_method(out, "static ", "(* const ", "", ") ",
348                                      "", "",
349                                      m, FALSE, TRUE, FALSE);
350                         out_printf(out, " = %s_%s;\n", funcbase,
351                                    get_real_id(m->id));
352
353                         /* for compatibility with gob2 */
354                         print_method(out, "static ", "(* const self_", "", ") ",
355                                      "", "",
356                                      m, FALSE, TRUE, FALSE);
357                         out_printf(out, " = %s_%s;\n", funcbase,
358                                    get_real_id(m->id));
359
360                         local_made_aliases = TRUE;
361                 }
362         }
363         if(local_made_aliases) {
364                 out_printf(out, "\n");
365                 made_aliases = TRUE;
366         }
367 }
368
369 static void
370 add_bad_hack_to_avoid_unused_warnings(Class *c)
371 {
372         GList *li;
373
374         /* if we haven't had any methods, just return */
375         if( ! made_aliases)
376                 return;
377         
378         if( ! no_gnu)
379                 out_printf(out, "\n\n#if (!defined __GNUC__) || (defined __GNUC__ && defined __STRICT_ANSI__)\n");
380         out_printf(out,
381                    "/*REALLY BAD HACK\n"
382                    "  This is to avoid unused warnings if you don't call\n"
383                    "  some method.  I need to find a better way to do\n"
384                    "  this, not needed in GCC since we use some gcc\n"
385                    "  extentions to make saner, faster code */\n"
386                    "static void\n"
387                    "___%s_really_bad_hack_to_avoid_warnings(void)\n"
388                    "{\n", funcbase);
389         for(li=c->nodes;li;li=g_list_next(li)) {
390                 Node *node = li->data;
391                 if(node->type == METHOD_NODE) {
392                         Method *m = (Method *)node;
393                         
394                         if(m->method == INIT_METHOD ||
395                            m->method == CLASS_INIT_METHOD ||
396                            m->method == OVERRIDE_METHOD)
397                                 continue;
398
399                         /* in C++ mode we don't alias new */
400                         if(for_cpp && strcmp(m->id, "new")==0)
401                                 continue;
402
403                         out_printf(out, "\t((void (*)(void))%s)();\n", m->id);
404                 }
405         }
406         out_printf(out, "\t___%s_really_bad_hack_to_avoid_warnings();\n",
407                    funcbase);
408         if(!no_gnu)
409                 out_printf(out, "}\n#endif /* !__GNUC__ || (__GNUC__ && __STRICT_ANSI__) */\n\n");
410         else
411                 out_printf(out, "}\n\n");
412 }
413
414 static void
415 put_variable(Variable *v, FILE *fp)
416 {
417         out_printf(fp, "\t");
418         print_type(fp, v->vtype, FALSE);
419         out_printf(fp, "%s%s;", v->id,
420                    v->vtype->postfix?
421                    v->vtype->postfix:""); 
422         if(v->scope == PROTECTED_SCOPE)
423                 out_printf(fp, " /* protected */");
424         out_printf(fp, "\n");
425 }
426
427 static void
428 put_vs_method(const Method *m)
429 {
430         if(m->method != SIGNAL_LAST_METHOD &&
431            m->method != SIGNAL_FIRST_METHOD &&
432            m->method != VIRTUAL_METHOD)
433                 return;
434
435         /* if a signal mark it as such */
436         if(m->method != VIRTUAL_METHOD)
437                 print_method(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
438                              m, FALSE, TRUE, TRUE);
439         else
440                 print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
441                              m, FALSE, TRUE, TRUE);
442 }
443
444 static void
445 put_pub_method(const Method *m)
446 {
447         if(m->scope != PUBLIC_SCOPE)
448                 return;
449
450         print_method(outh, "", "\t", "", "\t", "", ";\n", m, TRUE, FALSE, TRUE);
451 }
452
453 static void
454 put_signal_macro (const Method *m, gboolean gnu)
455 {
456         char *id;
457
458         if(m->method != SIGNAL_LAST_METHOD &&
459            m->method != SIGNAL_FIRST_METHOD)
460                 return;
461
462         id = g_strdup (m->id);
463         g_strup (id);
464
465         if ( ! gnu) {
466                 out_printf (outh, "#define %s_SIGNAL_%s(func)\t"
467                             "\"%s\",GTK_SIGNAL_FUNC(func)\n",
468                             macrobase, id, get_real_id (m->id));
469         } else {
470                 out_printf (outh, "#define %s_SIGNAL_%s(func)\t"
471                             "\"%s\",GTK_SIGNAL_FUNC(({",
472                             macrobase, id, get_real_id (m->id));
473                 print_method (outh, "", "(* ___", "", ") ", ", gpointer data ",
474                               " = func; ", m, FALSE, TRUE, TRUE);
475                 out_printf (outh, "___%s; }))\n", get_real_id (m->id));
476
477         }
478         g_free (id);
479 }
480
481 static void
482 put_signal_macros (const Class *c, gboolean gnu)
483 {
484         const GList *li;
485
486         if (signals < 0)
487                 return;
488
489         for (li = c->nodes; li != NULL; li = li->next) {
490                 const Node *n = li->data;
491                 if (n->type == METHOD_NODE)
492                         put_signal_macro ((Method *)n, gnu);
493         }
494 }
495
496
497 static void
498 put_prot_method(const Method *m)
499 {
500         if(m->scope != PROTECTED_SCOPE)
501                 return;
502
503         if(outph)
504                 print_method(outph, "", "\t", "", "\t", "", ";\n",
505                              m, FALSE, FALSE, TRUE);
506         else
507                 print_method(out, "", "\t", "", "\t", "", ";\n",
508                              m, FALSE, FALSE, TRUE);
509 }
510
511 static void
512 put_priv_method_prot(Method *m)
513 {
514         if(m->method == SIGNAL_LAST_METHOD ||
515            m->method == SIGNAL_FIRST_METHOD ||
516            m->method == VIRTUAL_METHOD) {
517                 if(m->cbuf)
518                         print_method(out,
519                                      "static ", "___real_", "", " ", "", ";\n",
520                                      m, FALSE, FALSE, TRUE);
521         }
522         /* no else, here, it might still have a private prototype, it's not
523          * exclusive */
524
525         if((m->method == OVERRIDE_METHOD &&
526             m->cbuf)) {
527                 /* add unique ID */
528                 char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
529                 print_method(out, "static ", s, "", " ", "",
530                              no_gnu?";\n":" G_GNUC_UNUSED;\n",
531                              m, FALSE, FALSE, FALSE);
532                 g_free(s);
533         } else if(m->scope == PRIVATE_SCOPE ||
534                   m->method == INIT_METHOD ||
535                   m->method == CLASS_INIT_METHOD)
536                 print_method(out, "static ", "", "", " ", "",
537                              no_gnu?";\n":" G_GNUC_UNUSED;\n",
538                              m, FALSE, FALSE, TRUE);
539 }
540
541 static GList *
542 make_func_arg(char *typename, int is_class, char *name)
543 {
544         Node *node;
545         Node *type;
546         char *tn;
547         
548         if(is_class)
549                 tn = g_strconcat(typename, ":Class", NULL);
550         else
551                 tn = g_strdup(typename);
552
553         type = new_type(tn, g_strdup("*"), NULL);
554         node = new_funcarg((Type *)type, name, NULL);
555         return g_list_prepend(NULL, node);
556 }
557
558 static void
559 make_inits(Class *cl)
560 {
561         int got_class_init = FALSE;
562         int got_init = FALSE;
563         GList *li;
564         Node *node;
565         for(li=cl->nodes;li;li=g_list_next(li)) {
566                 Node *n = li->data;
567                 if(n->type == METHOD_NODE) {
568                         Method *m = (Method *)n;
569                         if(m->method == INIT_METHOD) {
570                                 if(got_init)
571                                         error_print(GOB_ERROR, m->line_no, "init defined more then once");
572                                 got_init = TRUE;
573                         } else if(m->method == CLASS_INIT_METHOD) {
574                                 if(got_class_init)
575                                         error_print(GOB_ERROR, m->line_no, "class_init defined more then once");
576                                 got_class_init = TRUE;
577                         }
578                 }
579         }
580         if(!got_class_init) {
581                 node = new_method(NO_SCOPE, CLASS_INIT_METHOD,
582                                   (Type *)new_type(g_strdup("void"),
583                                                    NULL, NULL),
584                                   NULL, NULL, NULL, g_strdup("class_init"),
585                                   make_func_arg(cl->otype, TRUE, g_strdup("c")),
586                                   NULL, NULL, NULL, 0, 0, FALSE,
587                                   method_unique_id++,
588                                   FALSE /*bonobo_x_func*/);
589                 cl->nodes = g_list_prepend(cl->nodes, node);
590         }
591         if(!got_init) {
592                 node = new_method(NO_SCOPE, INIT_METHOD,
593                                   (Type *)new_type(g_strdup("void"),
594                                                    NULL, NULL),
595                                   NULL, NULL, NULL, g_strdup("init"),
596                                   make_func_arg(cl->otype, FALSE, g_strdup("o")),
597                                   NULL, NULL, NULL, 0, 0, FALSE,
598                                   method_unique_id++,
599                                   FALSE /*bonobo_x_func*/);
600                 cl->nodes = g_list_prepend(cl->nodes, node);
601         }
602 }
603
604 static void
605 find_destroy(Class *cl)
606 {
607         GList *li;
608
609         destroy_handler = NULL;
610         for(li=cl->nodes;li;li=g_list_next(li)) {
611                 Node *n = li->data;
612                 if(n->type == METHOD_NODE) {
613                         Method *m = (Method *)n;
614                         if(m->method == OVERRIDE_METHOD &&
615                            strcmp(m->id, "destroy")==0) {
616                                 if(strcmp(m->otype, "Gtk:Object") != 0) {
617                                         error_print(GOB_ERROR, m->line_no,
618                                                     "destroy method override "
619                                                     "of class other then "
620                                                     "Gtk:Object");
621                                 }
622                                 if(g_list_length(m->args) != 1) {
623                                         error_print(GOB_ERROR, m->line_no,
624                                                     "destroy method override "
625                                                     "with more then one "
626                                                     "parameter");
627                                 }
628                                 destroy_handler = m;
629                                 break;
630                         }
631                 }
632         }
633 }
634
635 static void
636 find_finalize(Class *cl)
637 {
638         GList *li;
639
640         finalize_handler = NULL;
641         for(li=cl->nodes;li;li=g_list_next(li)) {
642                 Node *n = li->data;
643                 if(n->type == METHOD_NODE) {
644                         Method *m = (Method *)n;
645                         if(m->method == OVERRIDE_METHOD &&
646                            strcmp(m->id, "finalize")==0) {
647                                 if(strcmp(m->otype, "Gtk:Object") != 0 &&
648                                    strcmp(m->otype, "G:Object") != 0) {
649                                         error_print(GOB_ERROR, m->line_no,
650                                                     "finalize method override "
651                                                     "of class other then "
652                                                     "Gtk:Object (or G:Object"
653                                                     "for GTK+ 2.0)");
654                                 }
655                                 if(g_list_length(m->args) != 1) {
656                                         error_print(GOB_ERROR, m->line_no,
657                                                     "finalize method override "
658                                                     "with more then one "
659                                                     "parameter");
660                                 }
661                                 finalize_handler = m;
662                                 break;
663                         }
664                 }
665         }
666 }
667
668
669 /* hash of method -> name of signal prototype */
670 static GHashTable *marsh = NULL;
671
672 /* list of methods with different signal prototypes,
673    we check this list if we can use a signal prototype of a
674    previous signal method, there are only uniques here */
675 static GList *eq_signal_methods = NULL;
676
677 /* compare a list of strings */
678 static gboolean
679 is_list_equal(GList *a, GList *b)
680 {
681         for(;a && b; a=a->next, b=b->next) {
682                 if(strcmp(a->data, b->data)!=0) {
683                         return FALSE;
684                 }
685         }
686         /* the the lists were different length */
687         if(a || b)
688                 return FALSE;
689         return TRUE;
690 }
691
692 static Method *
693 find_same_type_signal(Method *m)
694 {
695         GList *li;
696         for(li=eq_signal_methods;li;li=li->next) {
697                 Method *mm = li->data;
698                 if(is_list_equal(mm->gtktypes, m->gtktypes))
699                         return mm;
700         }
701         return NULL;
702 }
703
704 static void
705 print_signal_marsal_args_gtk1 (Method *m)
706 {
707         if(strcmp(m->gtktypes->next->data, "NONE")!=0) {
708                 GList *li;
709                 int i;
710                 for(i=0, li=m->gtktypes->next;li;
711                     i++, li=g_list_next(li)) {
712                         if(!for_cpp)
713                                 out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
714                                            (char *)li->data, i);
715                         else {
716                                 out_printf(out, ",\n\t\t(%s)"
717                                            "GTK_VALUE_%s(args[%d])",
718                                            get_cast(li->data, FALSE),
719                                            (char *)li->data, i);
720                         }
721                 }
722         }
723         out_printf(out, ",\n\t\tfunc_data);\n}\n\n");
724 }
725
726 static void
727 add_marshal_gtk1 (Method *m, const char *mname)
728 {
729         out_printf(out, "\nstatic void\n"
730                 "___marshal_%s (GtkObject * object,\n"
731                 "\tGtkSignalFunc func,\n"
732                 "\tgpointer func_data,\n"
733                 "\tGtkArg * args)\n"
734                 "{\n", mname);
735         
736         if(strcmp(m->gtktypes->data, "NONE")==0) {
737                 out_printf(out, "\t___%s rfunc;\n\n"
738                         "\trfunc = (___%s)func;\n\n"
739                         "\t(*rfunc)((%s *)object", mname, mname, typebase);
740         } else {
741                 const char *retcast = get_cast(m->gtktypes->data, FALSE);
742                 gboolean is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
743                 out_printf(out,
744                            "\t___%s rfunc;\n\t"
745                            "%s *retval;\n\n"
746                            "\trfunc = (___%s)func;\n\n"
747                            "\tretval = GTK_RETLOC_%s(args[%d]);\n\n"
748                            "\t*retval = (*rfunc)((%s *)object",
749                            mname, retcast, mname,
750                            (char *)m->gtktypes->data,
751                            g_list_length(m->gtktypes) - (is_none ? 2 : 1),
752                            typebase);
753         }
754         print_signal_marsal_args_gtk1 (m);
755 }
756
757 static const char *
758 gtk2_debool (const char *s)
759 {
760         if (strcmp (s, "BOOL") == 0)
761                 return "BOOLEAN";
762         else
763                 return s;
764 }
765
766 static void
767 print_signal_marsal_args_gtk2 (Method *m)
768 {
769         if (strcmp (m->gtktypes->next->data, "NONE") != 0) {
770                 GList *li;
771                 int i;
772                 for (i = 0, li = m->gtktypes->next;
773                      li != NULL;
774                      i++, li = li->next) {
775                         char *get_func = g_strdup_printf
776                                 ("g_value_get_%s",
777                                  (char *)gtk2_debool (li->data));
778                         g_strdown (get_func);
779                         out_printf (out, ",\n\t\t(%s) "
780                                     "%s (param_values + %d)",
781                                     get_cast (li->data, FALSE),
782                                     get_func, i + 1);
783                         g_free (get_func);
784                 }
785         }
786         out_printf (out, ",\n\t\tdata2);\n");
787 }
788
789 static void
790 add_marshal_gtk2 (Method *m, const char *mname)
791 {
792         gboolean ret_none;
793         gboolean arglist_none;
794         const char *retcast;
795
796         ret_none = strcmp (m->gtktypes->data, "NONE") == 0;
797         arglist_none = strcmp (m->gtktypes->next->data, "NONE") == 0;
798
799         if (ret_none)
800                 retcast = NULL;
801         else
802                 retcast = get_cast (m->gtktypes->data, FALSE);
803
804         out_printf (out, "\nstatic void\n"
805                     "___marshal_%s (GClosure *closure,\n"
806                     "\tGValue *return_value,\n"
807                     "\tguint n_param_values,\n"
808                     "\tconst GValue *param_values,\n"
809                     "\tgpointer invocation_hint,\n"
810                     "\tgpointer marshal_data)\n"
811                     "{\n", mname);
812
813         if ( ! ret_none)
814                 out_printf (out, "\t%s v_return;\n", retcast);
815
816         out_printf (out, "\tregister ___%s callback;\n"
817                     "\tregister GCClosure *cc = (GCClosure*) closure;\n"
818                     "\tregister gpointer data1, data2;\n\n",
819                     mname);
820
821         out_printf (out, "\tg_return_if_fail (n_param_values == %d);\n\n",
822                     arglist_none ? 1 : g_list_length (m->gtktypes));
823
824         out_printf (out,
825                     "\tif (G_CCLOSURE_SWAP_DATA (closure)) {\n"
826                     "\t\tdata1 = closure->data;\n"
827                     "\t\tdata2 = g_value_peek_pointer (param_values + 0);\n"
828                     "\t} else {\n"
829                     "\t\tdata1 = g_value_peek_pointer (param_values + 0);\n"
830                     "\t\tdata2 = closure->data;\n"
831                     "\t}\n\n");
832
833         out_printf (out, "\tcallback = (___%s) "
834                     "(marshal_data != NULL ? marshal_data : cc->callback);"
835                     "\n\n", mname);
836         
837         if (ret_none) {
838                 out_printf (out, "\tcallback ((%s *)data1", typebase);
839         } else {
840                 out_printf (out, "\tv_return = callback ((%s *)data1",
841                             typebase);
842         }
843
844         print_signal_marsal_args_gtk2 (m);
845
846         if ( ! ret_none) {
847                 /* FIXME: This code is so fucking ugly it hurts */
848                 gboolean take_ownership = 
849                         (strcmp ((char *)m->gtktypes->data, "STRING") == 0 ||
850                          strcmp ((char *)m->gtktypes->data, "BOXED") == 0);
851                 char *set_func = g_strdup_printf ("g_value_set_%s%s",
852                                                   (char *)gtk2_debool (m->gtktypes->data),
853                                                   take_ownership ?
854                                                     "_take_ownership" : ""); 
855                 g_strdown (set_func);
856
857                 out_printf (out, "\n\t%s (return_value, v_return);\n",
858                             set_func);
859
860                 g_free (set_func);
861         }
862         out_printf (out, "}\n\n");
863 }
864
865
866
867 static void
868 add_signal_prots(Method *m)
869 {
870         GList *li;
871         static int sig = 1;
872         char *s;
873         Method *mm;
874         
875         if(m->method != SIGNAL_LAST_METHOD &&
876            m->method != SIGNAL_FIRST_METHOD)
877                 return;
878
879         if(!marsh)
880                 marsh = g_hash_table_new(NULL, NULL);
881         
882         if(strcmp(m->gtktypes->data, "NONE")==0 &&
883            strcmp(m->gtktypes->next->data, "NONE")==0)
884                 return;
885
886         /* if we already did a signal prototype just use that */
887         mm = find_same_type_signal(m);
888         if(mm) {
889                 s = g_hash_table_lookup(marsh, mm);
890                 g_hash_table_insert(marsh, m, s);
891                 return;
892         }
893         
894         s = g_strdup_printf("Sig%d", sig++);
895         
896         g_hash_table_insert(marsh, m, s);
897         eq_signal_methods = g_list_prepend(eq_signal_methods, m);
898
899         /* we know that we'll know all the gtktypes (so get_cast can't fail) */
900         out_printf(out, "\ntypedef %s (*___%s) (%s *, ",
901                    get_cast(m->gtktypes->data, FALSE), s, typebase);
902         
903         if (strcmp (m->gtktypes->next->data, "NONE") != 0) {
904                 for (li = m->gtktypes->next; li != NULL; li = li->next)
905                         out_printf(out, "%s, ", get_cast(li->data, FALSE));
906         }
907         out_printf (out, "gpointer);\n"); 
908         
909
910         out_printf (out, "\n#ifdef G_OBJECT_CLASS\n");
911         add_marshal_gtk2 (m, s);
912         out_printf (out, "#else /* ! G_OBJECT_CLASS */\n");
913         add_marshal_gtk1 (m, s);
914         out_printf (out, "#endif /* G_OBJECT_CLASS */\n\n");
915 }
916
917 static void
918 add_enums(Class *c)
919 {
920         GList *li;
921         out_printf(out, "\n");
922         if(signals>0) {
923                 out_printf(out, "enum {\n");
924                 for(li=c->nodes;li;li=g_list_next(li)) {
925                         Node *n = li->data;
926                         if(n->type == METHOD_NODE) {
927                                 Method *m = (Method *)n;
928                                 if(m->method == SIGNAL_LAST_METHOD ||
929                                    m->method == SIGNAL_FIRST_METHOD) {
930                                         char *s = g_strdup(get_real_id(m->id));
931                                         g_strup(s);
932                                         out_printf(out, "\t%s_SIGNAL,\n", s);
933                                         g_free(s);
934                                 }
935                         }
936                 }
937                 out_printf(out, "\tLAST_SIGNAL\n};\n\n");
938         }
939         if(set_arguments > 0 || get_arguments > 0) {
940                 out_printf(out, "enum {\n\tARG_0");
941                 for(li=c->nodes;li;li=g_list_next(li)) {
942                         Node *n = li->data;
943                         if(n->type == ARGUMENT_NODE) {
944                                 Argument *a = (Argument *)n;
945                                 char *s = g_strdup(a->name);
946                                 g_strup(s);
947                                 out_printf(out, ",\n\tARG_%s", s);
948                                 g_free(s);
949                         }
950                 }
951                 out_printf(out, "\n};\n\n");
952         }
953
954         if(signals>0)
955                 out_printf(out,
956                            "static guint object_signals[LAST_SIGNAL] = {0};\n\n");
957
958         out_printf(out, "/* pointer to the class of our parent */\n");
959         out_printf(out, "static %sClass *parent_class = NULL;\n\n", ptypebase);
960 }
961
962 static void
963 add_get_type(void)
964 {
965         char *chunk_size = ((Class*)class)->chunk_size;
966         
967         out_printf(out,
968                    "GtkType\n"
969                    "%s_get_type (void)\n"
970                    "{\n"
971                    "\tstatic GtkType type = 0;\n\n"
972                    "\tif (type == 0) {\n"
973                    "\t\tstatic const GtkTypeInfo info = {\n"
974                    "\t\t\t\"%s\",\n"
975                    "\t\t\tsizeof (%s),\n"
976                    "\t\t\tsizeof (%sClass),\n"
977                    "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
978                    "\t\t\t(GtkObjectInitFunc) %s_init,\n"
979                    "\t\t\t/* reserved_1 */ NULL,\n"
980                    "\t\t\t/* reserved_2 */ NULL,\n"
981                    "\t\t\t(GtkClassInitFunc) NULL\n"
982                    "\t\t};\n\n"
983                    "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n",
984                    funcbase, typebase, typebase, typebase,
985                    funcbase, funcbase, pfuncbase);
986         if(chunk_size)  {
987                 out_printf(out,
988                            "#if %s > 0\n"
989                            "\t\tgtk_type_set_chunk_alloc(type, %s);\n"
990                            "#endif\n", 
991                            chunk_size, chunk_size);
992         }
993         out_printf(out,
994                    "\t}\n\n"
995                    "\treturn type;\n"
996                    "}\n\n");
997 }
998
999 static void
1000 add_bonobo_x_get_type (void)
1001 {
1002         char *chunk_size = ((Class*)class)->chunk_size;
1003         
1004         out_printf(out,
1005                    "GtkType\n"
1006                    "%s_get_type (void)\n"
1007                    "{\n"
1008                    "\tstatic GtkType type = 0;\n\n"
1009                    "\tif (type == 0) {\n"
1010                    "\t\tstatic const GtkTypeInfo info = {\n"
1011                    "\t\t\t\"%s\",\n"
1012                    "\t\t\tsizeof (%s),\n"
1013                    "\t\t\tsizeof (%sClass),\n"
1014                    "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
1015                    "\t\t\t(GtkObjectInitFunc) %s_init,\n"
1016                    "\t\t\t/* reserved_1 */ NULL,\n"
1017                    "\t\t\t/* reserved_2 */ NULL,\n"
1018                    "\t\t\t(GtkClassInitFunc) NULL\n"
1019                    "\t\t};\n\n"
1020                    "\t\ttype = bonobo_x_type_unique\n"
1021                    "\t\t\t(%s_get_type (),\n"
1022                    "\t\t\tPOA_%s__init, NULL,\n"
1023                    "\t\t\tGTK_STRUCT_OFFSET (%sClass, _epv),\n"
1024                    "\t\t\t&info);\n",
1025                    funcbase, typebase, typebase, typebase,
1026                    funcbase, funcbase, pfuncbase,
1027                    ((Class*)class)->bonobo_x_class,
1028                    typebase);
1029         if(chunk_size)  {
1030                 out_printf(out,
1031                            "#if %s > 0\n"
1032                            "\t\tgtk_type_set_chunk_alloc(type, %s);\n"
1033                            "#endif\n", 
1034                            chunk_size, chunk_size);
1035         }
1036         out_printf(out,
1037                    "\t}\n\n"
1038                    "\treturn type;\n"
1039                    "}\n\n");
1040 }
1041
1042 static void
1043 add_overrides(Class *c, const char *oname, gboolean did_base_obj)
1044 {
1045         GList *li;
1046         GHashTable *done;
1047         char *s;
1048         
1049         done = g_hash_table_new(g_str_hash, g_str_equal);
1050         if(did_base_obj) {
1051                 s = g_strdup("GtkObject"); /* This was already done */
1052                 g_hash_table_insert(done, s, s);
1053                 s = g_strdup("GObject"); /* This was probably already done as well (if using Gtk/Glib 1.3/2.0) */
1054                 g_hash_table_insert(done, s, s);
1055         }
1056         for(li=c->nodes; li; li=g_list_next(li)) {
1057                 Node *n = li->data;
1058                 char *f;
1059                 Method *m = (Method *)n;
1060                 if(n->type != METHOD_NODE ||
1061                    m->method != OVERRIDE_METHOD)
1062                         continue;
1063
1064                 s = remove_sep(m->otype);
1065                 
1066                 if(g_hash_table_lookup(done, s)) {
1067                         g_free(s);
1068                         continue;
1069                 }
1070                 g_hash_table_insert(done, s, s);
1071
1072                 f = replace_sep(m->otype, '_');
1073                 g_strdown(f);
1074
1075                 out_printf(out, "\t%sClass *%s_class = (%sClass *)%s;\n",
1076                            s, f, s, oname);
1077                 
1078                 g_free(f);
1079         }
1080         g_hash_table_foreach(done, (GHFunc)g_free, NULL);
1081         g_hash_table_destroy(done);
1082 }
1083
1084 static char *
1085 make_run_signal_flags(Method *m, gboolean last)
1086 {
1087         GList *li;
1088         GString *gs;
1089         char *flags[] = {
1090                 "FIRST",
1091                 "LAST",
1092                 "BOTH",
1093                 "NO_RECURSE",
1094                 "ACTION",
1095                 "NO_HOOKS",
1096                 NULL
1097         };
1098
1099         gs = g_string_new(NULL);
1100
1101         if(last)
1102                 g_string_assign(gs, "GTK_RUN_LAST");
1103         else
1104                 g_string_assign(gs, "GTK_RUN_FIRST");
1105
1106         if(m->scope == PUBLIC_SCOPE)
1107                 g_string_append(gs, " | GTK_RUN_ACTION");
1108
1109         for(li = m->flags; li; li = li->next) {
1110                 char *flag = li->data;
1111                 int i;
1112                 for(i=0;flags[i];i++) {
1113                         if(strcmp(flags[i], flag)==0)
1114                                 break;
1115                 }
1116                 /* if we haven't found it in our list */
1117                 if( ! flags[i]) {
1118                         error_printf(GOB_WARN, m->line_no,
1119                                      "Unknown flag '%s' used, "
1120                                      "perhaps it was misspelled",
1121                                      flag);
1122                 }
1123                 g_string_sprintfa(gs, " | GTK_RUN_%s", flag);
1124         }
1125
1126         {
1127                 char *ret = gs->str;
1128                 g_string_free(gs, FALSE);
1129                 return ret;
1130         }
1131 }
1132                 
1133
1134 static void
1135 add_signals(Class *c)
1136 {
1137         GList *li;
1138
1139         out_printf(out, "\n");
1140         for(li=c->nodes;li;li=g_list_next(li)) {
1141                 Node *n = li->data;
1142                 char *mar, *sig, *flags;
1143                 gboolean is_none, last = FALSE;
1144                 Method *m = (Method *)n;
1145
1146                 if(n->type != METHOD_NODE ||
1147                    (m->method != SIGNAL_FIRST_METHOD &&
1148                     m->method != SIGNAL_LAST_METHOD))
1149                         continue;
1150
1151                 if(m->method == SIGNAL_FIRST_METHOD)
1152                         last = FALSE;
1153                 else
1154                         last = TRUE;
1155
1156                 if(g_hash_table_lookup(marsh, m))
1157                         mar = g_strconcat("___marshal_",
1158                                           (char *)g_hash_table_lookup(marsh, m),
1159                                           NULL);
1160                 else
1161                         mar = g_strdup("gtk_signal_default_marshaller");
1162                 
1163                 is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
1164
1165                 sig = g_strdup(get_real_id(m->id));
1166                 g_strup(sig);
1167                 flags = make_run_signal_flags(m, last);
1168                 out_printf(out, "\tobject_signals[%s_SIGNAL] =\n"
1169                         "\t\tgtk_signal_new (\"%s\",\n"
1170                         "\t\t\t(GtkSignalRunType)(%s),\n"
1171                         "\t\t\tGTK_CLASS_TYPE(gtk_object_class),\n"
1172                         "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n"
1173                         "\t\t\t%s,\n"
1174                         "\t\t\tGTK_TYPE_%s, %d",
1175                         sig, get_real_id(m->id),
1176                         flags,
1177                         typebase, get_real_id(m->id), mar,
1178                         (char *)m->gtktypes->data,
1179                         is_none ? 0 : g_list_length(m->gtktypes->next));
1180                 g_free(mar);
1181                 g_free(sig);
1182                 g_free(flags);
1183                 
1184                 if( ! is_none) {
1185                         GList *l;
1186                         for(l = m->gtktypes->next; l != NULL; l = l->next)
1187                                 out_printf(out, ",\n\t\t\tGTK_TYPE_%s",
1188                                         (char *)l->data);
1189                 }
1190
1191                 out_printf(out, ");\n");
1192
1193                 if(strcmp(m->gtktypes->data, "NONE") != 0 ||
1194                    ! is_none) {
1195                         GList *gl, *al;
1196                         char *sep = "";
1197                         out_printf(out, "\tif(");
1198                         if(strcmp(m->gtktypes->data, "NONE") != 0) {
1199                                 out_printf(out, "%s sizeof(", sep);
1200                                 print_type(out, m->mtype, FALSE);
1201                                 out_printf(out, "%s",
1202                                            m->mtype->postfix ?
1203                                            m->mtype->postfix : ""); 
1204                                 out_printf(out, ") != sizeof(%s)",
1205                                            get_cast(m->gtktypes->data, FALSE));
1206
1207                                 sep = " || ";
1208                         }
1209
1210                         for(al = m->args->next, gl = m->gtktypes->next;
1211                             al != NULL && gl != NULL;
1212                             al = al->next, gl = gl->next) {
1213                                 FuncArg *arg = al->data;
1214                                 char *gtkarg = gl->data;
1215
1216                                 out_printf(out, "%ssizeof(", sep);
1217                                 print_type(out, arg->atype, FALSE);
1218                                 out_printf(out, "%s",
1219                                            arg->atype->postfix ?
1220                                            arg->atype->postfix : ""); 
1221                                 out_printf(out, ") != sizeof(%s)",
1222                                            get_cast(gtkarg, FALSE));
1223
1224                                 sep = " || ";
1225                         }
1226                         out_printf(out, ") {\n"
1227                                    "\t\tg_error(\"%s line %d: Type mismatch "
1228                                    "of \\\"%s\\\" signal signature\");\n"
1229                                    "\t}\n",
1230                                    filename, m->line_no, get_real_id(m->id));
1231
1232                 }
1233         }
1234         out_printf (out, "#ifndef G_OBJECT_CLASS\n");
1235         out_printf (out, "\tgtk_object_class_add_signals (gtk_object_class,\n"
1236                     "\t\tobject_signals, LAST_SIGNAL);\n");
1237         out_printf (out, "#endif /* ! G_OBJECT_CLASS */\n\n");
1238 }
1239
1240 static void
1241 set_def_handlers(Class *c, const char *oname)
1242 {
1243         GList *li;
1244         gboolean set_line = FALSE;
1245
1246         out_printf(out, "\n");
1247         for(li = c->nodes; li; li = g_list_next(li)) {
1248                 Node *n = li->data;
1249                 Method *m = (Method *)n;
1250
1251                 if(n->type != METHOD_NODE ||
1252                    (m->method != SIGNAL_FIRST_METHOD &&
1253                     m->method != SIGNAL_LAST_METHOD &&
1254                     m->method != VIRTUAL_METHOD &&
1255                     m->method != OVERRIDE_METHOD))
1256                         continue;
1257
1258                 if(m->line_no > 0 && m->cbuf) {
1259                         out_addline_infile(out, m->line_no);
1260                         set_line = TRUE;
1261                 } else if(set_line) {
1262                         out_addline_outfile(out);
1263                         set_line = FALSE;
1264                 }
1265
1266
1267                 if(m->method == OVERRIDE_METHOD) {
1268                         char *s;
1269                         s = replace_sep(m->otype, '_');
1270                         g_strdown(s);
1271
1272                         if(need_destroy &&
1273                            destroy_handler &&
1274                            strcmp(get_real_id(m->id), "destroy") == 0)
1275                                 out_printf(out, "\tgtk_object_class->destroy "
1276                                            "= ___destroy;\n");
1277                         else if(need_finalize &&
1278                                 finalize_handler &&
1279                                 strcmp(get_real_id(m->id), "finalize") == 0)
1280                                 out_printf(out,
1281                                            "#ifdef G_OBJECT_CLASS\n"
1282                                            "\tg_object_class->finalize = ___finalize;\n"
1283                                            "#else /* !G_OBJECT_CLASS */\n"
1284                                            "\tgtk_object_class->finalize = ___finalize;\n"
1285                                            "#endif /* G_OBJECT_CLASS */\n");
1286                         else if(m->cbuf)
1287                                 out_printf(out,
1288                                            "\t%s_class->%s = ___%x_%s_%s;\n",
1289                                            s, get_real_id(m->id), (guint)m->unique_id,
1290                                            funcbase, get_real_id(m->id));
1291                         else
1292                                 out_printf(out, "\t%s_class->%s = NULL;\n",
1293                                            s, get_real_id(m->id));
1294                 } else {
1295                         if(m->cbuf)
1296                                 out_printf(out, "\t%s->%s = ___real_%s_%s;\n",
1297                                            oname, get_real_id(m->id),
1298                                            funcbase, get_real_id(m->id));
1299                         else
1300                                 out_printf(out, "\t%s->%s = NULL;\n",
1301                                            oname, get_real_id(m->id));
1302                 }
1303         }
1304         if(set_line)
1305                 out_addline_outfile(out);
1306 }
1307
1308 static void
1309 make_arguments(Class *c)
1310 {
1311         GList *li;
1312         char *argflags[] = {
1313                 "CONSTRUCT",
1314                 "CONSTRUCT_ONLY",
1315                 "CHILD_ARG",
1316                 "MASK",
1317                 NULL
1318         };
1319
1320         out_printf(out, "\n");
1321         for(li=c->nodes;li;li=g_list_next(li)) {
1322                 Node *n = li->data;
1323                 Argument *a;
1324                 GString *flags;
1325                 GList *l;
1326                 char *s;
1327                 if(n->type != ARGUMENT_NODE)
1328                         continue;
1329
1330                 a = (Argument *)n;
1331                 
1332                 if(a->get && a->set)
1333                         flags = g_string_new("GTK_ARG_READWRITE");
1334                 else if(a->get)
1335                         flags = g_string_new("GTK_ARG_READABLE");
1336                 else
1337                         flags = g_string_new("GTK_ARG_WRITABLE");
1338
1339                 g_assert(a->get || a->set);
1340                 
1341                 for(l=a->flags;l;l=g_list_next(l)) {
1342                         char *flag = l->data;
1343                         int i;
1344                         if(strcmp(flag, "READWRITE")==0 ||
1345                            strcmp(flag, "READABLE")==0 ||
1346                            strcmp(flag, "WRITABLE")==0) {
1347                                 error_print(GOB_WARN, a->line_no,
1348                                             "READWRITE, READABLE and "
1349                                             "WRITABLE argument flags are "
1350                                             "set automatically");
1351                                 continue;
1352                         }
1353                         for(i = 0; argflags[i]; i++) {
1354                                 if(strcmp(argflags[i], flag)==0)
1355                                         break;
1356                         }
1357                         /* if we haven't found it in our list */
1358                         if( ! argflags[i]) {
1359                                 error_printf(GOB_WARN, a->line_no,
1360                                              "Unknown flag '%s' used, "
1361                                              "perhaps it was misspelled", flag);
1362                         }
1363                         g_string_sprintfa(flags, " | GTK_ARG_%s", flag);
1364                 }
1365
1366                 s = g_strdup(a->name);
1367                 g_strup(s);
1368                 out_printf(out, "\tgtk_object_add_arg_type(\"%s::%s\",\n"
1369                         "\t\tGTK_TYPE_%s,\n"
1370                         "\t\t%s,\n"
1371                         "\t\tARG_%s);\n",
1372                         typebase, a->name, a->gtktype, flags->str, s);
1373                 g_free(s);
1374                 g_string_free(flags, TRUE);
1375         }
1376         
1377         out_printf(out, "\n");
1378         if(get_arguments > 0)
1379                 out_printf(out, "\tgtk_object_class->get_arg = ___object_get_arg;\n");
1380         if(set_arguments > 0)
1381                 out_printf(out, "\tgtk_object_class->set_arg = ___object_set_arg;\n");
1382 }
1383
1384 static void
1385 print_initializer(Method *m, Variable *v)
1386 {
1387         char *root;
1388
1389         if(v->initializer == NULL)
1390                 return;
1391
1392         if(v->scope == PRIVATE_SCOPE)
1393                 root = g_strconcat(((FuncArg *)m->args->data)->name,
1394                                    "->_priv", NULL);
1395         else
1396                 root = g_strdup(((FuncArg *)m->args->data)->name);
1397
1398         if(v->initializer_line > 0)
1399                 out_addline_infile(out, v->initializer_line);
1400
1401         out_printf(out, "\t%s->%s = %s;\n",
1402                    root, v->id, v->initializer);
1403
1404         if(v->initializer_line > 0)
1405                 out_addline_outfile(out);
1406
1407         g_free(root);
1408 }
1409
1410 static void
1411 print_destructor(Variable *v)
1412 {
1413         char *root;
1414
1415         if(v->destructor == NULL)
1416                 return;
1417
1418         if(v->scope == PRIVATE_SCOPE)
1419                 root = "self->_priv";
1420         else
1421                 root = "self";
1422
1423         if(v->destructor_simple) {
1424                 if(v->destructor_line > 0)
1425                         out_addline_infile(out, v->destructor_line);
1426
1427                 out_printf(out, "\tif(%s->%s) { "
1428                            "((*(void (*)(void *))%s)) (%s->%s); "
1429                            "%s->%s = NULL; }\n",
1430                            root, v->id, v->destructor, root, v->id,
1431                            root, v->id);
1432
1433                 if(v->destructor_line > 0)
1434                         out_addline_outfile(out);
1435         } else {
1436                 out_printf(out, "#define VAR (%s->%s)\n", root, v->id);
1437                 out_printf(out, "\t{\n");
1438                 if(v->destructor_line > 0)
1439                         out_addline_infile(out, v->destructor_line);
1440
1441                 out_printf(out, "\t%s}\n", v->destructor);
1442
1443                 if(v->destructor_line > 0)
1444                         out_addline_outfile(out);
1445                 out_printf(out, "\tmemset(&VAR, 0, sizeof(VAR));\n");
1446                 out_printf(out, "#undef VAR\n");
1447         }
1448 }
1449
1450 static void
1451 add_destroy(Class *c)
1452 {
1453         out_printf(out, "\nstatic void\n"
1454                    "___destroy(GtkObject *obj_self)\n"
1455                    "{\n");
1456         out_printf(out,
1457                    "#define __GOB_FUNCTION__ \"%s::destroy\"\n",
1458                    c->otype);
1459
1460         if(destructors > 0) {
1461                 out_printf(out, "\t%s *self = %s (obj_self);\n",
1462                            typebase, macrobase);
1463         }
1464
1465         if(destroy_handler) {
1466                 /* so we get possible bad argument warning */
1467                 if(destroy_handler->line_no > 0)
1468                         out_addline_infile(out, destroy_handler->line_no);
1469                 out_printf(out, "\t___%x_%s_destroy(obj_self);\n",
1470                            (guint)destroy_handler->unique_id, funcbase);
1471                 if(destroy_handler->line_no > 0)
1472                         out_addline_outfile(out);
1473         } else {
1474                 out_printf(out,
1475                            "\tif(GTK_OBJECT_CLASS(parent_class)->destroy) \\\n"
1476                            "\t\t(* GTK_OBJECT_CLASS(parent_class)->destroy)(obj_self);\n");
1477         }
1478
1479         if(destructors > 0) {
1480                 GList *li;
1481                 for(li = ((Class *)class)->nodes;
1482                     li != NULL;
1483                     li = li->next) {
1484                         Node *n = li->data;
1485                         Variable *v = (Variable *)n;
1486                         if(n->type == VARIABLE_NODE &&
1487                            v->scope != CLASS_SCOPE)
1488                                 print_destructor(v);
1489                 }
1490         }
1491
1492         out_printf(out, "\treturn;\n");
1493         if(destructors > 0)
1494                 out_printf(out, "\tself = NULL;\n");
1495         out_printf(out, "}\n"
1496                    "#undef __GOB_FUNCTION__\n\n");
1497 }
1498
1499 static void
1500 add_finalize(Class *c)
1501 {
1502         /* Sort of a hack to make it work with gtk+ 1.3/2.0 */
1503         out_printf(out,
1504                    "\n#ifdef G_OBJECT_CLASS\n"
1505                    "static void\n"
1506                    "___finalize(GObject *obj_self)\n"
1507                    "#else /* !G_OBJECT_CLASS */\n"
1508                    "static void\n"
1509                    "___finalize(GtkObject *obj_self)\n"
1510                    "#endif /* G_OBJECT_CLASS */\n"
1511                    "{\n");
1512         out_printf(out,
1513                    "#define __GOB_FUNCTION__ \"%s::finalize\"\n",
1514                    c->otype);
1515
1516         if(privates > 0) {
1517                 out_printf(out, "\t%s *self = %s (obj_self);\n",
1518                            typebase, macrobase);
1519                 out_printf(out, "\tgpointer priv = self->_priv;\n");
1520         }
1521
1522         if(finalize_handler) {
1523                 /* so we get possible bad argument warning */
1524                 if(finalize_handler->line_no > 0)
1525                         out_addline_infile(out, finalize_handler->line_no);
1526                 out_printf(out, "\t___%x_%s_finalize(obj_self);\n",
1527                            (guint)finalize_handler->unique_id, funcbase);
1528                 if(finalize_handler->line_no > 0)
1529                         out_addline_outfile(out);
1530         } else {
1531                 /* Sort of a hack to make it work with gtk+ 1.3/2.0 */
1532                 out_printf(out,
1533                            "#ifdef G_OBJECT_CLASS\n"
1534                            "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
1535                            "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n"
1536                            "#else /* !G_OBJECT_CLASS */\n"
1537                            "\tif(GTK_OBJECT_CLASS(parent_class)->finalize) \\\n"
1538                            "\t\t(* GTK_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n"
1539                            "#endif /* G_OBJECT_CLASS */\n");
1540         }
1541
1542         if(privates > 0) {
1543                 out_printf(out, "\tg_free(priv);\n");
1544         }
1545
1546         out_printf(out, "}\n"
1547                    "#undef __GOB_FUNCTION__\n\n");
1548 }
1549
1550 static void
1551 make_bonobo_x_epv (Class *c, const char *classname)
1552 {
1553         GList *li;
1554         gboolean added_line = FALSE;
1555
1556         for (li = c->nodes; li != NULL; li = li->next) {
1557                 Node *n = li->data;
1558                 Method *m = (Method *)n;
1559                 if(n->type != METHOD_NODE ||
1560                    m->method == OVERRIDE_METHOD)
1561                         continue;
1562
1563                 if (m->bonobo_x_func) {
1564                         if(m->line_no > 0) {
1565                                 out_addline_infile(out, m->line_no);
1566                                 added_line = TRUE;
1567                         } else if (m->line_no == 0 &&
1568                                    added_line) {
1569                                 out_addline_outfile(out);
1570                                 added_line = FALSE;
1571                         }
1572                         out_printf (out, "\t%s->_epv.%s = %s;\n",
1573                                     classname, m->id, m->id);
1574                 }
1575         }
1576         if (added_line)
1577                 out_addline_outfile(out);
1578 }
1579
1580 static void
1581 add_inits(Class *c)
1582 {
1583         GList *li;
1584         for(li=c->nodes;li;li=g_list_next(li)) {
1585                 Node *n = li->data;
1586                 Method *m;
1587
1588                 gboolean add_unused_class = FALSE;
1589
1590                 if(n->type != METHOD_NODE)
1591                         continue;
1592                 m = (Method *)n;
1593                 if(m->method == INIT_METHOD) {
1594                         if(m->line_no > 0)
1595                                 out_addline_infile(out, m->line_no);
1596                         print_method(out, "static ", "\n", "", " ", "", "\n",
1597                                      m, FALSE, FALSE, TRUE);
1598                         if(m->line_no > 0)
1599                                 out_addline_outfile(out);
1600                         out_printf(out, "{\n"
1601                                    "#define __GOB_FUNCTION__ \"%s::init\"\n",
1602                                    c->otype);
1603                         if(privates > 0) {
1604                                 out_printf(out, "\t%s->_priv = "
1605                                            "g_new0 (%sPrivate, 1);\n",
1606                                            ((FuncArg *)m->args->data)->name,
1607                                            typebase);
1608                         } else if(always_private_struct) {
1609                                 out_printf(out, "\t%s->_priv = NULL;\n",
1610                                            ((FuncArg *)m->args->data)->name);
1611                         }
1612                         if(initializers > 0) {
1613                                 GList *li;
1614                                 for(li = ((Class *)class)->nodes;
1615                                     li != NULL;
1616                                     li = li->next) {
1617                                         Node *n = li->data;
1618                                         Variable *v = (Variable *)n;
1619                                         if(n->type != VARIABLE_NODE ||
1620                                            v->scope == CLASS_SCOPE)
1621                                                 continue;
1622                                         print_initializer(m, v);
1623                                 }
1624                         }
1625                 } else if(m->method == CLASS_INIT_METHOD) {
1626                         gboolean did_base_obj = FALSE;
1627
1628                         if(m->line_no > 0)
1629                                 out_addline_infile(out, m->line_no);
1630                         print_method(out, "static ", "\n", "", " ", "", "\n",
1631                                      m, FALSE, FALSE, TRUE);
1632                         if(m->line_no > 0)
1633                                 out_addline_outfile(out);
1634                         out_printf(out, "{\n"
1635                                    "#define __GOB_FUNCTION__ \"%s::class_init\"\n",
1636                                    c->otype);
1637                         if(signals > 0 ||
1638                            set_arguments > 0 ||
1639                            get_arguments > 0 ||
1640                            need_destroy ||
1641                            need_finalize) {
1642                                 add_unused_class = TRUE;
1643                                 out_printf(out,
1644                                            "\tGtkObjectClass *"
1645                                            "gtk_object_class = "
1646                                            "(GtkObjectClass*) %s;\n",
1647                                            ((FuncArg *)m->args->data)->name);
1648                                 out_printf(out,
1649                                            "#ifdef G_OBJECT_CLASS\n"
1650                                            "\tGObjectClass *"
1651                                            "g_object_class = "
1652                                            "(GObjectClass*) %s;\n"
1653                                            "#endif /* G_OBJECT_CLASS */\n",
1654                                            ((FuncArg *)m->args->data)->name);
1655                                 did_base_obj = TRUE;
1656                         }
1657
1658                         if(overrides > 0)
1659                                 add_overrides(c,
1660                                               ((FuncArg *)m->args->data)->name,
1661                                               did_base_obj);
1662
1663                         if(initializers > 0) {
1664                                 GList *li;
1665                                 for(li = ((Class *)class)->nodes;
1666                                     li != NULL;
1667                                     li = li->next) {
1668                                         Node *n = li->data;
1669                                         Variable *v = (Variable *)n;
1670                                         if(n->type == VARIABLE_NODE &&
1671                                            v->scope == CLASS_SCOPE)
1672                                                 print_initializer(m, v);
1673                                 }
1674                         }
1675                         
1676                         out_printf(out, "\n\tparent_class = ");
1677                         if(for_cpp)
1678                                 out_printf(out, "(%sClass *)", ptypebase);
1679                         out_printf(out, "gtk_type_class (%s_get_type ());\n",
1680                                    pfuncbase);
1681
1682                         if(signals > 0)
1683                                 add_signals(c);
1684
1685                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
1686
1687                         /* if there are no handlers for these things, we
1688                          * need to set them up here */
1689                         if(need_destroy && !destroy_handler)
1690                                 out_printf(out, "\tgtk_object_class->destroy "
1691                                            "= ___destroy;\n");
1692                         if(need_finalize && !finalize_handler)
1693                                 out_printf(out,
1694                                            "#ifdef G_OBJECT_CLASS\n"
1695                                            "\tg_object_class->finalize = ___finalize;\n"
1696                                            "#else /* !G_OBJECT_CLASS */\n"
1697                                            "\tgtk_object_class->finalize = ___finalize;\n"
1698                                            "#endif /* G_OBJECT_CLASS */\n");
1699                         
1700                         if(get_arguments > 0 || set_arguments > 0)
1701                                 make_arguments(c);
1702
1703                         if (c->bonobo_x_class != NULL) {
1704                                 make_bonobo_x_epv (c, ((FuncArg *)m->args->data)->name);
1705                         }
1706                 } else
1707                         continue;
1708
1709                 if(m->cbuf) {
1710                         out_printf(out, " {\n");
1711                         out_addline_infile(out, m->ccode_line);
1712                         out_printf(out, "%s\n", m->cbuf);
1713                         out_addline_outfile(out);
1714                         out_printf(out, " }\n");
1715                 }
1716                 out_printf(out, "\treturn;\n");
1717                 out_printf(out,
1718                            "\t%s = NULL;\n",
1719                            ((FuncArg *)m->args->data)->name);
1720                 if(add_unused_class) {
1721                         out_printf(out,
1722                                    "\tgtk_object_class = NULL;\n"
1723                                    "#ifdef G_OBJECT_CLASS\n"
1724                                    "\tg_object_class = NULL;\n"
1725                                    "#endif /* G_OBJECT_CLASS */\n");
1726                 }
1727                 out_printf(out, "}\n"
1728                            "#undef __GOB_FUNCTION__\n");
1729         }
1730 }
1731
1732 static void
1733 add_getset_arg(Class *c, gboolean is_set)
1734 {
1735         GList *li;
1736         out_printf(out, "\nstatic void\n"
1737                    "___object_%s_arg (GtkObject *object,\n"
1738                    "\tGtkArg *arg,\n"
1739                    "\tguint arg_id)\n"
1740                    "#define __GOB_FUNCTION__ \"%s::%s_arg\"\n"
1741                    "{\n"
1742                    "\t%s *self;\n\n"
1743                    "\tself = %s (object);\n\n"
1744                    "\tswitch (arg_id) {\n",
1745                    is_set ? "set" : "get",
1746                    c->otype, is_set ? "set" : "get",
1747                    typebase, macrobase);
1748
1749         for(li=c->nodes;li;li=g_list_next(li)) {
1750                 Node *n = li->data;
1751                 Argument *a;
1752                 char *s;
1753                 char *cbuf;
1754                 int line_no;
1755                 if(n->type != ARGUMENT_NODE)
1756                         continue;
1757                 a = (Argument *)n;
1758                 if(is_set) {
1759                         cbuf = a->set;
1760                         line_no = a->set_line;
1761                 } else {
1762                         cbuf = a->get;
1763                         line_no = a->get_line;
1764                 }
1765                 if(!cbuf)
1766                         continue;
1767                 s = g_strdup(a->name);
1768                 g_strup(s);
1769                 out_printf(out, "\tcase ARG_%s:\n", s);
1770                 if(is_set && a->atype) {
1771                         char *cast = get_type(a->atype, TRUE);
1772                         if(no_gnu || for_cpp) {
1773                                 out_printf(out, "#define ARG "
1774                                            "((%s)GTK_VALUE_%s(*arg))\n",
1775                                            cast, a->gtktype);
1776                         } else {
1777                                 out_printf(out, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
1778                                 if(strcmp(a->gtktype, "OBJECT")==0) {
1779                                         out_printf(out, "#define ARG "
1780                                                    "({%s foo = "
1781                                                    "GTK_VALUE_POINTER(*arg); "
1782                                                    "foo; })\n",
1783                                                    cast);
1784                                 } else {
1785                                         out_printf(out, "#define ARG "
1786                                                    "({%s foo = "
1787                                                    "GTK_VALUE_%s(*arg); "
1788                                                    "foo; })\n",
1789                                                    cast, a->gtktype);
1790                                 }
1791                                 out_printf(out, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
1792                                 out_printf(out, "#define ARG "
1793                                            "((%s)GTK_VALUE_%s(*arg))\n",
1794                                            cast, a->gtktype);
1795                                 out_printf(out, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
1796                         }
1797                         out_printf(out, "\t\t{\n");
1798                         g_free(cast);
1799                 } else if(!is_set && strcmp(a->gtktype, "OBJECT")==0) {
1800                         out_printf(out,
1801                                    "#define ARG (GTK_VALUE_POINTER(*arg))\n"
1802                                    "\t\t{\n");
1803                 } else {
1804                         out_printf(out,
1805                                    "#define ARG (GTK_VALUE_%s(*arg))\n"
1806                                    "\t\t{\n",
1807                                    a->gtktype);
1808                 }
1809                 g_free(s);
1810                 if(line_no > 0)
1811                         out_addline_infile(out, line_no);
1812                 out_printf(out, "%s\n", cbuf);
1813                 if(line_no > 0)
1814                         out_addline_outfile(out);
1815                 out_printf(out, "\t\t}\n\t\tbreak;\n"
1816                         "#undef ARG\n");
1817         }
1818         out_printf(out, "\tdefault:\n\t\tbreak;\n\t}\n"
1819                    "\treturn;\n\tself = NULL;\n\targ = NULL;\n}\n"
1820                    "#undef __GOB_FUNCTION__\n");
1821 }
1822
1823 static void
1824 print_checks(Method *m, FuncArg *fa)
1825 {
1826         GList *li;
1827         gboolean is_void;
1828         gboolean checked_null = FALSE;
1829         is_void = (strcmp(m->mtype->name, "void")==0 &&
1830                    m->mtype->pointer == NULL);
1831         
1832         for(li = fa->checks; li; li = g_list_next(li)) {
1833                 Check *ch = li->data;
1834                 char *s;
1835                 /* point to the method prot in .gob for failed checks */
1836                 if(m->line_no > 0)
1837                         out_addline_infile(out, m->line_no);
1838                 if(is_void)
1839                         out_printf(out, "\tg_return_if_fail (");
1840                 else
1841                         out_printf(out, "\tg_return_val_if_fail (");
1842                 switch(ch->chtype) {
1843                 case NULL_CHECK:
1844                         out_printf(out, "%s != NULL", fa->name);
1845                         checked_null = TRUE;
1846                         break;
1847                 case TYPE_CHECK:
1848                         s = make_pre_macro(fa->atype->name, "IS");
1849                         if(checked_null)
1850                                 out_printf(out, "%s (%s)", s, fa->name);
1851                         else
1852                                 /* if not check null, null may be valid */
1853                                 out_printf(out, "!(%s) || %s (%s)", fa->name,
1854                                            s, fa->name);
1855                         g_free(s);
1856                         break;
1857                 case LT_CHECK:
1858                         out_printf(out, "%s < %s", fa->name, ch->number);
1859                         break;
1860                 case GT_CHECK:
1861                         out_printf(out, "%s > %s", fa->name, ch->number);
1862                         break;
1863                 case LE_CHECK:
1864                         out_printf(out, "%s <= %s", fa->name, ch->number);
1865                         break;
1866                 case GE_CHECK:
1867                         out_printf(out, "%s >= %s", fa->name, ch->number);
1868                         break;
1869                 case EQ_CHECK:
1870                         out_printf(out, "%s == %s", fa->name, ch->number);
1871                         break;
1872                 case NE_CHECK:
1873                         out_printf(out, "%s != %s", fa->name, ch->number);
1874                         break;
1875                 }
1876                 if(is_void)
1877                         out_printf(out, ");\n");
1878                 else {
1879                         out_printf(out, ", (");
1880                         print_type(out, m->mtype, TRUE);
1881                         out_printf(out, ")%s);\n",
1882                                 m->onerror?m->onerror:"0");
1883                 }
1884         }
1885 }
1886
1887 static void
1888 print_preconditions(Method *m)
1889 {
1890         GList *li;
1891         
1892         for(li=m->args;li;li=g_list_next(li)) {
1893                 FuncArg *fa = li->data;
1894                 if(fa->checks)
1895                         print_checks(m, fa);
1896         }
1897         if(m->line_no>0)
1898                 out_addline_outfile(out);
1899 }
1900
1901 static void
1902 print_method_body(Method *m, int pre)
1903 {
1904         if (m->line_no > 0)
1905                 out_addline_outfile(out);
1906         out_printf(out, "{\n"
1907                    "#define __GOB_FUNCTION__ \"%s::%s\"\n",
1908                    ((Class *)class)->otype,
1909                    get_real_id(m->id));
1910         if(pre)
1911                 print_preconditions(m);
1912
1913         /* Note: the trailing }'s are on one line, this is so
1914            that we get the no return warning correctly and point to
1915            the correct line in the .gob file, yes this is slightly
1916            ugly in the .c file, but that is not supposed to be
1917            human readable anyway. */
1918         if(m->cbuf) {
1919                 out_printf(out, "{\n");
1920                 if(m->ccode_line>0)
1921                         out_addline_infile(out, m->ccode_line);
1922                 out_printf(out, "\t%s}", m->cbuf);
1923         }
1924
1925         /* Note, there is no \n between the last } and this } so that
1926          * errors/warnings reported on the end of the body get pointed to the
1927          * right line in the .gob source */
1928         out_printf(out, "}\n");
1929
1930         if(m->cbuf)
1931                 out_addline_outfile(out);
1932         out_printf(out, "#undef __GOB_FUNCTION__\n");
1933 }
1934
1935 static void
1936 put_signal_args(Method *m)
1937 {
1938         GList *li;
1939         GList *ali;
1940         for(ali = m->gtktypes->next, li=m->args->next;
1941             li && ali;
1942             li=li->next, ali=ali->next) {
1943                 FuncArg *fa = li->data;
1944                 const char *cast = get_cast(ali->data, FALSE);
1945                 /* we should have already proved before that
1946                    the we know all the types */
1947                 g_assert(cast);
1948
1949                 out_printf(out, ",\n\t\t(%s)%s", cast,
1950                            fa->name);
1951         }
1952 }
1953
1954 static char *
1955 get_arg_names_for_macro(Method *m)
1956 {
1957         char *p;
1958         GList *li;
1959         GString *gs = g_string_new(NULL);
1960         p = "";
1961         for(li=m->args;li;li=g_list_next(li)) {
1962                 FuncArg *arg = li->data;
1963                 g_string_sprintfa(gs, "%s___%s", p, arg->name);
1964                 p = ",";
1965         }
1966         p = gs->str;
1967         g_string_free(gs, FALSE);
1968         return p;
1969 }
1970
1971 static void
1972 put_method(Method *m)
1973 {
1974         char *s, *args, *doc;
1975         gboolean is_void;
1976         is_void = (strcmp(m->mtype->name, "void")==0 &&
1977                    m->mtype->pointer == NULL);
1978         out_printf(out, "\n");
1979         if(m->method != OVERRIDE_METHOD) {
1980                 doc = get_gtk_doc(m->id);
1981                 if(doc) {
1982                         out_printf(out, "%s", doc);
1983                         g_free(doc);
1984                 }
1985         }
1986         switch(m->method) {
1987         case REGULAR_METHOD:
1988                 if(m->line_no > 0)
1989                         out_addline_infile(out, m->line_no);
1990                 if(m->scope == PRIVATE_SCOPE)
1991                         print_method(out, "static ", "\n", "", " ", "", "\n",
1992                                      m, FALSE, FALSE, TRUE);
1993                 else /* PUBLIC, PROTECTED */
1994                         print_method(out, "", "\n", "", " ", "", "\n",
1995                                      m, FALSE, FALSE, TRUE);
1996                 print_method_body(m, TRUE);
1997                 /* the outfile line was added above */
1998                 break;
1999         case SIGNAL_FIRST_METHOD:
2000         case SIGNAL_LAST_METHOD:
2001                 if(m->line_no > 0)
2002                         out_addline_infile(out, m->line_no);
2003                 if(m->scope == PRIVATE_SCOPE)
2004                         print_method(out, "static ", "\n", "", " ", "", "\n",
2005                                      m, FALSE, FALSE, TRUE);
2006                 else /* PUBLIC, PROTECTED */
2007                         print_method(out, "", "\n", "", " ", "", "\n",
2008                                      m, FALSE, FALSE, TRUE);
2009                 out_addline_outfile(out);
2010                 out_printf(out, "{\n");
2011                 s = g_strdup(get_real_id(m->id));
2012                 g_strup(s);
2013                 if(strcmp(m->mtype->name, "void") == 0 &&
2014                    m->mtype->pointer == NULL) {
2015                         print_preconditions(m);
2016                         if(((FuncArg *)m->args->data)->name)
2017                         out_printf(out, "\tgtk_signal_emit (GTK_OBJECT (%s),\n"
2018                                 "\t\tobject_signals[%s_SIGNAL]",
2019                                 ((FuncArg *)m->args->data)->name, s);
2020                         put_signal_args(m);
2021                         out_printf(out, ");\n}\n");
2022                 } else {
2023                         out_printf(out, "\t");
2024                         print_type(out, m->mtype, TRUE);
2025                         out_printf(out, "return_val = (");
2026                         print_type(out, m->mtype, TRUE);
2027                         if(m->defreturn)
2028                                 out_printf(out, ")(%s);\n", m->defreturn);
2029                         else if(m->onerror)
2030                                 out_printf(out, ")(%s);\n", m->onerror);
2031                         else
2032                                 out_printf(out, ")(0);\n");
2033                         print_preconditions(m);
2034                         out_printf(out, "\tgtk_signal_emit (GTK_OBJECT (%s),\n"
2035                                 "\t\tobject_signals[%s_SIGNAL]",
2036                                 ((FuncArg *)m->args->data)->name, s);
2037                         put_signal_args(m);
2038                         out_printf(out, ",\n\t\t&return_val);\n"
2039                                 "\treturn return_val;\n}\n");
2040                 }
2041
2042                 if(!m->cbuf)
2043                         break;
2044                 if(m->line_no > 0)
2045                         out_addline_infile(out, m->line_no);
2046                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
2047                              m, FALSE, FALSE, TRUE);
2048                 print_method_body(m, FALSE);
2049                 /* the outfile line was added above */
2050                 break;
2051         case VIRTUAL_METHOD:
2052                 if(m->line_no > 0)
2053                         out_addline_infile(out, m->line_no);
2054                 if(m->scope==PRIVATE_SCOPE)
2055                         print_method(out, "static ", "\n", "", " ", "", "\n",
2056                                      m, FALSE, FALSE, TRUE);
2057                 else /* PUBLIC, PROTECTED */
2058                         print_method(out, "", "\n", "", " ", "", "\n",
2059                                      m, FALSE, FALSE, TRUE);
2060                 out_addline_outfile(out);
2061                 out_printf(out, "{\n"
2062                         "\t%sClass *klass;\n", typebase);
2063                 print_preconditions(m);
2064                 out_printf(out, "\tklass = %s_GET_CLASS(%s);\n\n"
2065                         "\tif(klass->%s)\n",
2066                         macrobase, ((FuncArg *)m->args->data)->name,
2067                         get_real_id(m->id));
2068                 if(strcmp(m->mtype->name, "void") == 0 &&
2069                    m->mtype->pointer == NULL) {
2070                         GList *li;
2071                         out_printf(out, "\t\t(*klass->%s)(%s",
2072                                    get_real_id(m->id),
2073                                    ((FuncArg *)m->args->data)->name);
2074                         for(li=m->args->next;li;li=g_list_next(li)) {
2075                                 FuncArg *fa = li->data;
2076                                 out_printf(out, ",%s", fa->name);
2077                         }
2078                         out_printf(out, ");\n}\n");
2079                 } else {
2080                         GList *li;
2081                         out_printf(out, "\t\treturn (*klass->%s)(%s",
2082                                    get_real_id(m->id),
2083                                    ((FuncArg *)m->args->data)->name);
2084                         for(li=m->args->next;li;li=g_list_next(li)) {
2085                                 FuncArg *fa = li->data;
2086                                 out_printf(out, ",%s", fa->name);
2087                         }
2088                         out_printf(out, ");\n"
2089                                 "\telse\n"
2090                                 "\t\treturn (");
2091                         print_type(out, m->mtype, TRUE);
2092                         if(m->defreturn)
2093                                 out_printf(out, ")(%s);\n}\n", m->defreturn);
2094                         else if(m->onerror)
2095                                 out_printf(out, ")(%s);\n}\n", m->onerror);
2096                         else
2097                                 out_printf(out, ")(0);\n}\n");
2098                 }
2099
2100                 if(!m->cbuf)
2101                         break;
2102                 if(m->line_no > 0)
2103                         out_addline_infile(out, m->line_no);
2104                 print_method(out, "static ", "\n___real_", "", " ", "", "\n",
2105                              m, FALSE, FALSE, TRUE);
2106                 print_method_body(m, FALSE);
2107                 /* the outfile line was added above */
2108                 break;
2109         case OVERRIDE_METHOD:
2110                 if(!m->cbuf)
2111                         break;
2112                 if(m->line_no > 0)
2113                         out_addline_infile(out, m->line_no);
2114                 s = g_strdup_printf("\n___%x_", (guint)m->unique_id);
2115                 print_method(out, "static ", s, "", " ", "", "\n",
2116                              m, FALSE, FALSE, FALSE);
2117                 g_free(s);
2118                 out_addline_outfile(out);
2119                 s = replace_sep(m->otype, '_');
2120                 g_strup(s);
2121                 args = get_arg_names_for_macro(m);
2122                 if(is_void) {
2123                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
2124                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
2125                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n",
2126                                    args, s, get_real_id(m->id), s, get_real_id(m->id), args);
2127                 } else {
2128                         out_printf(out, "#define PARENT_HANDLER(%s) \\\n"
2129                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
2130                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n"
2131                                    "\t\t(",
2132                                    args, s, get_real_id(m->id), s, get_real_id(m->id), args);
2133                         out_printf(out, "(");
2134                         print_type(out, m->mtype, TRUE);
2135                         out_printf(out, ")%s))\n",
2136                                    m->onerror?m->onerror:"0");
2137                 }
2138                 g_free(args);
2139                 g_free(s);
2140                 print_method_body(m, TRUE);
2141                 /* the outfile line was added above */
2142                 out_printf(out, "#undef PARENT_HANDLER\n");
2143                 break;
2144         default:
2145                 break;
2146         }
2147 }
2148
2149 static void
2150 open_files(void)
2151 {
2152         char *outfile, *outfileh, *outfileph;
2153
2154         if(!for_cpp)
2155                 outfile = g_strconcat(filebase, ".c", NULL);
2156         else
2157                 outfile = g_strconcat(filebase, ".cc", NULL);
2158         if(no_touch_headers)
2159                 outfileh = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
2160         else
2161                 outfileh = g_strconcat(filebase, ".h", NULL);
2162
2163         if((privates > 0 || protecteds > 0 ||
2164             private_header == PRIVATE_HEADER_ALWAYS) &&
2165            private_header != PRIVATE_HEADER_NEVER)
2166                 outfileph = g_strconcat(filebase, "-private.h", NULL);
2167         else
2168                 outfileph = NULL;
2169
2170         
2171         if(no_write) {
2172                 devnull = fopen("/dev/null", "w");
2173                 if(!devnull)
2174                         g_error("Cannot open null device");
2175                 out = devnull;
2176                 outh = devnull;
2177                 if(outfileph)
2178                         outph = devnull;
2179         } else {
2180                 out = fopen(outfile, "w");
2181                 if(!out) {
2182                         g_error("Cannot open outfile: %s", outfile);
2183                 }
2184                 outh = fopen(outfileh, "w");
2185                 if(!outh)
2186                         g_error("Cannot open outfile: %s", outfileh);
2187                 if(outfileph) {
2188                         outph = fopen(outfileph, "w");
2189                         if(!outph)
2190                                 g_error("Cannot open outfile: %s", outfileh);
2191                 }
2192         }
2193 }
2194
2195 static void
2196 put_argument_nongnu_wrappers(Class *c)
2197 {
2198         GList *li;
2199
2200         if(get_arguments < 0 && set_arguments < 0)
2201                 return;
2202
2203         for(li=c->nodes;li;li=g_list_next(li)) {
2204                 Node *n = li->data;
2205                 Argument *a = (Argument *)n;
2206                 char *aname;
2207                 char *cast;
2208
2209                 if(n->type != ARGUMENT_NODE)
2210                         continue;
2211
2212                 aname = g_strdup(a->name);
2213                 g_strup(aname);
2214
2215                 if(a->atype)
2216                         cast = get_type(a->atype, TRUE);
2217                 else
2218                         cast = g_strdup(get_cast(a->gtktype, TRUE));
2219
2220                 if(cast) {
2221                         if(a->set)
2222                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2223                                            "\"%s\",(%s)(arg)\n",
2224                                            macrobase, aname, a->name, cast);
2225                         if(a->get)
2226                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2227                                            "\"%s\",(%s*)(arg)\n",
2228                                            macrobase, aname, a->name, cast);
2229                 } else {
2230                         if(a->set)
2231                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2232                                            "\"%s\",(arg)\n",
2233                                            macrobase, aname, a->name);
2234                         if(a->get)
2235                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2236                                            "\"%s\",(arg)\n",
2237                                            macrobase, aname, a->name);
2238                 }
2239                 g_free(cast);
2240                 g_free(aname);
2241         }
2242 }
2243
2244 static void
2245 put_argument_gnu_wrappers(Class *c)
2246 {
2247         GList *li;
2248
2249         if(get_arguments < 0 && set_arguments < 0)
2250                 return;
2251
2252         for(li=c->nodes;li;li=g_list_next(li)) {
2253                 Node *n = li->data;
2254                 Argument *a = (Argument *)n;
2255                 char *s;
2256                 char *cast;
2257                 if(n->type != ARGUMENT_NODE)
2258                         continue;
2259                 s = g_strdup(a->name);
2260                 g_strup(s);
2261                 if(a->atype)
2262                         cast = get_type(a->atype, TRUE);
2263                 else
2264                         cast = g_strdup(get_cast(a->gtktype, TRUE));
2265                 if(cast) {
2266                         if(a->set)
2267                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2268                                            "\"%s\",({%sz = (arg); z;})\n",
2269                                            macrobase, s, a->name, cast);
2270                         if(a->get)
2271                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2272                                            "\"%s\",({%s*z = (arg); z;})\n",
2273                                            macrobase, s, a->name, cast);
2274                 } else {
2275                         if(a->set)
2276                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
2277                                            "\"%s\",(arg)\n",
2278                                            macrobase, s, a->name);
2279                         if(a->get)
2280                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
2281                                            "\"%s\",(arg)\n",
2282                                            macrobase, s, a->name);
2283                 }
2284                 g_free(cast);
2285                 g_free(s);
2286         }
2287 }
2288
2289 static void
2290 print_ccode_block(CCode *cc)
2291 {
2292         FILE *fp;
2293         switch(cc->cctype) {
2294         case HT_CCODE:
2295                 /* HT code is printed exactly like normal header
2296                    code but is printed before */
2297         case H_CCODE:
2298                 fp = outh;
2299                 out_printf(fp, "\n");
2300                 break;
2301         case AT_CCODE:
2302                 /* AT code is printed exactly like normal 'all'
2303                    code but is printed before */
2304         case A_CCODE:
2305                 if(outph) {
2306                         out_printf(outph, "\n");
2307                         out_printf(outph, "%s\n", cc->cbuf);
2308                         out_addline_infile(outph, cc->line_no);
2309                         out_addline_outfile(outph);
2310                 }
2311                 out_printf(outh, "\n");
2312                 out_printf(outh, "%s\n", cc->cbuf);
2313                 fp = out;
2314                 out_printf(fp, "\n");
2315                 out_addline_infile(fp, cc->line_no);
2316                 break;
2317         default:
2318         case C_CCODE:
2319                 fp = out;
2320                 out_printf(fp, "\n");
2321                 out_addline_infile(fp, cc->line_no);
2322                 break;
2323         case PH_CCODE:
2324                 if(outph)
2325                         fp = outph;
2326                 else
2327                         fp = out;
2328                 out_printf(fp, "\n");
2329                 out_addline_infile(fp, cc->line_no);
2330                 break;
2331         }
2332         out_printf(fp, "%s\n", cc->cbuf);
2333         if(cc->cctype == C_CCODE ||
2334            cc->cctype == A_CCODE ||
2335            cc->cctype == AT_CCODE ||
2336            cc->cctype == PH_CCODE)
2337                 out_addline_outfile(fp);
2338 }
2339
2340 static void
2341 print_class_block(Class *c)
2342 {
2343         GList *l;
2344         char *s;
2345         gboolean printed_private = FALSE;
2346
2347         if(any_special) {
2348                 out_printf(out, "/* utility types we may need */\n");
2349                 if(special_array[SPECIAL_2POINTER])
2350                         out_printf(out, "typedef struct { "
2351                                    "gpointer a; gpointer b; "
2352                                    "} ___twopointertype;\n");
2353                 if(special_array[SPECIAL_3POINTER])
2354                         out_printf(out, "typedef struct { "
2355                                    "gpointer a; gpointer b; "
2356                                    "gpointer c; "
2357                                    "} ___threepointertype;\n");
2358                 if(special_array[SPECIAL_INT_POINTER])
2359                         out_printf(out, "typedef struct { "
2360                                    "gint a; gpointer b; "
2361                                    "} ___intpointertype;\n");
2362                 out_printf(out, "\n");
2363         }
2364
2365         out_printf(outh, "\n/*\n"
2366                    " * Type checking and casting macros\n"
2367                    " */\n");
2368         out_printf(outh, "#define %s\t"
2369                    "(%s_get_type())\n",
2370                    macrotype, funcbase);
2371         out_printf(outh, "#define %s(obj)\t"
2372                    "GTK_CHECK_CAST((obj), %s_get_type(), %s)\n",
2373                    macrobase, funcbase, typebase);
2374         out_printf(outh, "#define %s_CONST(obj)\t"
2375                    "GTK_CHECK_CAST((obj), %s_get_type(), %s const)\n",
2376                    macrobase, funcbase, typebase); 
2377         out_printf(outh, "#define %s_CLASS(klass)\t"
2378                    "GTK_CHECK_CLASS_CAST((klass), %s_get_type(), %sClass)\n",
2379                    macrobase, funcbase, typebase);
2380         out_printf(outh, "#define %s(obj)\t"
2381                    "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
2382                    macrois, funcbase);
2383         out_printf(outh, "#ifdef GTK_CHECK_GET_CLASS\n"
2384                    "#define %s_GET_CLASS(obj)\t"
2385                    "GTK_CHECK_GET_CLASS((obj), %s_get_type(), %sClass)\n",
2386                    macrobase, funcbase, typebase);
2387         out_printf(outh, "#else /* !GTK_CHECK_GET_CLASS */\n"
2388                    "#define %s_GET_CLASS(obj)\t"
2389                    "((%sClass *)GTK_OBJECT(obj)->klass)\n"
2390                    "#endif /* GTK_CHECK_GET_CLASS */\n",
2391                    macrobase, typebase);
2392
2393         if( ! no_self_alias) {
2394                 out_printf(out, "/* self casting macros */\n");
2395                 out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
2396                 out_printf(out, "#define SELF_CONST(x) %s_CONST(x)\n", macrobase);
2397                 out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
2398                 out_printf(out, "#define TYPE_SELF %s\n", macrotype);
2399                 out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n",
2400                            macrobase);
2401                 out_printf(out, "#define SELF_GET_CLASS(x) %s_GET_CLASS(x)\n\n",
2402                            macrobase);
2403
2404                 out_printf(out, "/* self typedefs */\n");
2405                 out_printf(out, "typedef %s Self;\n", typebase);
2406                 out_printf(out, "typedef %sClass SelfClass;\n\n", typebase);
2407         }
2408
2409         out_printf(out, "/* GTK_CLASS_TYPE for 1.2<->1.3/2.0 GTK+ compatibility */\n");
2410         out_printf(out,
2411                    "#ifndef GTK_CLASS_TYPE\n"
2412                    "#define GTK_CLASS_TYPE(x) (GTK_OBJECT_CLASS(x)->type)\n"
2413                    "#endif /* GTK_CLASS_TYPE */\n\n");
2414
2415         if(privates > 0 || always_private_struct) {
2416                 out_printf(outh, "\n/* Private structure type */\n");
2417                 out_printf(outh, "typedef struct _%sPrivate %sPrivate;\n",
2418                            typebase, typebase);
2419                 if(privates == 0)
2420                         out_printf(outh, "/* There are no privates, this "
2421                                    "structure is thus never defined */\n");
2422         }
2423
2424         out_printf(outh, "\n/*\n"
2425                    " * Main object structure\n"
2426                    " */\n");
2427         s = replace_sep(c->otype, '_');
2428         g_strup(s);
2429         out_printf(outh, "#ifndef __TYPEDEF_%s__\n"
2430                    "#define __TYPEDEF_%s__\n", s, s);
2431         g_free(s);
2432         out_printf(outh, "typedef struct _%s %s;\n"
2433                    "#endif\n", typebase, typebase);
2434         out_printf(outh, "struct _%s {\n\t%s __parent__;\n",
2435                    typebase, ptypebase);
2436         for(l=c->nodes; l; l=g_list_next(l)) {
2437                 static gboolean printed_public = FALSE;
2438                 Node *n = l->data;
2439                 Variable *v = (Variable *)n;
2440                 if(n->type == VARIABLE_NODE &&
2441                    v->scope == PUBLIC_SCOPE) {
2442                         if( ! printed_public) {
2443                                 out_printf(outh, "\t/*< public >*/\n");
2444                                 printed_public = TRUE;
2445                         }
2446                         put_variable((Variable *)n, outh);
2447                 }
2448         }
2449         /* put protecteds always AFTER publics */
2450         for(l=c->nodes; l; l=g_list_next(l)) {
2451                 Node *n = l->data;
2452                 Variable *v = (Variable *)n;
2453                 if(n->type == VARIABLE_NODE &&
2454                    v->scope == PROTECTED_SCOPE) {
2455                         if( ! printed_private) {
2456                                 out_printf(outh, "\t/*< private >*/\n");
2457                                 printed_private = TRUE;
2458                         }
2459                         put_variable((Variable *)n, outh);
2460                 }
2461         }
2462         if(privates > 0 || always_private_struct) {
2463                 if( ! printed_private)
2464                         out_printf(outh, "\t/*< private >*/\n");
2465                 out_printf(outh, "\t%sPrivate *_priv;\n", typebase);
2466         }
2467         out_printf(outh, "};\n");
2468
2469         if(privates > 0) {
2470                 FILE *outfp;
2471
2472                 /* if we are to stick this into the private
2473                    header, if not stick it directly into the
2474                    C file */
2475                 if(outph) 
2476                         outfp = outph;
2477                 else
2478                         outfp = out;
2479
2480                 out_printf(outfp, "struct _%sPrivate {\n",
2481                            typebase);
2482                 for(l=c->nodes; l; l=l->next) {
2483                         Node *n = l->data;
2484                         Variable *v = (Variable *)n;
2485                         if(n->type == VARIABLE_NODE &&
2486                            v->scope == PRIVATE_SCOPE) {
2487                                 out_addline_infile(outfp, v->line_no);
2488                                 put_variable(v, outfp);
2489                         }
2490                 }
2491                 out_addline_outfile(outfp);
2492                 out_printf(outfp, "};\n");
2493         }
2494
2495         out_printf(outh, "\n/*\n"
2496                    " * Class definition\n"
2497                    " */\n");
2498         out_printf(outh, "typedef struct _%sClass %sClass;\n",
2499                    typebase, typebase);
2500         out_printf(outh,
2501                    "struct _%sClass {\n\t%sClass __parent__;\n",
2502                    typebase, ptypebase);
2503         for(l = c->nodes; l != NULL; l = l->next) {
2504                 Node *n = l->data;
2505                 if(n->type == METHOD_NODE)
2506                         put_vs_method((Method *)n);
2507         }
2508         /* If BonoboX type class put down the epv */
2509         if (c->bonobo_x_class != NULL) {
2510                 out_printf (outh,
2511                             "\t/* Bonobo object epv */\n"
2512                             "\tPOA_%s__epv _epv;\n",
2513                             c->bonobo_x_class);
2514         }
2515         /* put class scope variables */
2516         for(l = c->nodes; l != NULL; l = l->next) {
2517                 Node *n = l->data;
2518                 Variable *v = (Variable *)n;
2519                 if(n->type == VARIABLE_NODE &&
2520                    v->scope == CLASS_SCOPE)
2521                         put_variable((Variable *)n, outh);
2522         }
2523         out_printf(outh, "};\n\n");
2524
2525         out_printf(out, "/* here are local prototypes */\n");
2526         if(set_arguments > 0) {
2527                 out_printf(out, "static void ___object_set_arg "
2528                            "(GtkObject *object, GtkArg *arg, "
2529                            "guint arg_id);\n");
2530         }
2531         if(get_arguments > 0) {
2532                 out_printf(out, "static void ___object_get_arg "
2533                            "(GtkObject *object, GtkArg *arg, "
2534                            "guint arg_id);\n");
2535         }
2536
2537         out_printf(outh, "\n/*\n"
2538                    " * Public methods\n"
2539                    " */\n");
2540
2541         if ( ! overrode_get_type) {
2542                 out_printf(outh, "GtkType\t%s_get_type\t(void)", funcbase);
2543                 if ( ! no_gnu) {
2544                         out_printf(outh, " G_GNUC_CONST;\n");
2545                 } else {
2546                         out_printf(outh, ";\n");
2547                 }
2548         }
2549
2550         for(l = c->nodes; l != NULL; l = l->next) {
2551                 Node *n = l->data;
2552                 if(n->type == METHOD_NODE) {
2553                         put_pub_method((Method *)n);
2554                         put_prot_method((Method *)n);
2555                         put_priv_method_prot((Method *)n);
2556                 }
2557         }
2558
2559         /* this idea is less and less apealing to me */
2560         if (signals > 0) {
2561                 out_printf (outh, "\n/*\n"
2562                             " * Signal connection wrapper macros\n"
2563                             " */\n");
2564                 if( ! no_gnu) {
2565                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2566                         put_signal_macros (c, TRUE);
2567                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
2568                         put_signal_macros (c, FALSE);
2569                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
2570                 } else {
2571                         put_signal_macros (c, FALSE);
2572                 }
2573         }
2574
2575         /* argument wrapping macros */
2576         if(get_arguments > 0 || set_arguments > 0) {
2577                 out_printf(outh, "\n/*\n"
2578                            " * Argument wrapping macros\n"
2579                            " */\n");
2580                 if( ! no_gnu) {
2581                         out_printf(outh, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2582                         put_argument_gnu_wrappers(c);
2583                         out_printf(outh, "#else /* __GNUC__ && !__STRICT_ANSI__ */\n");
2584                         put_argument_nongnu_wrappers(c);
2585                         out_printf(outh, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n\n");
2586                 } else {
2587                         put_argument_nongnu_wrappers(c);
2588                 }
2589         }
2590
2591         if(signals > 0) {
2592                 for(l = c->nodes; l != NULL; l = l->next) {
2593                         Node *n = l->data;
2594                         if(n->type == METHOD_NODE)
2595                                 add_signal_prots((Method *)n);
2596                 }
2597         }
2598
2599         add_enums(c);
2600
2601         if ( ! overrode_get_type) {
2602                 if (c->bonobo_x_class != NULL)
2603                         add_bonobo_x_get_type ();
2604                 else
2605                         add_get_type ();
2606         }
2607
2608         if(any_method_to_alias(c)) {
2609                 if( ! no_gnu) {
2610                         out_printf(out, "/* Short form macros */\n");
2611                         out_printf(out, "#if defined(__GNUC__) && !defined(__STRICT_ANSI__)\n");
2612                         make_method_gnu_aliases(c);
2613                         out_printf(out, "#endif /* __GNUC__ && !__STRICT_ANSI__ */\n");
2614                 }
2615                 make_method_nongnu_aliases(c);
2616         }
2617
2618         out_printf(out, "/* a macro for creating a new object of our type */\n");
2619         out_printf(out,
2620                    "#define GET_NEW ((%s *)gtk_type_new(%s_get_type()))\n\n",
2621                    typebase, funcbase);
2622
2623         if(need_destroy)
2624                 add_destroy(c);
2625
2626         if(need_finalize)
2627                 add_finalize(c);
2628
2629         add_inits(c);
2630
2631         if(set_arguments > 0) {
2632                 add_getset_arg(c, TRUE);
2633         }
2634
2635         if(get_arguments > 0) {
2636                 add_getset_arg(c, FALSE);
2637         }
2638
2639         for(l = c->nodes; l != NULL; l = l->next) {
2640                 Node *n = l->data;
2641                 if(n->type == METHOD_NODE)
2642                         put_method((Method *)n);
2643         }
2644
2645         add_bad_hack_to_avoid_unused_warnings(c);
2646 }
2647
2648 static void
2649 print_version_macros(void)
2650 {
2651         int major=0, minor=0, pl=0;
2652         sscanf(VERSION, "%d.%d.%d", &major, &minor, &pl);
2653
2654         out_printf(out, "#define GOB_VERSION_MAJOR %d\n", major);
2655         out_printf(out, "#define GOB_VERSION_MINOR %d\n", minor);
2656         out_printf(out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
2657 }
2658
2659 static void
2660 print_file_comments(void)
2661 {
2662         time_t curtime;
2663         time(&curtime);
2664         out_printf(outh, "/* Generated by GOB (v%s)"
2665                    "   (do not edit directly) */\n\n", VERSION);
2666         if(outph)
2667                 out_printf(outph, "/* Generated by GOB (v%s)"
2668                            "   (do not edit directly) */\n\n", VERSION);
2669         out_printf(out, "/* Generated by GOB (v%s) on %s"
2670                    "   (do not edit directly) */\n\n",
2671                    VERSION, ctime(&curtime));
2672
2673         out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
2674 }
2675
2676 static void
2677 print_includes(void)
2678 {
2679         gboolean found_header;
2680         char *p;
2681
2682         /* We may need string.h for memset */
2683         if(destructors > 0 &&
2684            ! g_list_find_custom(include_files, "string.h", (GCompareFunc)strcmp)) {
2685                 out_printf(out, "#include <string.h> /* memset() */\n\n");
2686         }
2687
2688         p = g_strconcat(filebase, ".h", NULL);
2689         found_header = TRUE;
2690         if( ! g_list_find_custom(include_files, p, (GCompareFunc)strcmp)) {
2691                 out_printf(out, "#include \"%s.h\"\n\n", filebase);
2692                 found_header = FALSE;
2693         }
2694         g_free(p);
2695
2696         /* if we are creating a private header see if it was included */
2697         if(outph) {
2698                 p = g_strconcat(filebase, "-private.h", NULL);
2699                 if( ! g_list_find_custom(include_files, p,
2700                                          (GCompareFunc)strcmp)) {
2701                         out_printf(out, "#include \"%s-private.h\"\n\n",
2702                                    filebase);
2703                         if(found_header)
2704                                 error_printf(GOB_WARN, 0,
2705                                             "Implicit private header include "
2706                                             "added to top of\n"
2707                                             "\tsource file, while public "
2708                                             "header is at a custom location, "
2709                                             "you should\n"
2710                                             "\texplicitly include "
2711                                             "the private header below the "
2712                                             "public one.");
2713                 }
2714                 g_free(p);
2715         }
2716 }
2717
2718 static void
2719 print_header_prefixes(void)
2720 {
2721         char *p;
2722
2723         p = replace_sep(((Class *)class)->otype, '_');
2724         g_strup(p);
2725         out_printf(outh, "#ifndef __%s_H__\n#define __%s_H__\n\n", p, p);
2726         if(outph)
2727                 out_printf(outph, "#ifndef __%s_PRIVATE_H__\n"
2728                            "#define __%s_PRIVATE_H__\n\n"
2729                            "#include \"%s.h\"\n\n", p, p, filebase);
2730         g_free(p);
2731
2732         if( ! no_extern_c) {
2733                 out_printf(outh, "#ifdef __cplusplus\n"
2734                            "extern \"C\" {\n"
2735                            "#endif /* __cplusplus */\n\n");
2736                 if(outph)
2737                         out_printf(outph, "#ifdef __cplusplus\n"
2738                                    "extern \"C\" {\n"
2739                                    "#endif /* __cplusplus */\n\n");
2740         }
2741 }
2742
2743 static void
2744 print_header_postfixes(void)
2745 {
2746         if( ! no_extern_c)
2747                 out_printf(outh, "\n#ifdef __cplusplus\n"
2748                            "}\n"
2749                            "#endif /* __cplusplus */\n");
2750         out_printf(outh, "\n#endif\n");
2751         if(outph) {
2752                 if( ! no_extern_c)
2753                         out_printf(outph, "\n#ifdef __cplusplus\n"
2754                                    "}\n"
2755                                    "#endif /* __cplusplus */\n");
2756                 out_printf(outph, "\n#endif\n");
2757         }
2758 }
2759
2760 static void
2761 print_all_top(void)
2762 {
2763         GList *li;
2764
2765         /* print the AT_CCODE blocks */
2766         for(li = nodes; li != NULL; li = li->next) {
2767                 Node *node = li->data;
2768                 if(node->type == CCODE_NODE) {
2769                         CCode *cc = (CCode *)node;
2770                         if(cc->cctype == AT_CCODE)
2771                                 print_ccode_block((CCode *)node);
2772                 }
2773         }
2774 }
2775
2776 static void
2777 print_header_top(void)
2778 {
2779         GList *li;
2780
2781         /* mandatory include */
2782         out_printf(outh, "#include <gtk/gtk.h>\n\n");
2783
2784         /* print the HT_CCODE blocks */
2785         for(li=nodes;li;li=g_list_next(li)) {
2786                 Node *node = li->data;
2787                 if(node->type == CCODE_NODE) {
2788                         CCode *cc = (CCode *)node;
2789                         if(cc->cctype == HT_CCODE)
2790                                 print_ccode_block((CCode *)node);
2791                 }
2792         }
2793 }
2794
2795 static void
2796 generate_outfiles(void)
2797 {
2798         GList *li;
2799
2800         print_file_comments();
2801
2802         print_all_top();
2803
2804         print_header_top();
2805
2806         print_header_prefixes();
2807
2808         print_version_macros();
2809
2810         print_includes();
2811
2812         for(li=nodes;li;li=g_list_next(li)) {
2813                 Node *node = li->data;
2814                 if(node->type == CCODE_NODE) {
2815                         CCode *cc = (CCode *)node;
2816                         if(cc->cctype != HT_CCODE &&
2817                            cc->cctype != AT_CCODE)
2818                                 print_ccode_block((CCode *)node);
2819                 } else if(node->type == CLASS_NODE) {
2820                         print_class_block((Class *)node);
2821                 } else
2822                         g_assert_not_reached();
2823         }
2824
2825         print_header_postfixes();
2826 }
2827
2828 static void
2829 print_help(void)
2830 {
2831         fprintf(stderr, "Gob version %s\n\n", VERSION);
2832         fprintf(stderr, "gob [options] file.gob\n\n");
2833         fprintf(stderr, "Options:\n"
2834                 "\t--help,-h,-?            Display this help\n"
2835                 "\t--version               Display version\n"
2836                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
2837                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
2838                 "\t--for-cpp               Create C++ files\n"
2839                 "\t--no-extern-c           Never print extern \"C\" into the "
2840                                           "header\n"
2841                 "\t--no-gnu                Never use GNU extentions\n"
2842                 "\t--no-touch-headers      Don't touch headers unless they "
2843                                           "really changed\n"
2844                 "\t--always-private-header Always create a private header "
2845                                           "file,\n"
2846                 "\t                        even if it would be empty "
2847                                           "[default]\n"
2848                 "\t--ondemand-private-header Create private header only when "
2849                                           "needed\n"
2850                 "\t--no-private-header     Don't create a private header, "
2851                                           "put private\n"
2852                 "\t                        structure and protected "
2853                                           "prototypes inside c file\n"
2854                 "\t--always-private-struct Always create a private pointer "
2855                                           "in\n"
2856                 "\t                        the object structure\n"
2857                 "\t--m4                    Preprocess source with m4. "
2858                                           "Following args will\n"
2859                 "\t                        be passed to m4\n"
2860                 "\t--m4-dir                Print directory that will be "
2861                                           "searched for m4\n"
2862                 "\t                        files\n"
2863                 "\t--no-write,-n           Don't write output files, just "
2864                                           "check syntax\n"
2865                 "\t--no-lines              Don't print '#line' to output\n"
2866                 "\t--no-self-alias         Don't create self type and macro "
2867                                           "aliases\n"
2868                 "\t--no-kill-underscores   Don't remove the leading underscore "
2869                                           "from\n"
2870                 "\t                        short id names\n");
2871 }
2872
2873 static void
2874 parse_options(int argc, char *argv[])
2875 {
2876         int i;
2877         int got_file = FALSE;
2878         int no_opts = FALSE;
2879         int m4_opts = FALSE; /* if we are just passing on args to m4 */
2880
2881         filename = NULL;
2882
2883         for(i = 1 ; i < argc; i++) {
2884                 if(m4_opts) {
2885                         char *new_commandline;
2886                         g_assert(m4_commandline!=NULL);
2887
2888                         /* check whether this one looks like the filename */
2889                         if((!strcmp(argv[i],"-") || argv[i][0] != '-') 
2890                            && !got_file) {
2891                                 const gchar *m4_flags=use_m4_clean?"":M4_FLAGS;
2892                                 filename = argv[i];
2893                                 got_file = TRUE;
2894                                 
2895                                 /* insert flags before the filename */
2896                                 new_commandline=g_strconcat(m4_commandline,
2897                                                             " ",
2898                                                             m4_flags, 
2899                                                             " ",
2900                                                             argv[i],
2901                                                             NULL);
2902                         }
2903
2904                         /* just an ordinary option */
2905                         else                      
2906                           new_commandline=g_strconcat(m4_commandline,
2907                                                       " ",
2908                                                       argv[i],
2909                                                       NULL);
2910
2911                         /* free old commandline */
2912                         g_free(m4_commandline);
2913                         m4_commandline=new_commandline;
2914
2915                 } else if(no_opts ||
2916                    argv[i][0] != '-') {
2917                         /*must be a file*/
2918                         if(got_file) {
2919                                 fprintf(stderr, "Specify only one file!\n");
2920                                 print_help();
2921                                 exit(1);
2922                         }
2923                         filename = argv[i];
2924                         got_file = TRUE;
2925                 } else if(strcmp(argv[i], "--help")==0) {
2926                         print_help();
2927                         exit(0);
2928                 } else if(strcmp(argv[i], "--version")==0) {
2929                         fprintf(stderr, "Gob version %s\n", VERSION);
2930                         exit(0);
2931                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
2932                         exit_on_warn = TRUE;
2933                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
2934                         exit_on_warn = FALSE;
2935                 } else if(strcmp(argv[i], "--for-cpp")==0) {
2936                         for_cpp = TRUE;
2937                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
2938                         no_touch_headers = TRUE;
2939                 } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
2940                         private_header = PRIVATE_HEADER_ONDEMAND;
2941                 } else if(strcmp(argv[i], "--always-private-header")==0) {
2942                         private_header = PRIVATE_HEADER_ALWAYS;
2943                 } else if(strcmp(argv[i], "--no-private-header")==0) {
2944                         private_header = PRIVATE_HEADER_NEVER;
2945                 } else if(strcmp(argv[i], "--no-gnu")==0) {
2946                         no_gnu = TRUE;
2947                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
2948                         no_extern_c = TRUE;
2949                 } else if(strcmp(argv[i], "--no-write")==0) {
2950                         no_write = TRUE;
2951                 } else if(strcmp(argv[i], "--no-lines")==0) {
2952                         no_lines = TRUE;
2953                 } else if(strcmp(argv[i], "--no-self-alias")==0) {
2954                         no_self_alias = TRUE;
2955                 } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
2956                         no_kill_underscores = TRUE;
2957                 } else if(strcmp(argv[i], "--always-private-struct")==0) {
2958                         always_private_struct = TRUE;
2959                 } else if(strcmp(argv[i], "--m4-dir")==0) {
2960                         printf("%s\n",M4_INCLUDE_DIR);
2961                         exit(0);
2962                 } else if(strcmp(argv[i], "--m4")==0) {
2963                         use_m4 = TRUE;
2964                         use_m4_clean=FALSE;
2965                         m4_opts = TRUE;
2966                         m4_commandline=g_strdup(M4_COMMANDLINE);
2967                 } else if(strcmp(argv[i], "--m4-clean")==0) {
2968                         use_m4 = TRUE;
2969                         use_m4_clean=TRUE;
2970                         m4_opts = TRUE;
2971                         m4_commandline=g_strdup(M4_COMMANDLINE);
2972                 } else if(strcmp(argv[i], "--")==0) {
2973                         /*further arguments are files*/
2974                         no_opts = TRUE;
2975                 } else if(strncmp(argv[i], "--", 2)==0) {
2976                         /*unknown long option*/
2977                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
2978                         print_help();
2979                         exit(1);
2980                 } else {
2981                         /*by now we know we have a string starting with
2982                           - which is a short option string*/
2983                         char *p;
2984                         for(p = argv[i] + 1; *p; p++) {
2985                                 switch(*p) {
2986                                 case 'w':
2987                                         exit_on_warn=TRUE;
2988                                         break;
2989                                 case 'n':
2990                                         no_write = TRUE;
2991                                         break;
2992                                 case 'h':
2993                                 case '?':
2994                                         print_help();
2995                                         exit(0);
2996                                 default:
2997                                         fprintf(stderr,
2998                                                 "Unknown option '%c'!\n", *p);
2999                                         print_help();
3000                                         exit(1);
3001                                 }
3002                         }
3003                 }
3004         }
3005
3006 #if 0
3007         /* if we are using m4, and got no filename, append m4 flags now */
3008         if(!got_file && use_m4 && !use_m4_clean) {
3009                 char *new_commandline;
3010                 new_commandline=g_strconcat(m4_commandline,
3011                                             " ",
3012                                             M4_FLAGS,
3013                                             NULL);
3014                 g_free(m4_commandline);
3015                 m4_commandline=new_commandline;
3016         }
3017 #endif
3018 }
3019
3020 /* this is a somewhat ugly hack, but it appears to work */
3021 static void
3022 compare_and_move_header(void)
3023 {
3024         char *hfnew = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
3025         char *hf = g_strconcat(filebase, ".h", NULL);
3026         struct stat s;
3027         if(stat(hf, &s) == 0) {
3028                 char *s;
3029                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
3030                 if(system(s) == 0) {
3031                         if(unlink(hfnew) != 0)
3032                                 error_printf(GOB_ERROR, 0,
3033                                              "Can't remove new header file");
3034                         g_free(hfnew);
3035                         g_free(hf);
3036                         g_free(s);
3037                         return;
3038                 }
3039                 g_free(s);
3040                 if(unlink(hf) != 0)
3041                         error_printf(GOB_ERROR, 0,
3042                                      "Can't remove old header file");
3043         }
3044         if(rename(hfnew, hf) != 0)
3045                 error_printf(GOB_ERROR, 0,
3046                              "Can't rename new header file");
3047         g_free(hfnew);
3048         g_free(hf);
3049 }
3050
3051 int
3052 main(int argc, char *argv[])
3053 {
3054         parse_options(argc, argv);
3055         
3056         if(use_m4) {
3057                 yyin = popen(m4_commandline, "r");
3058                 if(!yyin) {
3059                         fprintf(stderr, "Error: can't open pipe from '%s'\n",
3060                                 m4_commandline);
3061                         exit(1);
3062                 }
3063         } else if(filename) {
3064                 yyin = fopen(filename, "r");
3065                 if(!yyin) {
3066                         fprintf(stderr, "Error: can't open file '%s'\n",
3067                                 filename);
3068                         exit(1);
3069                 }
3070         }
3071
3072         if(filename==NULL)
3073                 filename = "stdin";
3074
3075         /* This is where parsing is done */
3076         /*yydebug = 1;*/
3077         if(yyparse() != 0)
3078                 g_error("Parsing errors, quitting");
3079
3080         /* close input file */
3081         if(use_m4) pclose(yyin);
3082         else fclose(yyin);
3083         yyin=stdin;
3084
3085         if( ! class)
3086                 error_print(GOB_ERROR, 0, " no class defined");
3087         
3088
3089         exit_on_error = FALSE;
3090
3091         signals = count_signals((Class *)class);
3092         set_arguments = count_set_arguments((Class *)class);
3093         get_arguments = count_get_arguments((Class *)class);
3094         overrides = count_overrides((Class *)class);
3095         privates = count_privates((Class *)class);
3096         protecteds = count_protecteds((Class *)class);
3097         destructors = count_destructors((Class *)class);
3098         initializers = count_initializers((Class *)class);
3099         overrode_get_type = find_get_type((Class *)class);
3100
3101         make_bases();
3102         make_inits((Class *)class);
3103         if(destructors > 0) {
3104                 need_destroy = TRUE;
3105                 find_destroy((Class *)class);
3106         }
3107         if(privates > 0) {
3108                 need_finalize = TRUE;
3109                 find_finalize((Class *)class);
3110         }
3111         check_bad_symbols((Class *)class);
3112         check_duplicate_symbols((Class *)class);
3113         check_duplicate_overrides((Class *)class);
3114         check_duplicate_signals_args((Class *)class);
3115         check_public_new((Class *)class);
3116         check_vararg((Class *)class);
3117         check_firstarg((Class *)class);
3118         check_nonvoidempty((Class *)class);
3119         check_signal_args((Class *)class);
3120         check_argument_types((Class *)class);
3121         check_func_arg_checks((Class *)class);
3122
3123         exit_on_error = TRUE;
3124         
3125         if(got_error)
3126                 exit(1);
3127
3128         any_special = setup_special_array((Class *)class, special_array);
3129
3130         open_files();
3131         
3132         generate_outfiles();
3133
3134         if(devnull)
3135                 fclose(devnull);
3136         else {
3137                 fclose(out);
3138                 fclose(outh);
3139                 if(outph)
3140                         fclose(outph);
3141         }
3142
3143         if(no_touch_headers &&
3144            ! no_write)
3145                 compare_and_move_header();
3146         
3147         return 0;
3148 }