/*   wbuild
     Copyright (C) 1996  Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
     
     This program is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License
     as published by the Free Software Foundation; either version 2
     of the License, or (at your option) any later version.
     
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
     
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* This module contains the code that generates C and
 * documentation files from the specification of the widgets in a |Class|
 * datastructure. The only exported function is |generate|, which uses the
 * global list of class specifications.
 */

#define fputS(s, f) fputs(get(s), f)

#include <config.h>
#include <stdio.h>

#include <libit/unistd.h>
#include <libit/string.h>
#include <libit/ctype.h>
#include <wbuild.h>
#include <wsym.h>

#include <libintl.h>
#define _(String) gettext(String)

#include <libit/malloc.h>

/* Public header file. The public header file contains the |#define|s
 * for the resources and other exported identifiers. It is protected by a
 * guard.
 *
 * The public header files generated by wbuild also include the public
 * header file of the superclass, although this is not de rigueur for
 * standard widgets. The reason is that the exported things from
 * superclasses often stay valied for subclasses. An application that
 * includes only the widget that it actually uses, would have no access
 * to anything defined in the superclasses.
 */


/* The Intrinsics header files are alway found in |X11|, but other
 * files can either be in the same directory as where the headers for
 * this widget should go (|prefix| from |-p| option), or in an explicitly
 * named directory. E.g., if the widget was declared `@@class myclass
 * (Foo/mysuper),' then `Foo' will be used instead of |prefix|.
 */

inline static void public_include(FILE *f, Class c, char *prefix, char *private)
{
	char *s, *slash;

	if (c->super && c->super->filenamepart)
		s = get(c->super->filenamepart);
	else
		s = get(c->superclass);

	slash = strchr(s, '/');
	if (slash) {
		fprintf(f, "#include <%s%s.h>\n", s, private);
	} else {
		fprintf(f, "#include <%s/%s%s.h>\n", prefix, s, private);
	}
}


#if 0
inline static void public_include(FILE *f, Class c)
{
	if (c->superclass == CORE)
		fputs("#include <X11/Core.h>\n", f);
	else if (c->superclass == OBJECT)
		fputs("#include <X11/Object.h>\n", f);
	else if (c->superclass == RECTOBJ)
		fputs("#include <X11/RectObj.h>\n", f);
	else if (c->superclass == COMPOSITE)
		fputs("#include <X11/Composite.h>\n", f);
	else if (c->superclass == SHELL
			|| c->superclass == OVERRIDESHELL
			|| c->superclass == WMSHELL
			|| c->superclass == VENDORSHELL
			|| c->superclass == TRANSIENTSHELL
			|| c->superclass == TOPLEVELSHELL
			|| c->superclass == APPLICATIONSHELL)
		fputs("#include <X11/Shell.h>\n", f);
	else if (c->superclass == CONSTRAINT)
		fputs("#include <X11/Constraint.h>\n", f);
	else if (c->superclass == XMPRIMITIVE || c->superclass == PRIMITIVE)
		/* There is no such thing as Xm/Primitive.h */ ;
	else if (c->superclass == XMMANAGER || c->superclass == MANAGER)
		/* There is no such thing as Xm/Manager.h */ ;
	else if (c->super) {
		char *p, *q = get(c->superclass);
		if ((p = strrchr(q, '/'))) {
			*p = '\0';
			fprintf(f, "#include <%s>\n",
				get(get_headername(q, c->super)));
			*p = '/';
		} else {
			fprintf(f, "#include <%s>\n",
				get(get_headername(prefix, c->super)));
		}
	}
}
#endif

/* Exported things come in two flavors: functions and other things.
 * Functions are printed with their parameter list protected by a macro.
 * The function |declare_function| is defined
 * in~\ref{declare-function}.
 */

inline static void declare_export_type(FILE *f, Section s)
{
	fputs("typedef ", f);
	fputS(s->decl->type, f);
	putc(' ', f);
	fputS(s->decl->name, f);
	fputs(";\n\n", f);
}


static void define_macro(FILE *f, Class c, Decl d)
{
	Decl d1;

	fputs("#define ", f);
	fputS(d->name, f);
	if (d->params) {
		putc('(', f);
		for (d1 = d->params; d1; d1 = d1->next) {
			fputS(d1->name, f);
			if (d1->next)
				fputs(", ", f);
		}
		putc(')', f);
	}
	putc(' ', f);
	print_body(f, d->body, c, d->name, d->lineno, 1);
	fputs("\n\n", f);
}

