]> git.draconx.ca Git - gob-dx.git/blob - src/main.c
Release 0.92.4
[gob-dx.git] / src / main.c
1 /* GOB C Preprocessor
2  * Copyright (C) 1999 the Free Software Foundation.
3  *
4  * Author: George Lebl
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the  Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  * USA.
20  */
21
22 #include "config.h"
23 #include <glib.h>
24 #include <time.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <sys/stat.h>
30
31 #include "tree.h"
32 #include "parse.h"
33 #include "out.h"
34 #include "util.h"
35 #include "checks.h"
36
37 #include "main.h"
38
39 char *filename = NULL;
40
41 int yyparse(void);
42
43 extern int yydebug;
44 extern FILE * yyin;
45 extern Node *class;
46 extern GList *nodes;
47
48 extern GList *include_files;
49
50 extern GHashTable *gtk_doc_hash;
51
52 char *filebase;
53 static char *funcbase;
54 static char *pfuncbase;
55 static char *macrobase;
56 static char *macrois;
57 static char *macrotype;
58 static char *typebase;
59 static char *ptypebase;
60
61 static int signals = 0; /* number of signals */
62 static int arguments = 0; /* number of named arguments */
63 static int overrides = 0; /* number of override methods */
64 static int privates = 0; /* number of private data members */
65 static int protecteds = 0; /* number of protected methods */
66
67 static gboolean made_aliases = FALSE;  /* if we made any shorthand aliases
68                                           and need the REALLY UGLY HACK to
69                                           avoid warnings */
70
71 FILE *out = NULL;
72 FILE *outh = NULL;
73 FILE *outph = NULL;
74 FILE *devnull = NULL;
75
76 gboolean no_touch_headers = FALSE;
77 gboolean for_cpp = FALSE;
78 gboolean no_gnu = FALSE;
79 gboolean exit_on_warn = FALSE;
80 gboolean exit_on_error = TRUE;
81 gboolean got_error = FALSE;
82 gboolean always_private_header = FALSE;
83 gboolean no_private_header = FALSE;
84 gboolean no_extern_c = FALSE;
85 gboolean no_write = FALSE;
86
87 static void
88 make_bases(void)
89 {
90         filebase = replace_sep(((Class *)class)->otype, '-');
91         g_strdown(filebase);
92
93         funcbase = replace_sep(((Class *)class)->otype, '_');
94         g_strdown(funcbase);
95
96         pfuncbase = replace_sep(((Class *)class)->ptype, '_');
97         g_strdown(pfuncbase);
98
99         macrobase = replace_sep(((Class *)class)->otype, '_');
100         g_strup(macrobase);
101         
102         macrois = make_pre_macro(((Class *)class)->otype, "IS");
103         macrotype = make_pre_macro(((Class *)class)->otype, "TYPE");
104
105         typebase = remove_sep(((Class *)class)->otype);
106
107         ptypebase = remove_sep(((Class *)class)->ptype);
108 }
109
110 static char *
111 get_type(Type *t, gboolean postfix_to_stars)
112 {
113         char *s;
114         int i;
115         int extra;
116         GString *gs;
117
118         s = remove_sep(t->name);
119         gs = g_string_new(s);
120         g_free(s);
121
122
123         extra = 0;
124         if(postfix_to_stars) {
125                 char *p;
126                 /*XXX: this is ugly perhaps we can do this whole postfix thing
127                   in a nicer way, we just count the number of '[' s and from
128                   that we deduce the number of dimensions, so that we can print
129                   that many stars */
130                 for(p=t->postfix; p && *p; p++)
131                         if(*p == '[') extra++;
132         }
133         g_string_append_c(gs,' ');
134         
135         for(i=0; i<(t->stars+extra); i++)
136                 g_string_append_c(gs, '*');
137
138         s = gs->str;
139         g_string_free(gs, FALSE);
140         return s;
141 }
142
143 static char *
144 get_gtk_doc(char *id)
145 {
146         char *val, *s;
147
148         if(!gtk_doc_hash)
149                 return NULL;
150
151         val = g_hash_table_lookup(gtk_doc_hash, id);
152         if(val)
153                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
154                                        funcbase, id, val);
155         s = g_strconcat(funcbase, "_", id, NULL);
156         val = g_hash_table_lookup(gtk_doc_hash, s);
157         g_free(s);
158         if(val)
159                 return g_strdup_printf("/**\n * %s_%s:\n%s **/\n",
160                                        funcbase, id, val);
161         return NULL;
162 }
163
164 static void
165 print_type(FILE *fp, Type *t, gboolean postfix_to_stars)
166 {
167         char *s;
168
169         s = get_type(t, postfix_to_stars);
170         out_printf(fp, "%s", s); 
171         g_free(s);
172 }
173
174
175 static void
176 print_method(FILE *fp, char *typeprefix, char *nameprefix,
177              char *subnameprefix,
178              char *namepostfix, char *postfix, Method *m,
179              gboolean one_arg_per_line,
180              gboolean no_funcbase)
181 {
182         GList *li;
183
184         out_printf(fp, "%s", typeprefix); 
185         print_type(fp, m->mtype, TRUE);
186         if(no_funcbase)
187                 out_printf(fp, "%s%s%s%s(",
188                            nameprefix, subnameprefix, m->id, namepostfix); 
189         else
190                 out_printf(fp,"%s%s_%s%s%s(",
191                            nameprefix, funcbase, subnameprefix, m->id,
192                            namepostfix); 
193         
194         if(m->args) {
195                 for(li=m->args; li; li=g_list_next(li)) {
196                         FuncArg *arg = li->data;
197                         print_type(fp, arg->atype, FALSE);
198                         if(li->next)
199                                 out_printf(fp, "%s%s,%s", arg->name,
200                                            arg->atype->postfix?
201                                            arg->atype->postfix:"",
202                                            one_arg_per_line?"\n\t\t\t\t\t":" ");
203                         else
204                                 out_printf(fp, "%s%s", arg->name,
205                                            arg->atype->postfix?
206                                            arg->atype->postfix:""); 
207                 }
208                 if(m->vararg)
209                         out_printf(fp, ",%s...",
210                                    one_arg_per_line?"\n\t\t\t\t\t":" "); 
211         } else {
212                 out_printf(fp, "void"); 
213         }
214         out_printf(fp, ")%s", postfix); 
215 }
216
217
218 static void
219 make_method_gnu_aliases(Class *c)
220 {
221         GList *li;
222         
223         for(li=c->nodes;li;li=g_list_next(li)) {
224                 Node *node = li->data;
225                 if(node->type == METHOD_NODE) {
226                         Method *m = (Method *)node;
227                         
228                         if(m->method == INIT_METHOD ||
229                            m->method == CLASS_INIT_METHOD ||
230                            m->method == OVERRIDE_METHOD)
231                                 continue;
232
233                         /* in C++ mode don't alias new */
234                         if(for_cpp && strcmp(m->id, "new")==0)
235                                 continue;
236
237                         out_printf(out, "static const typeof(&%s_%s) %s "
238                                    "__attribute__ ((__unused__)) "
239                                    "= %s_%s;\n", funcbase, m->id, m->id,
240                                    funcbase, m->id);
241                         out_printf(out, "#define %s(args...) "
242                                    "%s_%s(##args)\n", m->id, funcbase, m->id);
243                 }
244         }
245 }
246
247 static void
248 make_method_nongnu_aliases(Class *c)
249 {
250         GList *li;
251         
252         for(li=c->nodes; li; li=g_list_next(li)) {
253                 Node *node = li->data;
254                 if(node->type == METHOD_NODE) {
255                         Method *m = (Method *)node;
256                         
257                         if(m->method == INIT_METHOD ||
258                            m->method == CLASS_INIT_METHOD ||
259                            m->method == OVERRIDE_METHOD)
260                                 continue;
261
262                         /* in C++ mode don't alias new */
263                         if(for_cpp && strcmp(m->id, "new")==0)
264                                 continue;
265
266                         print_method(out, "static ", "(* ", "", ") ", "",
267                                      m, FALSE, TRUE);
268                         out_printf(out, " = %s_%s;\n", funcbase, m->id);
269
270                         made_aliases = TRUE;
271                 }
272         }
273 }
274
275 static void
276 add_bad_hack_to_avoid_unused_warnings(Class *c)
277 {
278         GList *li;
279
280         /* if we haven't had any methods, just return */
281         if(!made_aliases)
282                 return;
283         
284         if(!no_gnu)
285                 out_printf(out,"\n\n#ifndef __GNUC__\n");
286         out_printf(out,
287                    "/*REALLY BAD HACK\n"
288                    "  This is to avoid unused warnings if you don't call\n"
289                    "  some method.  I need to find a better way to do\n"
290                    "  this, not needed in GCC since we use some gcc\n"
291                    "  extentions to make saner, faster code */\n"
292                    "static void\n"
293                    "___%s_really_bad_hack_to_avoid_warnings(void)\n"
294                    "{\n",funcbase);
295         for(li=c->nodes;li;li=g_list_next(li)) {
296                 Node *node = li->data;
297                 if(node->type == METHOD_NODE) {
298                         Method *m = (Method *)node;
299                         
300                         if(m->method == INIT_METHOD ||
301                            m->method == CLASS_INIT_METHOD ||
302                            m->method == OVERRIDE_METHOD)
303                                 continue;
304
305                         /* in C++ mode we don't alias new */
306                         if(for_cpp && strcmp(m->id,"new")==0)
307                                 continue;
308
309                         out_printf(out,"\t((void (*)(void))%s)();\n",m->id);
310                 }
311         }
312         out_printf(out, "\t___%s_really_bad_hack_to_avoid_warnings();\n",
313                    funcbase);
314         if(!no_gnu)
315                 out_printf(out,"}\n#endif /* __GNUC__ */\n\n");
316         else
317                 out_printf(out,"}\n\n");
318 }
319
320 static void
321 put_variable(Variable *v, FILE *fp)
322 {
323         out_printf(fp,"\t");
324         print_type(fp,v->vtype,FALSE);
325         out_printf(fp,"%s%s;",v->id,
326                    v->vtype->postfix?
327                    v->vtype->postfix:""); 
328         if(v->scope == PROTECTED_SCOPE)
329                 out_printf(fp," /* protected */");
330         out_printf(fp,"\n");
331 }
332
333 static void
334 put_vs_method(Method *m)
335 {
336         if(m->method != SIGNAL_LAST_METHOD &&
337            m->method != SIGNAL_FIRST_METHOD &&
338            m->method != VIRTUAL_METHOD)
339                 return;
340
341         /* if a signal mark it as such */
342         if(m->method != VIRTUAL_METHOD)
343                 print_method(outh,"\t/*signal*/","(* ","",") ",";\n",m,
344                              FALSE,TRUE);
345         else
346                 print_method(outh,"\t","(* ","",") ",";\n",m,FALSE,TRUE);
347 }
348
349 static void
350 put_pub_method(Method *m)
351 {
352         if(m->scope != PUBLIC_SCOPE)
353                 return;
354
355         print_method(outh,"","\t","","\t",";\n",m,TRUE,FALSE);
356 }
357
358 /* I'm starting not to like this idea */
359 #if 0
360 static void
361 put_signal_connect(Method *m)
362 {
363         if(m->method != SIGNAL_LAST_METHOD &&
364            m->method != SIGNAL_FIRST_METHOD)
365                 return;
366
367         out_printf(outh, "guint \t%s_%s__connect_full\t(%s *object,\n"
368                    "\t\t\t\t\tconst char *name,\n"
369                    "\t\t\t\t\tGtkSignalFunc func,\n"
370                    "\t\t\t\t\tGtkCallbackMarshal marshal,\n"
371                    "\t\t\t\t\tgpointer data,\n"
372                    "\t\t\t\t\tGtkDestroyNotify destroy_func,\n"
373                    "\t\t\t\t\tgboolean object_signal,\n"
374                    "\t\t\t\t\tgboolean after);\n",
375                    funcbase, m->id, typebase);
376
377         out_printf(outh, "#define %s_%s__connect(object,name,func,data) "
378                    "%s_%s__connect_full((object),(name),(func),NULL,"
379                    "(data),NULL,FALSE,FALSE)\n",
380                    funcbase, m->id, funcbase, m->id);
381         out_printf(outh, "#define %s_%s__connect_after(object,name,func,data) "
382                    "%s__connect_%s_full((object),(name),(func),NULL,"
383                    "(data),NULL,FALSE,TRUE)\n",
384                    funcbase, m->id, funcbase, m->id);
385
386         out_printf(outh, "guint \t%s_%s__connect_while_alive\t(%s *object,\n"
387                    "\t\t\t\t\tconst char *name,\n"
388                    "\t\t\t\t\tGtkSignalFunc func,\n"
389                    "\t\t\t\t\tgpointer data,\n"
390                    "\t\t\t\t\tGtkObject *alive_object);\n\n",
391                    funcbase, m->id, typebase);
392 }
393 #endif
394
395
396 static void
397 put_prot_method(Method *m)
398 {
399         if(m->scope != PROTECTED_SCOPE)
400                 return;
401
402         if(outph)
403                 print_method(outph,"","\t","","\t",";\n",m,FALSE,FALSE);
404         else
405                 print_method(out,"","\t","","\t",";\n",m,FALSE,FALSE);
406 }
407
408 static void
409 put_priv_method_prot(Method *m)
410 {
411         if(m->method == SIGNAL_LAST_METHOD ||
412            m->method == SIGNAL_FIRST_METHOD ||
413            m->method == VIRTUAL_METHOD) {
414                 if(m->cbuf)
415                         print_method(out,
416                                      "static ", "___real_", "", " ", ";\n",
417                                      m, FALSE, FALSE);
418         }
419
420         if(m->scope == PRIVATE_SCOPE ||
421            m->method == INIT_METHOD ||
422            m->method == CLASS_INIT_METHOD ||
423            (m->method == OVERRIDE_METHOD &&
424             m->cbuf))
425                 print_method(out, "static ", "", "", " ",
426                              no_gnu?";\n":" G_GNUC_UNUSED;\n",
427                              m, FALSE, FALSE);
428 }
429
430 static GList *
431 make_func_arg(char *typename, int is_class, char *name)
432 {
433         Node *node;
434         Node *type;
435         char *tn;
436         
437         if(is_class)
438                 tn = g_strconcat(typename,":Class",NULL);
439         else
440                 tn = g_strdup(typename);
441
442         type = new_type(1,tn,NULL);
443         node = new_funcarg((Type *)type,name,NULL);
444         return g_list_prepend(NULL, node);
445 }
446
447 static void
448 make_inits(Class *cl)
449 {
450         int got_class_init = FALSE;
451         int got_init = FALSE;
452         GList *li;
453         Node *node;
454         for(li=cl->nodes;li;li=g_list_next(li)) {
455                 Node *n = li->data;
456                 if(n->type == METHOD_NODE) {
457                         Method *m = (Method *)n;
458                         if(m->method == INIT_METHOD) {
459                                 if(got_init)
460                                         print_error(FALSE,"init defined more then once",m->line_no);
461                                 got_init = TRUE;
462                         } else if(m->method == CLASS_INIT_METHOD) {
463                                 if(got_class_init)
464                                         print_error(FALSE,"class_init defined more then once",m->line_no);
465                                 got_class_init = TRUE;
466                         }
467                 }
468         }
469         if(!got_class_init) {
470                 node = new_method(NO_SCOPE, CLASS_INIT_METHOD,
471                                   (Type *)new_type(0, g_strdup("void"),NULL),
472                                   NULL, NULL, NULL, g_strdup("class_init"),
473                                   make_func_arg(cl->otype, TRUE, g_strdup("c")),
474                                   NULL, NULL, 0, 0, FALSE);
475                 cl->nodes = g_list_prepend(cl->nodes,node);
476         }
477         if(!got_init) {
478                 node = new_method(NO_SCOPE, INIT_METHOD,
479                                   (Type *)new_type(0, g_strdup("void"),NULL),
480                                   NULL, NULL, NULL, g_strdup("init"),
481                                   make_func_arg(cl->otype, FALSE, g_strdup("o")),
482                                   NULL, NULL, 0, 0, FALSE);
483                 cl->nodes = g_list_prepend(cl->nodes,node);
484         }
485 }
486
487 static void
488 make_finalize(Class *cl)
489 {
490         int got_finalize = FALSE;
491         GList *li;
492         Node *node;
493         for(li=cl->nodes;li;li=g_list_next(li)) {
494                 Node *n = li->data;
495                 if(n->type == METHOD_NODE) {
496                         Method *m = (Method *)n;
497                         if(m->method == OVERRIDE_METHOD &&
498                            strcmp(m->id, "finalize")==0) {
499                                 if(strcmp(m->otype, "Gtk:Object")==0) {
500                                         got_finalize = TRUE;
501                                         break;
502                                 }
503                                 print_error(FALSE,"finalize method override "
504                                             "of class other then Gtk:Object",
505                                             m->line_no);
506                         }
507                 }
508         }
509         if(!got_finalize) {
510                 node = new_method(NO_SCOPE, OVERRIDE_METHOD,
511                                   (Type *)new_type(0,g_strdup("void"),NULL),
512                                   g_strdup("Gtk:Object"),
513                                   NULL, NULL, g_strdup("finalize"),
514                                   make_func_arg("Gtk:Object",FALSE,g_strdup("o")),
515                                   NULL,
516                                   g_strdup("PARENT_HANDLER (o);\n"),
517                                   0,0,FALSE);
518                 cl->nodes = g_list_append(cl->nodes,node);
519                 overrides++;
520         }
521 }
522
523
524 /* hash of method -> name of signal prototype */
525 static GHashTable *marsh = NULL;
526
527 /* list of methods with different signal prototypes,
528    we check this list if we can use a signal prototype of a
529    previous signal method, there are only uniques here */
530 static GList *eq_signal_methods = NULL;
531
532 /* compare a list of strings */
533 static gboolean
534 is_list_equal(GList *a, GList *b)
535 {
536         for(;a && b; a=a->next, b=b->next) {
537                 if(strcmp(a->data,b->data)!=0) {
538                         return FALSE;
539                 }
540         }
541         /* the the lists were different length */
542         if(a || b)
543                 return FALSE;
544         return TRUE;
545 }
546
547 static Method *
548 find_same_type_signal(Method *m)
549 {
550         GList *li;
551         for(li=eq_signal_methods;li;li=li->next) {
552                 Method *mm = li->data;
553                 if(is_list_equal(mm->gtktypes,m->gtktypes))
554                         return mm;
555         }
556         return NULL;
557 }
558
559 static void
560 print_signal_marsal_args(Method *m)
561 {
562         if(strcmp(m->gtktypes->next->data,"NONE")!=0) {
563                 GList *li;
564                 int i;
565                 for(i=0,li=m->gtktypes->next;li;
566                     i++,li=g_list_next(li)) {
567                         if(!for_cpp)
568                                 out_printf(out, ",\n\t\tGTK_VALUE_%s(args[%d])",
569                                            (char *)li->data,i);
570                         else {
571                                 out_printf(out, ",\n\t\t(%s)"
572                                            "GTK_VALUE_%s(args[%d])",
573                                            get_cast(li->data,FALSE),
574                                            (char *)li->data,i);
575                         }
576                 }
577         }
578         out_printf(out, ",\n\t\tfunc_data);\n}\n\n");
579 }
580
581
582 static void
583 add_signal_prots(Method *m)
584 {
585         GList *li;
586         static int sig = 1;
587         char *s;
588         Method *mm;
589         
590         if(m->method != SIGNAL_LAST_METHOD &&
591            m->method != SIGNAL_FIRST_METHOD)
592                 return;
593
594         if(!marsh)
595                 marsh = g_hash_table_new(NULL,NULL);
596         
597         if(strcmp(m->gtktypes->data,"NONE")==0 &&
598            strcmp(m->gtktypes->next->data,"NONE")==0)
599                 return;
600
601         /* if we already did a signal prototype just use that */
602         mm = find_same_type_signal(m);
603         if(mm) {
604                 s = g_hash_table_lookup(marsh,mm);
605                 g_hash_table_insert(marsh,m,s);
606                 return;
607         }
608         
609         s = g_strdup_printf("Sig%d",sig++);
610         
611         g_hash_table_insert(marsh,m,s);
612         eq_signal_methods = g_list_prepend(eq_signal_methods,m);
613         
614         /* we know that we'll know all the gtktypes (so get_cast can't fail) */
615         out_printf(out,"\ntypedef %s (*___%s) (%s *, ",
616                    get_cast(m->gtktypes->data,FALSE),s, typebase);
617         
618         for(li=m->gtktypes->next;li;li=g_list_next(li))
619                 out_printf(out,"%s, ",get_cast(li->data,FALSE));
620         out_printf(out,"gpointer);\n"); 
621         
622         out_printf(out,"\nstatic void\n"
623                 "___marshal_%s (GtkObject * object,\n"
624                 "\tGtkSignalFunc func,\n"
625                 "\tgpointer func_data,\n"
626                 "\tGtkArg * args)\n"
627                 "{\n",s);
628         
629         if(strcmp(m->gtktypes->data,"NONE")==0) {
630                 out_printf(out, "\t___%s rfunc;\n\n"
631                         "\trfunc = (___%s)func;\n\n"
632                         "\t(*rfunc)((%s *)object",s,s,typebase);
633         } else {
634                 out_printf(out, "\t___%s rfunc;\n\t",s);
635                 print_type(out,m->mtype,TRUE);
636                 out_printf(out, " *retval;\n\n"
637                         "\trfunc = (___%s)func;\n\n"
638                         "\tretval = GTK_RETLOC_%s(args[%d]);\n\n"
639                         "\t*retval = (*rfunc)((%s *)object",
640                         s,(char *)m->gtktypes->data,
641                         g_list_length(m->gtktypes)-1,typebase);
642         }
643         print_signal_marsal_args(m);
644
645 }
646
647 static void
648 add_enums(Class *c)
649 {
650         GList *li;
651         out_printf(out,"\n");
652         if(signals>0) {
653                 out_printf(out,"enum {\n");
654                 for(li=c->nodes;li;li=g_list_next(li)) {
655                         Node *n = li->data;
656                         if(n->type == METHOD_NODE) {
657                                 Method *m = (Method *)n;
658                                 if(m->method == SIGNAL_LAST_METHOD ||
659                                    m->method == SIGNAL_FIRST_METHOD) {
660                                         char *s = g_strdup(m->id);
661                                         g_strup(s);
662                                         out_printf(out,"\t%s_SIGNAL,\n",s);
663                                         g_free(s);
664                                 }
665                         }
666                 }
667                 out_printf(out,"\tLAST_SIGNAL\n};\n\n");
668         }
669         if(arguments>0) {
670                 out_printf(out,"enum {\n\tARG_0");
671                 for(li=c->nodes;li;li=g_list_next(li)) {
672                         Node *n = li->data;
673                         if(n->type == ARGUMENT_NODE) {
674                                 Argument *a = (Argument *)n;
675                                 char *s = g_strdup(a->name);
676                                 g_strup(s);
677                                 out_printf(out,",\n\tARG_%s",s);
678                                 g_free(s);
679                         }
680                 }
681                 out_printf(out, "\n};\n\n");
682         }
683
684         if(signals>0)
685                 out_printf(out,
686                            "static guint object_signals[LAST_SIGNAL] = {0};\n\n");
687
688         out_printf(out, "static %sClass *parent_class = NULL;\n\n",ptypebase);
689 }
690
691 static void
692 add_get_type(void)
693 {
694         out_printf(out, "guint\n"
695                 "%s_get_type (void)\n"
696                 "{\n"
697                 "\tstatic guint type = 0;\n\n"
698                 "\tif (!type) {\n"
699                 "\t\tstatic const GtkTypeInfo info = {\n"
700                 "\t\t\t\"%s\",\n"
701                 "\t\t\tsizeof (%s),\n"
702                 "\t\t\tsizeof (%sClass),\n"
703                 "\t\t\t(GtkClassInitFunc) %s_class_init,\n"
704                 "\t\t\t(GtkObjectInitFunc) %s_init,\n"
705                 "\t\t\t/* reserved_1 */ NULL,\n"
706                 "\t\t\t/* reserved_2 */ NULL,\n"
707                 "\t\t\t(GtkClassInitFunc) NULL,\n"
708                 "\t\t};\n\n"
709                 "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n"
710                 "\t}\n\n"
711                 "\treturn type;\n"
712                 "}\n\n",
713                 funcbase,typebase,typebase,typebase,
714                 funcbase,funcbase,pfuncbase);
715 }
716
717 static void
718 add_overrides(Class *c, char *oname, gboolean did_gtk_obj)
719 {
720         GList *li;
721         GHashTable *done;
722         char *s;
723         
724         done = g_hash_table_new(g_str_hash, g_str_equal);
725         if(did_gtk_obj) {
726                 s = g_strdup("GtkObject"); /* This was already done */
727                 g_hash_table_insert(done, s, s);
728         }
729         for(li=c->nodes; li; li=g_list_next(li)) {
730                 Node *n = li->data;
731                 char *f;
732                 Method *m = (Method *)n;
733                 if(n->type != METHOD_NODE ||
734                    m->method != OVERRIDE_METHOD)
735                         continue;
736                 
737                 s = remove_sep(m->otype);
738                 
739                 if(g_hash_table_lookup(done,s)) {
740                         g_free(s);
741                         continue;
742                 }
743                 g_hash_table_insert(done,s,s);
744
745                 f = replace_sep(m->otype,'_');
746                 g_strdown(f);
747
748                 out_printf(out,"\t%sClass *%s_class = (%sClass *)%s;\n",
749                         s,f,s,oname);
750                 
751                 g_free(f);
752         }
753         g_hash_table_foreach(done,(GHFunc)g_free,NULL);
754         g_hash_table_destroy(done);
755 }
756
757 static char *
758 make_run_signal_flags(Method *m, gboolean last)
759 {
760         GList *li;
761         GString *gs;
762         char *flags[] = {
763                 "FIRST",
764                 "LAST",
765                 "BOTH",
766                 "NO_RECURSE",
767                 "ACTION",
768                 "NO_HOOKS",
769                 NULL
770         };
771
772         gs = g_string_new(NULL);
773
774         if(last)
775                 g_string_assign(gs, "GTK_RUN_LAST");
776         else
777                 g_string_assign(gs, "GTK_RUN_FIRST");
778
779         if(m->scope == PUBLIC_SCOPE)
780                 g_string_append(gs, " | GTK_RUN_ACTION");
781
782         for(li = m->flags; li; li = li->next) {
783                 char *flag = li->data;
784                 int i;
785                 for(i=0;flags[i];i++) {
786                         if(strcmp(flags[i],flag)==0)
787                                 break;
788                 }
789                 /* if we haven't found it in our list */
790                 if(!flags[i]) {
791                         char *s;
792                         s = g_strdup_printf("Unknown flag '%s' used, "
793                                             "perhaps it was misspelled",
794                                             flag);
795                         print_error(TRUE, s, m->line_no);
796                         g_free(s);
797                 }
798                 g_string_sprintfa(gs, " | GTK_RUN_%s",flag);
799         }
800
801         {
802                 char *ret = gs->str;
803                 g_string_free(gs, FALSE);
804                 return ret;
805         }
806 }
807                 
808
809 static void
810 add_signals(Class *c)
811 {
812         GList *li;
813
814         out_printf(out,"\n");
815         for(li=c->nodes;li;li=g_list_next(li)) {
816                 Node *n = li->data;
817                 char *mar, *sig, *flags;
818                 gboolean is_none, last = FALSE;
819                 Method *m = (Method *)n;
820
821                 if(n->type != METHOD_NODE ||
822                    (m->method != SIGNAL_FIRST_METHOD &&
823                     m->method != SIGNAL_LAST_METHOD))
824                         continue;
825
826                 if(m->method == SIGNAL_FIRST_METHOD)
827                         last = FALSE;
828                 else
829                         last = TRUE;
830
831                 if(g_hash_table_lookup(marsh, m))
832                         mar = g_strconcat("___marshal_",
833                                           (char *)g_hash_table_lookup(marsh,m),
834                                           NULL);
835                 else
836                         mar = g_strdup("gtk_signal_default_marshaller");
837                 
838                 is_none = (strcmp(m->gtktypes->next->data, "NONE")==0);
839                 
840                 sig = g_strdup(m->id);
841                 g_strup(sig);
842                 flags = make_run_signal_flags(m, last);
843                 out_printf(out,"\tobject_signals[%s_SIGNAL] =\n"
844                         "\t\tgtk_signal_new (\"%s\",\n"
845                         "\t\t\%s,\n"
846                         "\t\t\tgtk_object_class->type,\n"
847                         "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n"
848                         "\t\t\t%s,\n"
849                         "\t\t\tGTK_TYPE_%s, %d",
850                         sig,m->id,
851                         flags,
852                         typebase,m->id,mar,(char *)m->gtktypes->data,
853                         is_none?0:g_list_length(m->gtktypes->next));
854                 g_free(mar);
855                 g_free(sig);
856                 g_free(flags);
857                 
858                 if(!is_none) {
859                         GList *l;
860                         for(l=m->gtktypes->next;l;l=g_list_next(l))
861                                 out_printf(out,",\n\t\t\tGTK_TYPE_%s",
862                                         (char *)l->data);
863                 }
864
865                 out_printf(out,");\n");
866         }
867         out_printf(out,"\tgtk_object_class_add_signals (gtk_object_class,\n"
868                 "\t\tobject_signals, LAST_SIGNAL);\n\n");
869 }
870
871 static void
872 set_def_handlers(Class *c, char *oname)
873 {
874         GList *li;
875
876         out_printf(out,"\n");
877         for(li=c->nodes;li;li=g_list_next(li)) {
878                 Node *n = li->data;
879                 Method *m = (Method *)n;
880                 if(n->type != METHOD_NODE ||
881                    (m->method != SIGNAL_FIRST_METHOD &&
882                     m->method != SIGNAL_LAST_METHOD &&
883                     m->method != VIRTUAL_METHOD &&
884                     m->method != OVERRIDE_METHOD))
885                         continue;
886
887
888                 if(m->method == OVERRIDE_METHOD) {
889                         char *s;
890                         s = replace_sep(m->otype,'_');
891                         g_strdown(s);
892                         if(m->cbuf)
893                                 out_printf(out,"\t%s_class->%s = %s_%s;\n",
894                                            s,m->id,funcbase,m->id);
895                         else
896                                 out_printf(out,"\t%s_class->%s = NULL;\n",
897                                            s,m->id);
898                 } else {
899                         if(m->cbuf)
900                                 out_printf(out,"\t%s->%s = ___real_%s_%s;\n",
901                                         oname,m->id,funcbase,m->id);
902                         else
903                                 out_printf(out,"\t%s->%s = NULL;\n",
904                                         oname,m->id);
905                 }
906         }
907 }
908
909 static void
910 make_arguments(Class *c)
911 {
912         GList *li;
913         char *argflags[] = {
914                 "CONSTRUCT",
915                 "CONSTRUCT_ONLY",
916                 "CHILD_ARG",
917                 "MASK",
918                 NULL
919         };
920
921         out_printf(out,"\n");
922         for(li=c->nodes;li;li=g_list_next(li)) {
923                 Node *n = li->data;
924                 Argument *a;
925                 GString *flags;
926                 GList *l;
927                 char *s;
928                 if(n->type != ARGUMENT_NODE)
929                         continue;
930
931                 a = (Argument *)n;
932                 
933                 if(a->get && a->set)
934                         flags = g_string_new("GTK_ARG_READWRITE");
935                 else if(a->get)
936                         flags = g_string_new("GTK_ARG_READABLE");
937                 else
938                         flags = g_string_new("GTK_ARG_WRITABLE");
939                 
940                 for(l=a->flags;l;l=g_list_next(l)) {
941                         char *flag = l->data;
942                         int i;
943                         if(strcmp(flag,"READWRITE")==0 ||
944                            strcmp(flag,"READABLE")==0 ||
945                            strcmp(flag,"WRITABLE")==0) {
946                                 print_error(TRUE,"READWRITE, READABLE and "
947                                             "WRITABLE argument flags are "
948                                             "set automatically",a->line_no);
949                                 continue;
950                         }
951                         for(i=0;argflags[i];i++) {
952                                 if(strcmp(argflags[i],flag)==0)
953                                         break;
954                         }
955                         /* if we haven't found it in our list */
956                         if(!argflags[i]) {
957                                 char *s;
958                                 s = g_strdup_printf("Unknown flag '%s' used, "
959                                                     "perhaps it was misspelled",
960                                                     flag);
961                                 print_error(TRUE,s,a->line_no);
962                                 g_free(s);
963                         }
964                         g_string_sprintfa(flags, " | GTK_ARG_%s",flag);
965                 }
966
967                 s = g_strdup(a->name);
968                 g_strup(s);
969                 out_printf(out,"\tgtk_object_add_arg_type(\"%s::%s\",\n"
970                         "\t\tGTK_TYPE_%s,\n"
971                         "\t\t%s,\n"
972                         "\t\tARG_%s);\n",
973                         typebase,a->name,a->gtktype,flags->str,s);
974                 g_free(s);
975                 g_string_free(flags,TRUE);
976         }
977         
978         out_printf(out,
979                    "\n\tgtk_object_class->set_arg = ___object_set_arg;\n"
980                    "\tgtk_object_class->get_arg = ___object_get_arg;\n");
981 }
982
983 static void
984 add_inits(Class *c)
985 {
986         GList *li;
987         for(li=c->nodes;li;li=g_list_next(li)) {
988                 Node *n = li->data;
989                 Method *m;
990                 if(n->type != METHOD_NODE)
991                         continue;
992                 m = (Method *)n;
993                 if(m->method == INIT_METHOD) {
994                         if(m->line_no>0)
995                                 out_addline_infile(out,m->line_no);
996                         print_method(out, "static ", "\n", "", " ", "\n",
997                                      m, FALSE, FALSE);
998                         if(m->line_no>0)
999                                 out_addline_outfile(out);
1000                         out_printf(out,"{\n");
1001                         if(privates>0) {
1002                                 out_printf(out,"\t%s->_priv = "
1003                                            "g_new0 (%sPrivate,1);\n",
1004                                            ((FuncArg *)m->args->data)->name,
1005                                            typebase);
1006                         }
1007                 } else if(m->method == CLASS_INIT_METHOD) {
1008                         if(m->line_no>0)
1009                                 out_addline_infile(out, m->line_no);
1010                         print_method(out, "static ", "\n", "", " ", "\n",
1011                                      m, FALSE, FALSE);
1012                         if(m->line_no>0)
1013                                 out_addline_outfile(out);
1014                         out_printf(out,"{\n");
1015                         if(signals>0 ||
1016                            arguments>0)
1017                                 out_printf(out,
1018                                            "\tGtkObjectClass *"
1019                                            "gtk_object_class = "
1020                                            "(GtkObjectClass*) %s;\n",
1021                                            ((FuncArg *)m->args->data)->name);
1022
1023                         if(overrides>0)
1024                                 add_overrides(c,
1025                                               ((FuncArg *)m->args->data)->name,
1026                                               (signals>0 || arguments>0));
1027                         
1028                         out_printf(out,"\n\tparent_class = ");
1029                         if(for_cpp)
1030                                 out_printf(out,"(%sClass *)",ptypebase);
1031                         out_printf(out,"gtk_type_class (%s_get_type ());\n",
1032                                    pfuncbase);
1033
1034                         if(signals>0)
1035                                 add_signals(c);
1036
1037                         set_def_handlers(c, ((FuncArg *)m->args->data)->name);
1038                         
1039                         if(arguments>0)
1040                                 make_arguments(c);
1041
1042                 } else
1043                         continue;
1044
1045                 if(m->cbuf) {
1046                         out_printf(out," {\n");
1047                         out_addline_infile(out,m->ccode_line);
1048                         out_printf(out,"%s\n",m->cbuf);
1049                         out_addline_outfile(out);
1050                         out_printf(out," }\n");
1051                 } else {
1052                         out_printf(out,"return;\n");
1053                 }
1054                 out_printf(out,"}\n");
1055         }
1056 }
1057
1058 static void
1059 add_getset_arg(Class *c, int is_set)
1060 {
1061         GList *li;
1062         out_printf(out,"\nstatic void\n"
1063                 "___object_%s_arg (GtkObject *object,\n"
1064                 "\tGtkArg *arg,\n"
1065                 "\tguint arg_id)\n"
1066                 "{\n"
1067                 "\t%s *self;\n\n"
1068                 "\tself = %s (object);\n\n"
1069                 "\tswitch (arg_id) {\n",
1070                 is_set?"set":"get",typebase,macrobase);
1071
1072         for(li=c->nodes;li;li=g_list_next(li)) {
1073                 Node *n = li->data;
1074                 Argument *a;
1075                 char *s;
1076                 char *cbuf;
1077                 int line_no;
1078                 if(n->type != ARGUMENT_NODE)
1079                         continue;
1080                 a = (Argument *)n;
1081                 if(is_set) {
1082                         cbuf = a->set;
1083                         line_no = a->set_line;
1084                 } else {
1085                         cbuf = a->get;
1086                         line_no = a->get_line;
1087                 }
1088                 if(!cbuf)
1089                         continue;
1090                 s = g_strdup(a->name);
1091                 g_strup(s);
1092                 out_printf(out,"\tcase ARG_%s:\n"
1093                         "#define ARG (GTK_VALUE_%s(*arg))\n"
1094                         "\t\t{\n",
1095                         s,a->gtktype);
1096                 g_free(s);
1097                 out_addline_infile(out,line_no);
1098                 out_printf(out,"%s\n",cbuf);
1099                 out_addline_outfile(out);
1100                 out_printf(out,"\t\t}\n\t\tbreak;\n"
1101                         "#undef ARG\n");
1102         }
1103         out_printf(out,"\tdefault:\n\t\tbreak;\n\t}\n}\n");
1104 }
1105
1106 static void
1107 print_checks(Method *m, FuncArg *fa)
1108 {
1109         GList *li;
1110         gboolean is_void;
1111         gboolean checked_null = FALSE;
1112         is_void = (strcmp(m->mtype->name,"void")==0 &&
1113                    m->mtype->stars == 0);
1114         
1115         for(li=fa->checks;li;li=g_list_next(li)) {
1116                 Check *ch = li->data;
1117                 char *s;
1118                 /* point to the method prot in .gob for failed checks */
1119                 if(m->line_no>0)
1120                         out_addline_infile(out,m->line_no);
1121                 if(is_void)
1122                         out_printf(out,"\tg_return_if_fail (");
1123                 else
1124                         out_printf(out,"\tg_return_val_if_fail (");
1125                 switch(ch->chtype) {
1126                 case NULL_CHECK:
1127                         out_printf(out,"%s != NULL",fa->name);
1128                         checked_null = TRUE;
1129                         break;
1130                 case TYPE_CHECK:
1131                         s = make_pre_macro(fa->atype->name,"IS");
1132                         if(checked_null)
1133                                 out_printf(out,"%s (%s)",s,fa->name);
1134                         else
1135                                 /* if not check null, null may be valid */
1136                                 out_printf(out,"!(%s) || %s (%s)",fa->name,s,
1137                                            fa->name);
1138                         g_free(s);
1139                         break;
1140                 case LT_CHECK:
1141                         out_printf(out,"%s < %s",fa->name,ch->number);
1142                         break;
1143                 case GT_CHECK:
1144                         out_printf(out,"%s > %s",fa->name,ch->number);
1145                         break;
1146                 case LE_CHECK:
1147                         out_printf(out,"%s <= %s",fa->name,ch->number);
1148                         break;
1149                 case GE_CHECK:
1150                         out_printf(out,"%s >= %s",fa->name,ch->number);
1151                         break;
1152                 case EQ_CHECK:
1153                         out_printf(out,"%s == %s",fa->name,ch->number);
1154                         break;
1155                 case NE_CHECK:
1156                         out_printf(out,"%s != %s",fa->name,ch->number);
1157                         break;
1158                 }
1159                 if(is_void)
1160                         out_printf(out,");\n");
1161                 else {
1162                         out_printf(out,", (");
1163                         print_type(out,m->mtype,TRUE);
1164                         out_printf(out,")%s);\n",
1165                                 m->onerror?m->onerror:"0");
1166                 }
1167         }
1168 }
1169
1170 static void
1171 print_preconditions(Method *m)
1172 {
1173         GList *li;
1174         
1175         for(li=m->args;li;li=g_list_next(li)) {
1176                 FuncArg *fa = li->data;
1177                 if(fa->checks)
1178                         print_checks(m,fa);
1179         }
1180         if(m->line_no>0)
1181                 out_addline_outfile(out);
1182 }
1183
1184 /* put in code if it's needed */
1185 static void
1186 put_in_gen_code(Method *m)
1187 {
1188         /* now we only have the freeing of the private structure */
1189         if(privates>0 &&
1190            m->method == OVERRIDE_METHOD &&
1191            strcmp(m->id,"finalize")==0) {
1192                 out_printf(out,"\tg_free (%s (%s)->_priv);\n"
1193                            "\t%s (%s)->_priv = NULL;\n",
1194                            macrobase,
1195                            ((FuncArg *)m->args->data)->name,
1196                            macrobase,
1197                            ((FuncArg *)m->args->data)->name);
1198         }
1199 }
1200
1201 static void
1202 print_method_body(Method *m, int pre)
1203 {
1204         out_printf(out,"{\n");
1205         if(pre)
1206                 print_preconditions(m);
1207
1208         put_in_gen_code(m);
1209
1210         /* Note: the trailing }'s are on one line, this is so
1211            that we get the no return warning correctly and point to
1212            the correct line in the .gob file, yes this is slightly
1213            ugly in the .c file, but that is not supposed to be
1214            human readable anyway. */
1215         if(m->cbuf) {
1216                 out_printf(out,"{\n");
1217                 if(m->ccode_line>0)
1218                         out_addline_infile(out,m->ccode_line);
1219                 out_printf(out,"\t%s}",m->cbuf);
1220         }
1221
1222         out_printf(out,"}\n");
1223
1224         if(m->cbuf)
1225                 out_addline_outfile(out);
1226 }
1227
1228 static void
1229 put_signal_args(Method *m)
1230 {
1231         GList *li;
1232         GList *ali;
1233         for(ali = m->gtktypes->next,li=m->args->next;
1234             li && ali;
1235             li=li->next, ali=ali->next) {
1236                 FuncArg *fa = li->data;
1237                 const char *cast = get_cast(ali->data,FALSE);
1238                 /* we should have already proved before that
1239                    the we know all the types */
1240                 g_assert(cast);
1241
1242                 out_printf(out,",\n\t\t(%s)%s",cast,
1243                            fa->name);
1244         }
1245 }
1246
1247 static char *
1248 get_arg_names_for_macro(Method *m)
1249 {
1250         char *p;
1251         GList *li;
1252         GString *gs = g_string_new("");
1253         p = "";
1254         for(li=m->args;li;li=g_list_next(li)) {
1255                 FuncArg *arg = li->data;
1256                 g_string_sprintfa(gs, "%s___%s", p, arg->name);
1257                 p = ",";
1258         }
1259         p = gs->str;
1260         g_string_free(gs,FALSE);
1261         return p;
1262 }
1263
1264 static void
1265 put_method(Method *m)
1266 {
1267         char *s,*args,*doc;
1268         gboolean is_void;
1269         is_void = (strcmp(m->mtype->name,"void")==0 &&
1270                    m->mtype->stars == 0);
1271         out_printf(out,"\n");
1272         doc = get_gtk_doc(m->id);
1273         if(doc) {
1274                 out_printf(out, "%s", doc);
1275                 g_free(doc);
1276         }
1277         switch(m->method) {
1278         case REGULAR_METHOD:
1279                 if(m->line_no>0)
1280                         out_addline_infile(out,m->line_no);
1281                 if(m->scope == PRIVATE_SCOPE)
1282                         print_method(out,"static ","\n",""," ","\n",
1283                                      m,FALSE,FALSE);
1284                 else /* PUBLIC, PROTECTED */
1285                         print_method(out, "", "\n", "", " ", "\n",
1286                                      m, FALSE, FALSE);
1287                 print_method_body(m,TRUE);
1288                 break;
1289         case SIGNAL_FIRST_METHOD:
1290         case SIGNAL_LAST_METHOD:
1291                 if(m->line_no>0)
1292                         out_addline_infile(out,m->line_no);
1293                 if(m->scope == PRIVATE_SCOPE)
1294                         print_method(out,"static ","\n",""," ","\n",
1295                                      m,FALSE,FALSE);
1296                 else /* PUBLIC, PROTECTED */
1297                         print_method(out,"","\n",""," ","\n",m,FALSE,FALSE);
1298                 out_addline_outfile(out);
1299                 out_printf(out,"{\n");
1300                 s = g_strdup(m->id);
1301                 g_strup(s);
1302                 if(strcmp(m->mtype->name,"void")==0 &&
1303                    m->mtype->stars==0) {
1304                         print_preconditions(m);
1305                         if(((FuncArg *)m->args->data)->name)
1306                         out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1307                                 "\t\tobject_signals[%s_SIGNAL]",
1308                                 ((FuncArg *)m->args->data)->name,s);
1309                         put_signal_args(m);
1310                         out_printf(out,");\n}\n");
1311                 } else {
1312                         out_printf(out,"\t");
1313                         print_type(out,m->mtype,TRUE);
1314                         out_printf(out,"return_val;\n");
1315                         print_preconditions(m);
1316                         out_printf(out,"\tgtk_signal_emit (GTK_OBJECT (%s),\n"
1317                                 "\t\tobject_signals[%s_SIGNAL]",
1318                                 ((FuncArg *)m->args->data)->name,s);
1319                         put_signal_args(m);
1320                         out_printf(out,",\n\t\t&return_val);\n"
1321                                 "\treturn return_val;\n}\n");
1322                 }
1323
1324                 if(!m->cbuf)
1325                         break;
1326                 if(m->line_no>0)
1327                         out_addline_infile(out,m->line_no);
1328                 print_method(out,"static ","\n___real_",""," ","\n",
1329                              m,FALSE,FALSE);
1330                 print_method_body(m,FALSE);
1331                 break;
1332         case VIRTUAL_METHOD:
1333                 if(m->line_no>0)
1334                         out_addline_infile(out,m->line_no);
1335                 if(m->scope==PRIVATE_SCOPE)
1336                         print_method(out,"static ","\n",""," ","\n",
1337                                      m,FALSE,FALSE);
1338                 else /* PUBLIC, PROTECTED */
1339                         print_method(out,"","\n",""," ","\n",m,FALSE,FALSE);
1340                 out_addline_outfile(out);
1341                 out_printf(out,"{\n"
1342                         "\t%sClass *klass;\n",typebase);
1343                 print_preconditions(m);
1344                 out_printf(out,"\tklass = %s_CLASS(GTK_OBJECT(%s)->klass);\n\n"
1345                         "\tif(klass->%s)\n",
1346                         macrobase, ((FuncArg *)m->args->data)->name, m->id);
1347                 if(strcmp(m->mtype->name,"void")==0 &&
1348                    m->mtype->stars==0) {
1349                         GList *li;
1350                         out_printf(out,"\t\t(*klass->%s)(%s",m->id,
1351                                    ((FuncArg *)m->args->data)->name);
1352                         for(li=m->args->next;li;li=g_list_next(li)) {
1353                                 FuncArg *fa = li->data;
1354                                 out_printf(out,",%s",fa->name);
1355                         }
1356                         out_printf(out,");\n}\n");
1357                 } else {
1358                         GList *li;
1359                         out_printf(out,"\t\treturn (*klass->%s)(%s",m->id,
1360                                    ((FuncArg *)m->args->data)->name);
1361                         for(li=m->args->next;li;li=g_list_next(li)) {
1362                                 FuncArg *fa = li->data;
1363                                 out_printf(out,",%s",fa->name);
1364                         }
1365                         out_printf(out,");\n"
1366                                 "\telse\n"
1367                                 "\t\treturn (");
1368                         print_type(out,m->mtype,TRUE);
1369                         out_printf(out,")(%s);\n}\n",
1370                                 m->onerror?m->onerror:"0");
1371                 }
1372
1373                 if(!m->cbuf)
1374                         break;
1375                 if(m->line_no>0)
1376                         out_addline_infile(out,m->line_no);
1377                 print_method(out,"static ","\n___real_",""," ","\n",
1378                              m,FALSE,FALSE);
1379                 print_method_body(m,FALSE);
1380                 break;
1381         case OVERRIDE_METHOD:
1382                 if(!m->cbuf)
1383                         break;
1384                 if(m->line_no>0)
1385                         out_addline_infile(out,m->line_no);
1386                 print_method(out,"static ","\n",""," ","\n",
1387                              m,FALSE,FALSE);
1388                 s = replace_sep(m->otype,'_');
1389                 g_strup(s);
1390                 args = get_arg_names_for_macro(m);
1391                 if(is_void) {
1392                         out_printf(out,"#define PARENT_HANDLER(%s) \\\n"
1393                                    "\t{ if(%s_CLASS(parent_class)->%s) \\\n"
1394                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s); }\n",
1395                                    args,s,m->id,s,m->id,args);
1396                 } else {
1397                         out_printf(out,"#define PARENT_HANDLER(%s) \\\n"
1398                                    "\t((%s_CLASS(parent_class)->%s)? \\\n"
1399                                    "\t\t(* %s_CLASS(parent_class)->%s)(%s): \\\n"
1400                                    "\t\t(",
1401                                    args,s,m->id,s,m->id,args);
1402                         out_printf(out,"(");
1403                         print_type(out,m->mtype,TRUE);
1404                         out_printf(out,")%s))\n",
1405                                    m->onerror?m->onerror:"0");
1406                 }
1407                 g_free(args);
1408                 g_free(s);
1409                 print_method_body(m,TRUE);
1410                 out_printf(out,"#undef PARENT_HANDLER\n");
1411                 break;
1412         default:
1413                 break;
1414         }
1415 }
1416
1417 static void
1418 open_files(void)
1419 {
1420         char *outfile,*outfileh,*outfileph;
1421
1422         if(!for_cpp)
1423                 outfile = g_strconcat(filebase,".c",NULL);
1424         else
1425                 outfile = g_strconcat(filebase,".cc",NULL);
1426         if(no_touch_headers)
1427                 outfileh = g_strconcat("#gob#",filebase,".h#gob#",NULL);
1428         else
1429                 outfileh = g_strconcat(filebase,".h",NULL);
1430
1431         if((privates>0 || protecteds>0 || always_private_header) &&
1432            !no_private_header)
1433                 outfileph = g_strconcat(filebase,"-private.h",NULL);
1434         else
1435                 outfileph = NULL;
1436
1437         
1438         if(no_write) {
1439                 devnull = fopen("/dev/null","w");
1440                 if(!devnull) {
1441                         g_error("Cannot open null device",NULL);
1442                 }
1443                 out = devnull;
1444                 outh = devnull;
1445                 if(outfileph)
1446                         outph = devnull;
1447         } else {
1448                 out = fopen(outfile,"w");
1449                 if(!out) {
1450                         g_error("Cannot open outfile: %s",outfile);
1451                 }
1452                 outh = fopen(outfileh,"w");
1453                 if(!outh) {
1454                         g_error("Cannot open outfile: %s",outfileh);
1455                 }
1456                 if(outfileph) {
1457                         outph = fopen(outfileph,"w");
1458                         if(!outph) {
1459                                 g_error("Cannot open outfile: %s",outfileh);
1460                         }
1461                 }
1462         }
1463 }
1464
1465 static void
1466 put_argument_nongnu_wrappers(Class *c)
1467 {
1468         GList *li;
1469
1470         if(arguments<0)
1471                 return;
1472
1473         for(li=c->nodes;li;li=g_list_next(li)) {
1474                 Node *n = li->data;
1475                 Argument *a = (Argument *)n;
1476                 char *s;
1477                 char *cast;
1478                 if(n->type != ARGUMENT_NODE)
1479                         continue;
1480                 s = g_strdup(a->name);
1481                 g_strup(s);
1482                 if(a->atype)
1483                         cast = get_type(a->atype,TRUE);
1484                 else
1485                         cast = g_strdup(get_cast(a->gtktype,TRUE));
1486
1487                 if(cast) {
1488                         if(a->set)
1489                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1490                                            "\"%s\",(%s)(arg)\n",
1491                                            macrobase, s, a->name, cast);
1492                         if(a->get)
1493                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1494                                            "\"%s\",(%s*)(arg)\n",
1495                                            macrobase, s, a->name, cast);
1496                 } else {
1497                         if(a->set)
1498                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1499                                            "\"%s\",(arg)\n",
1500                                            macrobase, s, a->name);
1501                         if(a->get)
1502                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1503                                            "\"%s\",(arg)\n",
1504                                            macrobase, s, a->name);
1505                 }
1506                 g_free(cast);
1507                 g_free(s);
1508         }
1509 }
1510
1511 static void
1512 put_argument_gnu_wrappers(Class *c)
1513 {
1514         GList *li;
1515
1516         if(arguments<0)
1517                 return;
1518
1519         for(li=c->nodes;li;li=g_list_next(li)) {
1520                 Node *n = li->data;
1521                 Argument *a = (Argument *)n;
1522                 char *s;
1523                 char *cast;
1524                 if(n->type != ARGUMENT_NODE)
1525                         continue;
1526                 s = g_strdup(a->name);
1527                 g_strup(s);
1528                 if(a->atype)
1529                         cast = get_type(a->atype,TRUE);
1530                 else
1531                         cast = g_strdup(get_cast(a->gtktype,TRUE));
1532                 if(cast) {
1533                         if(a->set)
1534                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1535                                            "\"%s\",({%sz = (arg); z;})\n",
1536                                            macrobase, s, a->name, cast);
1537                         if(a->get)
1538                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1539                                            "\"%s\",({%s*z = (arg); z;})\n",
1540                                            macrobase, s, a->name, cast);
1541                 } else {
1542                         if(a->set)
1543                                 out_printf(outh, "#define %s_ARG_%s(arg)    \t"
1544                                            "\"%s\",(arg)\n",
1545                                            macrobase, s, a->name);
1546                         if(a->get)
1547                                 out_printf(outh, "#define %s_GET_ARG_%s(arg)\t"
1548                                            "\"%s\",(arg)\n",
1549                                            macrobase, s, a->name);
1550                 }
1551                 g_free(cast);
1552                 g_free(s);
1553         }
1554 }
1555
1556 static void
1557 print_ccode_block(CCode *cc)
1558 {
1559         FILE *fp;
1560         switch(cc->cctype) {
1561         case HT_CCODE:
1562                 /* HT code is printed exactly like normal header
1563                    code but is printed before */
1564         case H_CCODE:
1565                 fp = outh;
1566                 out_printf(fp,"\n");
1567                 break;
1568         case AT_CCODE:
1569                 /* AT code is printed exactly like normal 'all'
1570                    code but is printed before */
1571         case A_CCODE:
1572                 if(outph) {
1573                         out_printf(outph,"\n");
1574                         out_printf(outph,"%s\n",cc->cbuf);
1575                         out_addline_infile(outph,cc->line_no);
1576                         out_addline_outfile(outph);
1577                 }
1578                 out_printf(outh,"\n");
1579                 out_printf(outh,"%s\n",cc->cbuf);
1580                 fp = out;
1581                 out_printf(fp,"\n");
1582                 out_addline_infile(fp,cc->line_no);
1583                 break;
1584         default:
1585         case C_CCODE:
1586                 fp = out;
1587                 out_printf(fp,"\n");
1588                 out_addline_infile(fp,cc->line_no);
1589                 break;
1590         case PH_CCODE:
1591                 if(outph)
1592                         fp = outph;
1593                 else
1594                         fp = out;
1595                 out_printf(fp,"\n");
1596                 out_addline_infile(fp,cc->line_no);
1597                 break;
1598         }
1599         out_printf(fp,"%s\n",cc->cbuf);
1600         if(cc->cctype == C_CCODE ||
1601            cc->cctype == A_CCODE ||
1602            cc->cctype == AT_CCODE ||
1603            cc->cctype == PH_CCODE)
1604                 out_addline_outfile(fp);
1605 }
1606
1607 static void
1608 print_class_block(Class *c)
1609 {
1610         GList *l;
1611         char *s;
1612         gboolean printed_private = FALSE;
1613
1614         out_printf(out,"/* utility types we may need */\n");
1615         out_printf(out,"typedef struct { "
1616                    "gpointer a; gpointer b; "
1617                    "} ___twopointertype;\n");
1618         out_printf(out,"typedef struct { "
1619                    "gpointer a; gpointer b; "
1620                    "gpointer c; "
1621                    "} ___threepointertype;\n");
1622
1623         out_printf(outh, "\n/*\n"
1624                    " * Type checking and casting macros\n"
1625                    " */\n");
1626         out_printf(outh,"#define %s\t"
1627                    "(%s_get_type())\n",
1628                    macrotype,funcbase);
1629         out_printf(outh,"#define %s(obj)\t"
1630                    "GTK_CHECK_CAST((obj),%s_get_type(),%s)\n",
1631                    macrobase,funcbase,typebase);
1632         out_printf(outh,"#define %s_CLASS(klass)\t"
1633                    "GTK_CHECK_CLASS_CAST((klass),%s_get_type(),%sClass)\n",
1634                    macrobase,funcbase,typebase);
1635         out_printf(outh,"#define %s(obj)\t"
1636                    "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n",
1637                    macrois,funcbase);
1638
1639         out_printf(out, "\n/* self casting macros */\n");
1640         out_printf(out, "#define SELF(x) %s(x)\n", macrobase);
1641         out_printf(out, "#define IS_SELF(x) %s(x)\n", macrois);
1642         out_printf(out, "#define SELF_CLASS(x) %s_CLASS(x)\n\n", macrobase);
1643
1644         if(privates>0) {
1645                 out_printf(outh, "\n/* Private structure type */\n");
1646                 out_printf(outh,"typedef struct _%sPrivate %sPrivate;\n",
1647                            typebase,typebase);
1648         }
1649
1650         out_printf(outh, "\n/*\n"
1651                    " * Main object structure\n"
1652                    " */\n");
1653         s = replace_sep(c->otype,'_');
1654         g_strup(s);
1655         out_printf(outh,"#ifndef __TYPEDEF_%s__\n"
1656                    "#define __TYPEDEF_%s__\n",s,s);
1657         g_free(s);
1658         out_printf(outh,"typedef struct _%s %s;\n"
1659                    "#endif\n",typebase,typebase);
1660         out_printf(outh,"struct _%s {\n\t%s __parent__;\n",
1661                    typebase,ptypebase);
1662         for(l=c->nodes;l;l=g_list_next(l)) {
1663                 static gboolean printed_public = FALSE;
1664                 Node *n = l->data;
1665                 Variable *v = (Variable *)n;
1666                 if(n->type == VARIABLE_NODE &&
1667                    v->scope == PUBLIC_SCOPE) {
1668                         if(!printed_public) {
1669                                 out_printf(outh,"\t/*< public >*/\n");
1670                                 printed_public = TRUE;
1671                         }
1672                         put_variable((Variable *)n,outh);
1673                 }
1674         }
1675         /* put protecteds always AFTER publics */
1676         for(l=c->nodes;l;l=g_list_next(l)) {
1677                 Node *n = l->data;
1678                 Variable *v = (Variable *)n;
1679                 if(n->type == VARIABLE_NODE &&
1680                    v->scope == PROTECTED_SCOPE) {
1681                         if(!printed_private) {
1682                                 out_printf(outh,"\t/*< private >*/\n");
1683                                 printed_private = TRUE;
1684                         }
1685                         put_variable((Variable *)n,outh);
1686                 }
1687         }
1688         if(privates>0) {
1689                 if(!printed_private)
1690                         out_printf(outh,"\t/*< private >*/\n");
1691                 out_printf(outh,"\t%sPrivate *_priv;\n",typebase);
1692         }
1693         out_printf(outh,"};\n");
1694
1695         if(privates>0) {
1696                 FILE *outfp;
1697
1698                 /* if we are to stick this into the private
1699                    header, if not stick it directly into the
1700                    C file */
1701                 if(outph) 
1702                         outfp = outph;
1703                 else
1704                         outfp = out;
1705
1706                 out_printf(outfp,"struct _%sPrivate {\n",
1707                            typebase);
1708                 for(l=c->nodes;l;l=l->next) {
1709                         Node *n = l->data;
1710                         Variable *v = (Variable *)n;
1711                         if(n->type == VARIABLE_NODE &&
1712                            v->scope == PRIVATE_SCOPE) {
1713                                 out_addline_infile(outfp,v->line_no);
1714                                 put_variable(v,outfp);
1715                         }
1716                 }
1717                 out_addline_outfile(outfp);
1718                 out_printf(outfp,"};\n");
1719         }
1720
1721         out_printf(outh, "\n/*\n"
1722                    " * Class definition\n"
1723                    " */\n");
1724         out_printf(outh,"typedef struct _%sClass %sClass;\n",
1725                    typebase,typebase);
1726         out_printf(outh,
1727                    "struct _%sClass {\n\t%sClass __parent__;\n",
1728                    typebase,ptypebase);
1729         for(l=c->nodes;l;l=g_list_next(l)) {
1730                 Node *n = l->data;
1731                 if(n->type == METHOD_NODE)
1732                         put_vs_method((Method *)n);
1733         }
1734         out_printf(outh,"};\n\n");
1735
1736         out_printf(out,"/* here are local prototypes */\n");
1737         if(arguments>0) {
1738                 out_printf(out,"static void ___object_set_arg "
1739                            "(GtkObject *object, GtkArg *arg, "
1740                            "guint arg_id);\n"
1741                            "static void ___object_get_arg "
1742                            "(GtkObject *object, GtkArg *arg, "
1743                            "guint arg_id);\n");
1744         }
1745
1746         out_printf(outh, "\n/*\n"
1747                    " * Public methods\n"
1748                    " */\n");
1749
1750         out_printf(outh,"guint\t%s_get_type\t(void);\n",funcbase);
1751         for(l=c->nodes;l;l=g_list_next(l)) {
1752                 Node *n = l->data;
1753                 if(n->type == METHOD_NODE) {
1754                         put_pub_method((Method *)n);
1755                         put_prot_method((Method *)n);
1756                         put_priv_method_prot((Method *)n);
1757                 }
1758         }
1759
1760 /* this idea is less and less apealing to me */
1761 #if 0
1762         if(!no_signal_connect) {
1763                 if(signals>0) {
1764                         out_printf(outh, "\n/*\n"
1765                                    " * Signal connection methods\n"
1766                                    " */\n");
1767                 }
1768
1769                 for(l=c->nodes;l;l=g_list_next(l)) {
1770                         Node *n = l->data;
1771                         if(n->type == METHOD_NODE)
1772                                 put_signal_connect((Method *)n);
1773                 }
1774         }
1775 #endif
1776
1777
1778         /* argument wrapping macros */
1779         if(arguments>0 && !no_gnu) {
1780                 out_printf(outh, "\n/*\n"
1781                            " * Argument wrapping macros\n"
1782                            " */\n");
1783                 out_printf(outh,"#ifdef __GNUC__\n");
1784                 put_argument_gnu_wrappers(c);
1785                 out_printf(outh,"#else /* __GNUC__ */\n");
1786                 put_argument_nongnu_wrappers(c);
1787                 out_printf(outh,"#endif /* __GNUC__ */\n\n");
1788         } else if(arguments>0 && no_gnu) {
1789                 out_printf(outh, "\n/*\n"
1790                            " * Argument wrapping macros\n"
1791                            " */\n");
1792                 put_argument_nongnu_wrappers(c);
1793         }
1794
1795         if(signals>0) {
1796                 for(l=c->nodes;l;l=g_list_next(l)) {
1797                         Node *n = l->data;
1798                         if(n->type == METHOD_NODE)
1799                                 add_signal_prots((Method *)n);
1800                 }
1801         }
1802
1803         add_enums(c);
1804
1805         add_get_type();
1806
1807         if(no_gnu)
1808                 make_method_nongnu_aliases(c);
1809         else {
1810                 out_printf(out,"\n#ifdef __GNUC__\n");
1811                 make_method_gnu_aliases(c);
1812                 out_printf(out,"#else /* __GNUC__ */\n");
1813                 make_method_nongnu_aliases(c);
1814                 out_printf(out,"#endif /* __GNUC__ */\n\n");
1815         }
1816
1817         out_printf(out,"#define GET_NEW (gtk_type_new(%s_get_type()))\n",
1818                    funcbase);
1819
1820         add_inits(c);
1821
1822         if(arguments>0) {
1823                 add_getset_arg(c, TRUE);
1824                 add_getset_arg(c, FALSE);
1825         }
1826
1827         for(l=c->nodes;l;l=g_list_next(l)) {
1828                 Node *n = l->data;
1829                 if(n->type == METHOD_NODE) {
1830                         put_method((Method *)n);
1831                 }
1832         }
1833
1834         out_printf(out,"#undef GET_NEW\n");
1835
1836         add_bad_hack_to_avoid_unused_warnings(c);
1837 }
1838
1839 static void
1840 print_version_macros(void)
1841 {
1842         int major=0,minor=0,pl=0;
1843         sscanf(VERSION,"%d.%d.%d",&major,&minor,&pl);
1844
1845         out_printf(out, "#define GOB_VERSION_MAJOR %d\n", major);
1846         out_printf(out, "#define GOB_VERSION_MINOR %d\n", minor);
1847         out_printf(out, "#define GOB_VERSION_PATCHLEVEL %d\n\n", pl);
1848 }
1849
1850 static void
1851 print_file_comments(void)
1852 {
1853         time_t curtime;
1854         time(&curtime);
1855         out_printf(outh,"/* Generated by GOB (v%s)"
1856                "   (do not edit directly) */\n\n",VERSION);
1857         if(outph)
1858                 out_printf(outph,"/* Generated by GOB (v%s)"
1859                            "   (do not edit directly) */\n\n",VERSION);
1860         out_printf(out,"/* Generated by GOB (v%s) on %s"
1861                "   (do not edit directly) */\n\n",VERSION,ctime(&curtime));
1862 }
1863
1864 static void
1865 print_includes(void)
1866 {
1867         gboolean found_header;
1868         char *p;
1869
1870         p = g_strconcat(filebase,".h",NULL);
1871         found_header = TRUE;
1872         if(!g_list_find_custom(include_files,p,(GCompareFunc)strcmp)) {
1873                 out_printf(out,"#include \"%s.h\"\n\n",filebase);
1874                 found_header = FALSE;
1875         }
1876         g_free(p);
1877
1878         /* if we are creating a private header see if it was included */
1879         if(outph) {
1880                 p = g_strconcat(filebase,"-private.h",NULL);
1881                 if(!g_list_find_custom(include_files,p,(GCompareFunc)strcmp)) {
1882                         out_printf(out,"#include \"%s-private.h\"\n\n",
1883                                    filebase);
1884                         if(found_header)
1885                                 print_error(TRUE,
1886                                             "Implicit private header include "
1887                                             "added to top of\n"
1888                                             "\tsource file, while public "
1889                                             "header is at a custom location, "
1890                                             "you should\n"
1891                                             "\texplicitly include "
1892                                             "the private header below the "
1893                                             "public one.", 0);
1894                 }
1895                 g_free(p);
1896         }
1897 }
1898
1899 static void
1900 print_header_prefixes(void)
1901 {
1902         char *p;
1903
1904         p = replace_sep(((Class *)class)->otype,'_');
1905         g_strup(p);
1906         out_printf(outh,"#ifndef __%s_H__\n#define __%s_H__\n\n",p,p);
1907         if(outph)
1908                 out_printf(outph,"#ifndef __%s_PRIVATE_H__\n"
1909                            "#define __%s_PRIVATE_H__\n\n"
1910                            "#include \"%s.h\"\n\n",p,p,filebase);
1911         g_free(p);
1912
1913         if(!no_extern_c) {
1914                 out_printf(outh,"#ifdef __cplusplus\n"
1915                            "extern \"C\" {\n"
1916                            "#endif /* __cplusplus */\n\n");
1917                 if(outph)
1918                         out_printf(outph,"#ifdef __cplusplus\n"
1919                                    "extern \"C\" {\n"
1920                                    "#endif /* __cplusplus */\n\n");
1921         }
1922 }
1923
1924 static void
1925 print_header_postfixes(void)
1926 {
1927         if(!no_extern_c)
1928                 out_printf(outh,"\n#ifdef __cplusplus\n"
1929                            "}\n"
1930                            "#endif /* __cplusplus */\n");
1931         out_printf(outh,"\n#endif");
1932         if(outph) {
1933                 if(!no_extern_c)
1934                         out_printf(outph,"\n#ifdef __cplusplus\n"
1935                                    "}\n"
1936                                    "#endif /* __cplusplus */\n");
1937                 out_printf(outph,"\n#endif");
1938         }
1939 }
1940
1941 static void
1942 print_all_top(void)
1943 {
1944         GList *li;
1945
1946         /* print the AT_CCODE blocks */
1947         for(li=nodes;li;li=g_list_next(li)) {
1948                 Node *node = li->data;
1949                 if(node->type == CCODE_NODE) {
1950                         CCode *cc = (CCode *)node;
1951                         if(cc->cctype==AT_CCODE)
1952                                 print_ccode_block((CCode *)node);
1953                 }
1954         }
1955 }
1956
1957 static void
1958 print_header_top(void)
1959 {
1960         GList *li;
1961
1962         /* mandatory include */
1963         out_printf(outh,"#include <gtk/gtk.h>\n\n");
1964
1965         /* print the HT_CCODE blocks */
1966         for(li=nodes;li;li=g_list_next(li)) {
1967                 Node *node = li->data;
1968                 if(node->type == CCODE_NODE) {
1969                         CCode *cc = (CCode *)node;
1970                         if(cc->cctype==HT_CCODE)
1971                                 print_ccode_block((CCode *)node);
1972                 }
1973         }
1974 }
1975
1976 static void
1977 generate_outfiles(void)
1978 {
1979         GList *li;
1980
1981         print_file_comments();
1982
1983         print_all_top();
1984
1985         print_header_top();
1986
1987         print_header_prefixes();
1988
1989         print_version_macros();
1990
1991         print_includes();
1992
1993         for(li=nodes;li;li=g_list_next(li)) {
1994                 Node *node = li->data;
1995                 if(node->type == CCODE_NODE) {
1996                         CCode *cc = (CCode *)node;
1997                         if(cc->cctype!=HT_CCODE)
1998                                 print_ccode_block((CCode *)node);
1999                 } else if(node->type == CLASS_NODE) {
2000                         print_class_block((Class *)node);
2001                 } else
2002                         g_assert_not_reached();
2003         }
2004
2005         print_header_postfixes();
2006 }
2007
2008 static void
2009 print_help(void)
2010 {
2011         fprintf(stderr,"Gob version %s\n\n",VERSION);
2012         fprintf(stderr,"Options:\n"
2013                 "\t--help,-h,-?            Display this help\n"
2014                 "\t--version               Display version\n"
2015                 "\t--exit-on-warn,-w       Exit with an error on warnings\n"
2016                 "\t--no-exit-on-warn       Don't exit on warnings [default]\n"
2017                 "\t--for-cpp               Create C++ files\n"
2018                 "\t--no-extern-c           Never print extern \"C\" into the "
2019                                           "header\n"
2020                 "\t--no-gnu                Never use GNU extentions\n"
2021                 "\t--no-touch-headers      Don't touch headers unless they "
2022                                           "really changed\n"
2023                 "\t--always-private-header Always create a private header "
2024                                           "file,\n"
2025                 "\t                        even if it would be empty\n"
2026                 "\t--no-private-header     Don't create a private header, "
2027                                           "put private\n"
2028                 "\t                        structure and protected "
2029                                           "prototypes inside c file\n"
2030                 "\t--no-write,-n           Don't write output files, just "
2031                                           "check syntax\n");
2032 }
2033
2034 static void
2035 parse_options(int argc, char *argv[])
2036 {
2037         int i;
2038         int got_file = FALSE;
2039         int no_opts = FALSE;
2040
2041         filename = NULL;
2042
2043         for(i=1;i<argc;i++) {
2044                 if(no_opts || argv[i][0]!='-') {
2045                         /*must be a file*/
2046                         if(got_file) {
2047                                 fprintf(stderr, "Specify only one file!\n");
2048                                 print_help();
2049                                 exit(1);
2050                         }
2051                         filename = argv[i];
2052                         got_file = TRUE;
2053                 } else if(strcmp(argv[i],"--help")==0) {
2054                         print_help();
2055                         exit(0);
2056                 } else if(strcmp(argv[i],"--version")==0) {
2057                         fprintf(stderr, "Gob version %s\n", VERSION);
2058                         exit(0);
2059                 } else if(strcmp(argv[i], "--exit-on-warn")==0) {
2060                         exit_on_warn = TRUE;
2061                 } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
2062                         exit_on_warn = FALSE;
2063                 } else if(strcmp(argv[i], "--for-cpp")==0) {
2064                         for_cpp = TRUE;
2065                 } else if(strcmp(argv[i], "--no-touch-headers")==0) {
2066                         no_touch_headers = TRUE;
2067                 } else if(strcmp(argv[i], "--always-private-header")==0) {
2068                         no_private_header = FALSE;
2069                         always_private_header = TRUE;
2070                 } else if(strcmp(argv[i], "--no-private-header")==0) {
2071                         always_private_header = FALSE;
2072                         no_private_header = TRUE;
2073                 } else if(strcmp(argv[i], "--no-gnu")==0) {
2074                         no_gnu = TRUE;
2075                 } else if(strcmp(argv[i], "--no-extern-c")==0) {
2076                         no_extern_c = TRUE;
2077                 } else if(strcmp(argv[i], "--no-write")==0) {
2078                         no_write = TRUE;
2079                 } else if(strcmp(argv[i], "--")==0) {
2080                         /*further arguments are files*/
2081                         no_opts = TRUE;
2082                 } else if(strncmp(argv[i], "--",2)==0) {
2083                         /*unknown long option*/
2084                         fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
2085                         print_help();
2086                         exit(1);
2087                 } else {
2088                         /*by now we know we have a string starting with
2089                           - which is a short option string*/
2090                         char *p = argv[i]+1;
2091                         for(p=argv[i]+1; *p; p++) {
2092                                 switch(*p) {
2093                                 case 'w':
2094                                         exit_on_warn=TRUE;
2095                                         break;
2096                                 case 'n':
2097                                         no_write = TRUE;
2098                                         break;
2099                                 case 'h':
2100                                 case '?':
2101                                         print_help();
2102                                         exit(0);
2103                                 default:
2104                                         fprintf(stderr,
2105                                                 "Unknown option '%c'!\n", *p);
2106                                         print_help();
2107                                         exit(1);
2108                                 }
2109                         }
2110                 }
2111         }
2112 }
2113
2114 /* this is a somewhat ugly hack, but it appears to work */
2115 static void
2116 compare_and_move_header(void)
2117 {
2118         char *hfnew = g_strconcat("#gob#", filebase, ".h#gob#", NULL);
2119         char *hf = g_strconcat(filebase, ".h", NULL);
2120         struct stat s;
2121         if(stat(hf,&s)==0) {
2122                 char *s;
2123                 s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
2124                 if(system(s)==0) {
2125                         if(unlink(hfnew)!=0)
2126                                 print_error(FALSE,
2127                                             "Can't remove new header file", 0);
2128                         g_free(hfnew);
2129                         g_free(hf);
2130                         g_free(s);
2131                         return;
2132                 }
2133                 g_free(s);
2134                 if(unlink(hf)!=0)
2135                         print_error(FALSE, "Can't remove old header file", 0);
2136         }
2137         if(rename(hfnew,hf)!=0)
2138                 print_error(FALSE, "Can't rename new header file", 0);
2139         g_free(hfnew);
2140         g_free(hf);
2141 }
2142
2143 int
2144 main(int argc, char *argv[])
2145 {
2146         parse_options(argc, argv);
2147         
2148         if(filename) {
2149                 yyin = fopen(filename, "r");
2150                 if(!yyin) {
2151                         fprintf(stderr, "Error: can't open file '%s'\n",
2152                                 filename);
2153                         exit(1);
2154                 }
2155         } else
2156                 filename = "stdin";
2157
2158         /*yydebug = 1;*/
2159         if(yyparse()!=0)
2160                 g_error("Parsing errors, quitting");
2161         if(!class)
2162                 print_error(FALSE, " no class defined", 0);
2163         
2164
2165         exit_on_error = FALSE;
2166
2167         signals = count_signals((Class *)class);
2168         arguments = count_arguments((Class *)class);
2169         overrides = count_overrides((Class *)class);
2170         privates = count_privates((Class *)class);
2171         protecteds = count_protecteds((Class *)class);
2172
2173         make_bases();
2174         make_inits((Class *)class);
2175         if(privates>0)
2176                 make_finalize((Class *)class);
2177         check_bad_symbols((Class *)class);
2178         check_duplicate_symbols((Class *)class);
2179         check_duplicate_signals_args((Class *)class);
2180         check_public_new((Class *)class);
2181         check_vararg((Class *)class);
2182         check_firstarg((Class *)class);
2183         check_nonvoidempty((Class *)class);
2184         check_signal_args((Class *)class);
2185         check_argument_types((Class *)class);
2186
2187         exit_on_error = TRUE;
2188         
2189         if(got_error)
2190                 exit(1);
2191
2192         open_files();
2193         
2194         generate_outfiles();
2195
2196         if(devnull)
2197                 fclose(devnull);
2198         else {
2199                 fclose(out);
2200                 fclose(outh);
2201                 if(outph)
2202                         fclose(outph);
2203         }
2204
2205         if(no_touch_headers && !no_write)
2206                 compare_and_move_header();
2207         
2208         return 0;
2209 }