inline static void declare_export_var(FILE *f, Section s)
{
	fputS(s->decl->type, f);
	putc(' ', f);
	fputS(s->decl->name, f);
	if (s->decl->suffix)
		fputS(s->decl->suffix, f);
	fputs(";\n\n", f);
}

/* For each resource there are two define's, one for the instance name
 * (starting with \.{XtN}, and one for the class name, starting with
 * \.{XtC}. However, if the resource is inherited, we don't have to declare
 * it here.
 */

inline static void define_resource_symbols(FILE *f, Class c)
{
	STRING hi, hc, ht;
	Section s;

	for (s = c->publicvars; s; s = s->next) {
		if (s->decl == NULL || s->decl->tp != Var)
			continue;
		if (find_instvar_class(c, s->decl->name) != c)
			continue;
		if (s->decl->typesym) {
			ht = hdup(s->decl->typesym);
		} else if (!s->decl->type) {
			fprintf(stderr, _("%s:%d: Missing type for `%s'\n"),
				get(c->filename), s->decl->lineno,
				get(s->decl->name));
			nerrors++;
			continue;      
		} else {
			ht = get_word(get(get_classname(s->decl->type)));
		}
		if (s->decl->namesym) {
			hi = get_instname(s->decl->namesym);
			hc = get_classname(s->decl->namesym);
		} else {
			hi = get_instname(s->decl->name);
			hc = get_classname(s->decl->name);
		}
		fprintf(f, "#ifndef XtN%s\n", get(hi));
		fprintf(f, "#define XtN%s \"%s\"\n", get(hi), get(hi));
		fprintf(f, "#endif\n");
		fprintf(f, "#ifndef XtC%s\n", get(hc));
		fprintf(f, "#define XtC%s \"%s\"\n", get(hc), get(hc));
		fprintf(f, "#endif\n");
		fprintf(f, "#ifndef XtR%s\n", get(ht));
		fprintf(f, "#define XtR%s \"%s\"\n", get(ht), get(ht));
		fprintf(f, "#endif\n\n");
		delete(hi);
		delete(hc);
		delete(ht);
	}
}

/* Constraint resources are treated the same as public variables: for
 * each resource there are two define's, one for the instance name
 * (starting with \.{XtN}, and one for the class name, starting with
 * \.{XtC}. However, if the resource is inherited, we don't have to
 * declare it here.
 */

inline static void define_constraint_resource_symbols(FILE *f, Class c)
{
	STRING hi, hc, ht;
	Section s;

	for (s = c->constraints; s; s = s->next) {
		if (s->decl == NULL || s->decl->tp != Var)
			continue;
		if (find_constr_class(c, s->decl->name) != c)
			continue;
		if (s->decl->typesym)
			ht = hdup(s->decl->typesym);
		else if (!s->decl->type) {
			fprintf(stderr, _("%s:%d: Missing type for `%s'\n"),
				get(c->filename), s->decl->lineno,
				get(s->decl->name));
			nerrors++;
			continue;      
		} else {
			ht = get_word(get(get_classname(s->decl->type)));
		}
		if (s->decl->namesym) {
			hi = get_instname(s->decl->namesym);
			hc = get_classname(s->decl->namesym);
		} else {
			hi = get_instname(s->decl->name);
			hc = get_classname(s->decl->name);
		}
		fprintf(f, "#ifndef XtN%s\n", get(hi));
		fprintf(f, "#define XtN%s \"%s\"\n", get(hi), get(hi));
		fprintf(f, "#endif\n");
		fprintf(f, "#ifndef XtC%s\n", get(hc));
		fprintf(f, "#define XtC%s \"%s\"\n", get(hc), get(hc));
		fprintf(f, "#endif\n");
		fprintf(f, "#ifndef XtR%s\n", get(ht));
		fprintf(f, "#define XtR%s \"%s\"\n", get(ht), get(ht));
		fprintf(f, "#endif\n\n");
		delete(hi);
		delete(hc);
		delete(ht);
	}
}

inline static void typedef_class_instance(FILE *f, Class c)
{
	fprintf(f, "typedef struct _%sClassRec *%sWidgetClass;\n",
		get(c->name), get(c->name));
	fprintf(f, "typedef struct _%sRec *%sWidget;\n",
		get(c->name), get(c->name));
	fprintf(f, "externalref WidgetClass %sWidgetClass;\n",
		get(get_instname(c->name)));
}

inline static void declare_exports(FILE *f, Class c)
{
	Section s;

	for (s = c->exports; s; s = s->next) {
		if (s->decl) {
			switch (s->decl->tp) {
				case Var: declare_export_var(f, s); break;
				case Def: define_macro(f, c, s->decl); break;
				case Proc: declare_function(1, s->decl->name,
					s->decl, f); break;
				case Type: declare_export_type(f, s); break;
				case Incl:
					fprintf(f, "#include %s\n",
						get(s->decl->name));
					break;
				case Undefined: break;
				case Trans: break;
			}
		}
	}
}

void public_header(FILE *f, Class c, char *prefix, char *guard)
{
	wbuild_comment(f);
	fprintf(f, "#ifndef %s\n", guard);
	fprintf(f, "#define %s\n", guard);
	public_include(f, c, prefix, "");
	fputs("_XFUNCPROTOBEGIN\n", f);
	declare_exports(f, c);
	define_resource_symbols(f, c);
	define_constraint_resource_symbols(f, c);
	typedef_class_instance(f, c);
	fputs("_XFUNCPROTOEND\n", f);
	fprintf(f, "#endif /* %s */\n", guard);
}

/* Private header file. The private header file has an even more strict
 * layout than the public header file. It contains an external declaration
 * for the class record and four typedefs: the class part, the complete
 * class record, the instance part and the complete instance record.
 */


/* The private header file needs two includes, for the private header
 * of the superclass (if any) and for the public header of the class
 * itself.
 */

#if 0
inline static generate_private_includes(FILE *f, Class c)
{
	if (c->superclass == CORE)
		fputs("#include <X11/CoreP.h>\n", f);
	else if (c->superclass == RECTOBJ)
		fputs("#include <X11/RectObjP.h>\n", f);
	else if (c->superclass == OBJECT)
		fputs("#include <X11/ObjectP.h>\n", f);
	else if (c->superclass == COMPOSITE)
		fputs("#include <X11/CompositeP.h>\n", f);
	else if (c->superclass == SHELL
		|| c->superclass == OVERRIDESHELL
		|| c->superclass == WMSHELL
		|| c->superclass == VENDORSHELL
		|| c->superclass == TRANSIENTSHELL
		|| c->superclass == TOPLEVELSHELL
		|| c->superclass == APPLICATIONSHELL)
		fputs("#include <X11/ShellP.h>\n", f);
	else if (c->superclass == CONSTRAINT)
		fputs("#include <X11/ConstrainP.h>\n", f);
	else if (c->superclass == XMPRIMITIVE || c->superclass == PRIMITIVE)
		fputs("#include <Xm/PrimitiveP.h>\n", f);
	else if (c->superclass == XMMANAGER || c->superclass == MANAGER)
		fputs("#include <Xm/ManagerP.h>\n", f);
	else if (c->super) {
		char *p, *q = get(c->superclass);
		if ((p = strrchr(q, '/'))) {
		*p = '\0';
		fprintf(f, "#include <%s>\n",
			get(get_headerPname(q, c->super)));
		*p = '/';
	} else {
		fprintf(f, "#include <%s>\n",
			get(get_headerPname(prefix, c->super)));
	}
  }
  fprintf(f, "#include <%s>\n", get(get_headername(prefix, c)));
#endif

/* There may be macro definitions in the public, private, constraint
 * and classvar sections. These macros are collected at the start if the
 * private include file, because they should be available to subclasses,
 * but not to others.
 *
 * The macro definitions are collected by scanning throught the public,
 * private and class variables sections.
 */

inline static void generate_macro_loop(FILE *f, Class c, Section s)
{
	while (s) {
		if ((s->decl) && (s->decl->tp == Def))
			define_macro(f, c, s->decl);
		s = s->next;
	}
}

inline static void generate_macro(FILE *f, Class c)
{
	generate_macro_loop(f, c, c->classvars);
	generate_macro_loop(f, c, c->privatevars);
	generate_macro_loop(f, c, c->publicvars);
	generate_macro_loop(f, c, c->constraints);
	generate_macro_loop(f, c, c->privconstr);
}

/* Similarly, the type definitions are collected. But in the public
 * section there can be no type definitions, so only the private and
 * class var sections are scanned.
 */

static inline void generate_typedefs(FILE *f, Class c)
{
	Section s;

	for (s = c->classvars; s; s = s->next)
		if ((s->decl) && (s->decl->tp == Type))
			fprintf(f, "typedef %s %s;\n",
				get(s->decl->type), get(s->decl->name));
	for (s = c->privatevars; s; s = s->next)
		if ((s->decl) && (s->decl->tp == Type))
			fprintf(f, "typedef %s %s;\n",
				get(s->decl->type), get(s->decl->name));
}

/* Methods that are new in this widget have to have a symbolic constant
 * |XtInherit*|. Subclasses will then be able to inherit the method (simply by
 * not redefining it). Resolving inheritance is done by a method
 * |class_part_initialize| in normal widgets, but in widgets generated
 * with wbuild the inheritance is done automatically. However, if there
 * is a |class_part_initialize| method defined in the specification file,
 * the automatic inheritance will not be used.
 * (See~\ref{resolve-inheritance})
 *
 * If the name of the method started with a \$ (|class_id = DOLLAR|), it
 * is considered a new method, whether or not it has the same name as a
 * method in a superclass. If the name of the method started with
 * |$(class)|, it is considered an inherited method.
 */

inline static void generate_inherit_defines(FILE *f, Class c)
{
	Section s;
	Decl d1;

	for (s = c->methods; s; s = s->next) {
		if (!s->decl || s->decl->tp != Proc)
			/* No decl in this section */
			continue;
		if (s->decl->class_id && s->decl->class_id != DOLLAR) 
			/* Inherited method */
			continue;
		if (!s->decl->class_id
				&& find_method_class(c, s->decl->name) != c)
			/* Inherited method */
			continue;
		fprintf(f, "typedef %s (*%s_Proc)(\n",
			s->decl->type ? get(s->decl->type) : "void",
			get(s->decl->name));
		fprintf(f, "#if NeedFunctionPrototypes\n");
		if (s->decl->params == NULL) {
			fputs("void", f);
		} else {
			for (d1 = s->decl->params; d1; d1 = d1->next) {
				if (d1->name == DOLLAR)
					fputs("Widget", f);
				else
					fputS(d1->type, f);
				if (d1->suffix)
					/* An array? */
					fprintf(f, " %s%s", get(d1->name),
						get(d1->suffix));
				if (d1->next)
					putc(',', f);
			}
		}
		fprintf(f, "\n#endif\n);\n");
		fprintf(f, "#define XtInherit_%s ((%s_Proc) _XtInherit)\n",
		get(s->decl->name), get(s->decl->name));
	}
}

/* The constraint part contains the constraint resources of the
 * widget. This part is only gegerated if the widget is a subclass of
 * Constraint.
 *
 * The macros defined in this section are simply interleaved with the
 * variable declarations. The C preprocessor will know how to deal with
 * them.
 *
 * Only fields which are new in this class are declared. The names of the
 * variables are searched for in superclasses first. If the name starts
 * with a \$, it is considered a new variable, regardless of the
 * existence of variables with the same name in superclasses.
 *
 * When the section has no variables, a dummy variable will be added.
 *
 * For some strange reason we print comments.  I don't know why--wbuild
 * output is quite unreadable.
 */

inline static void generate_constraint_part_record(FILE *f, Class c)
{
	int n;
	Section s;

	fprintf(f, "typedef struct {\n");
	n = 0;
	fprintf(f, "/* Constraint resources */\n");
	for (s = c->constraints; s; s = s->next) {
		if (s->decl && s->decl->tp == Var) {
			if (s->decl->class_id
				&& s->decl->class_id != DOLLAR)
				/* Inherited */
				continue;
			if (!s->decl->class_id
				&& find_constr_class(c,s->decl->name) != c)
				/* Inherited */
				continue;
			fprintf(f, "%s %s", get(s->decl->type),
				get(s->decl->name));
			if (s->decl->suffix)
				fputS(s->decl->suffix, f);
			fputs(";\n", f);
			n++;
		}
	}
	fprintf(f, "/* Private constraint variables */\n");
	for (s = c->privconstr; s; s = s->next) {
		if (s->decl == NULL)
			continue;
		if (s->decl->tp == Var) {
			if (s->decl->class_id && (s->decl->class_id != DOLLAR))
				/* Inherited */
				continue;
			if (!s->decl->class_id
				&& find_constr_class(c,s->decl->name) != c)
				/* Inherited */
				continue;
			fprintf(f, "%s %s", get(s->decl->type), get(s->decl->name));
			if (s->decl->suffix)
				fputS(s->decl->suffix, f);
			fputs(";\n", f);
			n++;
		}
	}
	if (n == 0)
		fprintf(f, "int dummy;\n");
	fprintf(f, "} %sConstraintPart;\n\n", get(c->name));
}

inline static void declare_super_constraint_parts(FILE *f, Class c)
{
	if (c != NULL) {
		if (c->super && c->superclass != CONSTRAINT)
			declare_super_constraint_parts(f, c->super);
		fprintf(f, "%sConstraintPart %s;\n",
			get(c->name), get(get_instname(c->name)));
	}
}

inline static void generate_constraint_rec(FILE *f, Class c)
{
	fprintf(f, "typedef struct _%sConstraintRec {\n", get(c->name));
	declare_super_constraint_parts(f, c);
	fprintf(f, "} %sConstraintRec;\n\n", get(c->name));
}

/* The class part structure contains the class variables that are
 * introduced in this widget. It also contains the new methods. If there
 * are no class variables or methods (|n| = 0), a dummy variable is added.
 *
 * If the name of the variable starts with |$|, it is declared without
 * checking for variables of the same name in superclasses. The field
 * |class_id| has been set to |DOLLAR| by the parser to enforce this. If
 * the name starts with |$(class)|, it is an inherited variable and
 * should not be declared here.
 *
 * There may be macro and type definitions interleaved with the class
 * variables. They have already been generated, so they can be skipped
 * here.
 */

inline static void generate_class_part_rec(FILE *f, Class c)
{
	int n;
	Section s;

	n = 0;
	fprintf(f, "\ntypedef struct {\n/* methods */\n");
	for (s = c->methods; s; s = s->next) {
		if (s->decl && (s->decl->tp == Proc)) {
			if (s->decl->class_id
				&& s->decl->class_id != DOLLAR)
				/* Inherited */
				continue;
			if (!s->decl->class_id
				&& find_method_class(c, s->decl->name) != c)
				/* Inherited */
				continue;
			fprintf(f, "%s_Proc %s;\n",
				get(s->decl->name), get(s->decl->name));
			n++;
		}
	}
	fprintf(f, "/* class variables */\n");
	for (s = c->classvars; s; s = s->next) {
		if (s->decl && (s->decl->tp)) {
			if (s->decl->class_id
				&& s->decl->class_id != DOLLAR)
				/* Inherited */
				continue;
			if (!s->decl->class_id
				&& find_classvar_class(c,s->decl->name)!=c)
				/* Inherited */
				continue;
			fprintf(f, "%s %s", get(s->decl->type),
				get(s->decl->name));
			if (s->decl->suffix)
				fputS(s->decl->suffix, f);
			fputs(";\n", f);
			n++;
		}
	}
	if (n == 0)
		fprintf(f, "int dummy;\n");
	fprintf(f, "} %sClassPart;\n", get(c->name));
}

/* The complete class record contains fields for all of the
 * superclasses. It is most easily created by a recursive procedure.
 *
 * The class parts for RectObj and Object are treated specially: (1) the
 * field will be called |object_class|, never |rectobj_class|; (2) Object
 * is not `really' a superclass of RectObj, so recursion stops at
 * RectObj.
 *
 * The configuration file makes sure that the RectObj class structure
 * defines nothing that is not already in Object, even if that means that
 * two methods that are defined in RectObj are now (incorrectly) added to
 * the Object class. This works as long as nobody tries to use those
 * methods in an Object.
 */

inline static void declare_superclassparts(FILE *f, Class c)
{
	if (!c)
		return;
	if (c->name == OBJECT || c->name == RECTOBJ) {
		fprintf(f, "%sClassPart object_class;\n", get(c->name));
	} else {
		declare_superclassparts(f, c->super);
		fprintf(f, "%sClassPart %s_class;\n", get(c->name),
		get(get_instname(c->name)));
	}
}

inline static void generate_class_rec(FILE *f, Class c)
{
	fprintf(f, "\ntypedef struct _%sClassRec {\n", get(c->name));
	declare_superclassparts(f, c);
	fprintf(f, "} %sClassRec;\n\n", get(c->name));
}

/* The instance part contains the resources and private variables of the
 * widget. The resources come first, as is the convention.
 *
 * The macros defined in the public and private sections are simply
 * interleaved with the variable declarations. The C preprocessor will
 * know how to deal with them.
 *
 * Only fields which are new in this class are declared. The names of the
 * variables are searched for in superclasses first. If the name starts
 * with a \$, it is considered a new variable, regardless of the
 * existence of variables with the same name in superclasses.
 *
 * When neither the public division nor the private division holds any
 * variables, a dummy variable will be added.
 */

inline static void generate_instance_part_rec(FILE *f, Class c)
{
	int n;
	Section s;

	fprintf(f, "typedef struct {\n");
	n = 0;
	fprintf(f, "/* resources */\n");
	for (s = c->publicvars; s; s = s->next) {
		if (s->decl && (s->decl->tp == Var)) {
			if (s->decl->class_id
				&& s->decl->class_id != DOLLAR)
				/* Inherited */
				continue;
			if (!s->decl->class_id
				&& find_instvar_class(c, s->decl->name) != c)
				/* Inherited */
				continue;
			fprintf(f, "%s %s", get(s->decl->type),
				get(s->decl->name));
			if (s->decl->suffix)
				fputS(s->decl->suffix, f);
			fputs(";\n", f);
			n++;
		}
	}
	fprintf(f, "/* private state */\n");
	for (s = c->privatevars; s; s = s->next) {
		if (s->decl && (s->decl->tp == Var)) {
			if (s->decl->class_id
				&& s->decl->class_id != DOLLAR)
				/* Inherited */
				continue;
			if (!s->decl->class_id
				&& find_instvar_class(c,s->decl->name) != c)
				/* Inherited */
				continue;
			if (!s->decl->type) {
				nerrors++;
				fprintf(stderr,
					_("%s:%d: Missing type for `%s'\n"),
					get(c->filename), s->decl->lineno,
					get(s->decl->name));
				continue;
			}
			fprintf(f, "%s %s", get(s->decl->type),
				get(s->decl->name));
			if (s->decl->suffix)
				fputS(s->decl->suffix, f);
			fputs(";\n", f);
			n++;
		}
	}
	if (n == 0)
		fprintf(f, "int dummy;\n");
	fprintf(f, "} %sPart;\n\n", get(c->name));
}

inline static void declare_superparts(FILE *f, Class c)
{
	if (!c)
		return;
	if (c->super)
		declare_superparts(f, c->super);
	fprintf(f, "%sPart %s;\n",
	get(c->name), get(get_instname(c->name)));
}

inline static void generate_complete_instance_part_rec(FILE *f, Class c)
{
	fprintf(f, "typedef struct _%sRec {\n", get(c->name));
	declare_superparts(f, c);
	fprintf(f, "} %sRec;\n\n", get(c->name));
}

inline static void generate_extern_decl_class_rec(FILE *f, Class c)
{
	fprintf(f, "externalref %sClassRec %sClassRec;\n\n",
		get(c->name), get(get_instname(c->name)));
}

void generate_private_header(FILE *f, Class c, char *prefix, char *guard)
{
	wbuild_comment(f);
	fprintf(f, "#ifndef %s\n", guard);
	fprintf(f, "#define %s\n", guard);
	public_include(f, c, prefix, "P");
	fprintf(f, "#include <%s/%s.h>\n", prefix,
		get(c->filenamepart ? c->filenamepart : c->name));
	fputs("_XFUNCPROTOBEGIN\n", f);
	generate_macro(f, c);
	generate_typedefs(f, c);
	generate_inherit_defines(f, c);
	if (find_superclass(c, CONSTRAINT) != NULL) {
		generate_constraint_part_record(f, c);
		generate_constraint_rec(f, c);
	}
	generate_class_part_rec(f, c);
	generate_class_rec(f, c);
	generate_instance_part_rec(f, c);
	generate_complete_instance_part_rec(f, c);
	generate_extern_decl_class_rec(f, c);
	fputs("_XFUNCPROTOEND\n", f);
	fprintf(f, "#endif /* %s */\n", guard);
}
