/*
 * Motif
 *
 * Copyright (c) 2025-2026 Tim Hentenaar
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
*/
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: wmlouth.c /main/8 1995/08/29 11:10:46 drk $"
#endif
#endif

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/**
 * This module contains routines responsible for writing the .h files
 * produced by WML. All files are written into the current directory.
 *
 * Input:
 *	The resolved objects
 *
 * Output:
 *	UilSymGen.h
 *	UilSymArTy.h
 *	UilSymChCl.h
 *	UilSymRArg.h
 *	UilUrmClas.h
 *	UilConst.h
 *	UilSymReas.h
 *	UilSymArTa.h
 *	UilSymChTa.h
 *	UilSymCtl.h
 *	UilSymNam.h
 *	UilSymEnum.h
 *	UilSymCSet.h
 */
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "wml.h"

/**
 * Routines used only in this module
 */
static void wmlOutputUilSymGen(void);
static void wmlOutputUilSymArTy(void);
static void wmlOutputUilSymChCl(void);
static void wmlOutputUilSymRArg(void);
static void wmlOutputUilUrmClas(void);
static void wmlOutputUilConst(void);
static void wmlOutputUilSymReas(void);
static void wmlOutputUilSymArTa(void);
static void wmlOutputUilSymChTa(void);
static void wmlOutputUilSymCtl(void);
static void wmlOutputUilSymNam(void);
static void wmlOutputUilSymEnum(void);
static void wmlOutputUilSymCSet(void);
static int wmlResolveCtlIsMember(WmlClassDefPtr, WmlClassCtrlDefPtr);

/**
 * globals
 */
static const char canned_warn[] =
"/*\n\
**\tThis file is automatically generated.  Do not edit it by hand.\n\
**/\n";

/**
 * Used to create masks for bytes in bit vectors. Accessed by bit numbers
 * from 1 - 8.
 */
static const char * const bit_masks[9] =
{
	"",
	" | 1",   /* bit 1 */
	" | 2",   /* bit 2 */
	" | 4",   /* bit 3 */
	" | 8",   /* bit 4 */
	" | 16",  /* bit 5 */
	" | 32",  /* bit 6 */
	" | 64",  /* bit 7 */
	" | 128"  /* bit 8 */
};

/**
 * To pick up maximum code values
 */
static int max_object_code  = 0;
static int max_reason_code  = 0;
static int max_arg_code     = 0;
static int max_enumset_code = 0;
static int max_enumval_code = 0;
static int max_charset_code = 0;
static int max_child_code   = 0;

/**
 * Output control routine, which simply outputs each .h file in turn.
 */
void wmlOutputHFiles(void)
{
	wmlOutputUilSymGen();
	wmlOutputUilSymArTy();
	wmlOutputUilSymChCl();
	wmlOutputUilSymRArg();
	wmlOutputUilUrmClas();
	wmlOutputUilConst();
	wmlOutputUilSymReas();
	wmlOutputUilSymArTa();
	wmlOutputUilSymChTa();
	wmlOutputUilSymCtl();
	wmlOutputUilSymNam();
	wmlOutputUilSymEnum();
	wmlOutputUilSymCSet();
}

/**
 * Routine to write out UilSymGen.h
 *
 * This file defines the sym_k... literals for UIL. Each set of literals
 * typiclly increases monotonically from 1, with 0 used as en error value.
 *
 *	sym_k_<class>_object
 *		<class> is widget class name in lexicographic order
 *		gadgets are not include.
 *
 *	bit masks for table access
 *
 *	sym_k_<reason>_reason
 *		literals specifying all reasons, lexicographically ordered
 *
 *	sym_k_<argument>_arg
 *		literals for all arguments, lexicographically ordered.
 *		Constraints are included, and ordered with the arguments.
 *
 *	sym_k_<child>_child
 *		literals for all automatic children, lexicographically ordered.
 *
 *	sym_k_<enumset>_enumset
 *		literals naming each enumeration set, lexicographically ordered
 *
 *	Fixed literals naming character set character sizes
 *	sym_k_<charset>_charset
 *		literals naming each character set, lexicographically ordered
 */
static void wmlOutputUilSymGen(void)
{
	static const char * const canned1 = "\n/*  Define literals for objects */\n";
	static const char * const canned3 = "\n/*  Define literals for reasons */\n\n";
	static const char * const canned4 = "\n/*  Define literals for arguments */\n\n";
	static const char * const canned5 = "\n/*  Define literals for enumeration sets */\n\n";
	static const char * const canned6 = "\n/*  Define literals for enumeration values */\n\n";
	static const char * const canned7 = "\n/*  Define literals for character sets */\n\n";
	static const char * const canned8 = "\n/*  Define literals for automatic children */\n\n";

	FILE *outfil;	               /* output file */
	int ndx;                       /* loop index */
	WmlClassDefPtr     clsobj;     /* class object */
	WmlResourceDefPtr  resobj;     /* resource object */
	WmlEnumSetDefPtr   enumsetobj; /* enumeration set object */
	WmlEnumValueDefPtr enumvalobj; /* enumeration value object */
	WmlCharSetDefPtr   charsetobj; /* character set object */
	WmlChildDefPtr     childobj;   /* child object */

	/**
	 * Open the output file. Write the canned header stuff
	 */
	if (!(outfil = fopen("UilSymGen.h", "w+"))) {
		fputs("Couldn't open UilSymGen.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);

	/**
	 * Write the sym_k..._object literals
	 */
	fputs(canned1, outfil);
	for (ndx=0; ndx < wml_obj_class_ptr->cnt; ndx++) {
		clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[ndx].objptr;
		fprintf(outfil, "#define sym_k_%s_object\t%d\n",
		        clsobj->tkname, clsobj->sym_code);
		if (clsobj->sym_code > max_object_code)
			max_object_code = clsobj->sym_code;
	}

	/**
	 * Define the sym_k_..._reason literals
	 */
	fputs(canned3, outfil);
	for (ndx=0; ndx < wml_obj_reason_ptr->cnt; ndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_reason_ptr->hvec[ndx].objptr;
		fprintf(outfil, "#define sym_k_%s_reason\t%d\n",
		        resobj->tkname, resobj->sym_code);
		if (resobj->sym_code > max_reason_code)
			max_reason_code = resobj->sym_code;
	}

	/**
	 * Define the sym_k_..._arg literals
	 */
	fputs(canned4, outfil);
	for (ndx=0; ndx < wml_obj_arg_ptr->cnt; ndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_arg_ptr->hvec[ndx].objptr;
		fprintf(outfil, "#define sym_k_%s_arg\t%d\n",
		        resobj->tkname, resobj->sym_code);
		if (resobj->sym_code > max_arg_code)
			max_arg_code = resobj->sym_code;
	}

	/**
	 * Define the sym_k_..._enumset structs and literals
	 */
	fputs(canned5, outfil);
	for (ndx=0; ndx < wml_obj_enumset_ptr->cnt; ndx++) {
		enumsetobj = (WmlEnumSetDefPtr)wml_obj_enumset_ptr->hvec[ndx].objptr;
		fprintf(outfil, "#define sym_k_%s_enumset\t%d\n",
		        enumsetobj->tkname, enumsetobj->sym_code);
		if (enumsetobj->sym_code > max_enumset_code)
			max_enumset_code = enumsetobj->sym_code;
	}

	/**
	 * Define the sym_k_..._enumval literals
	 */
	fputs(canned6, outfil);
	for (ndx=0; ndx < wml_obj_enumval_ptr->cnt; ndx++) {
		enumvalobj = (WmlEnumValueDefPtr)wml_obj_enumval_ptr->hvec[ndx].objptr;
		fprintf(outfil, "#define sym_k_%s_enumval\t%d\n",
		        enumvalobj->syndef->name, enumvalobj->sym_code);
		if (enumvalobj->sym_code > max_enumval_code)
			max_enumval_code = enumvalobj->sym_code;
	}

	/**
	 * Define the sym_k_..._charsize literals
	 * Define the sym_k_..._charset literals
	 */
	fputs(canned7, outfil);
	for (ndx=0 ; ndx < wml_obj_charset_ptr->cnt ; ndx++) {
		charsetobj = (WmlCharSetDefPtr) wml_obj_charset_ptr->hvec[ndx].objptr;
		fprintf(outfil, "#define sym_k_%s_charset\t%d\n",
		        charsetobj->syndef->name, charsetobj->sym_code);
		if (charsetobj->sym_code > max_charset_code)
			max_charset_code = charsetobj->sym_code;
	}

	/**
	 * Define the sym_k_..._child literals
	 */
	fputs(canned8, outfil);
	for (ndx=0 ; ndx < wml_obj_child_ptr->cnt ; ndx++) {
		childobj = (WmlChildDefPtr) wml_obj_child_ptr->hvec[ndx].objptr;
		fprintf(outfil, "#define sym_k_%s_child\t%d\n",
		        childobj->syndef->name, childobj->sym_code);
		if (childobj->sym_code > max_child_code)
			max_child_code = childobj->sym_code;
	}

	puts("Created UilSymGen.h");
	fclose(outfil);
}

/**
 * Routine to write out UilSymChCl.h
 *
 * A table of classes accessed by child type (sym_k_<child>_child, in
 * the form
 *	...
 *	sym_k_<class>_class,
 */
static void wmlOutputUilSymChCl(void)
{
static const char * const canned1 =
"/*  Table of the class type of children\n\
    The table is indexed by child with each entry the\n\
    permitted class for that child.\n\
*/\n\
\n\
static unsigned char child_class_table_vec[] =\n\
  {\n\
    0,\n";

static const char * const canned1a =
"  };\n\
externaldef(uil_sym_glbl) unsigned char *child_class_table =\n\
\t child_class_table_vec;\n";

	FILE *outfil;            /* output file */
	int ndx;                 /* loop index */
	WmlChildDefPtr childobj; /* resource object */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilSymChCl.h", "w+"))) {
		fputs("Couldn't open UilSymChCL.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);

	/**
	 * Create table entries, similar to writing sym_k...
	 */
	fputs(canned1, outfil);
	for (ndx=0; ndx < wml_obj_child_ptr->cnt; ndx++) {
		childobj = (WmlChildDefPtr)wml_obj_child_ptr->hvec[ndx].objptr;
		fprintf(outfil, "    sym_k_%s_object,\n", childobj->class->tkname);
	}

	fputs(canned1a, outfil);
	puts("Created UilSymChCl.h");
	fclose(outfil);
}

/**
 * Routine to write out UilSymArTy.h
 *
 * A table of data types accessed by argument type (sym_k_<arg>_arg, in
 * the form
 *	...
 *	sym_k_<data_type>_value,
 */
static void wmlOutputUilSymArTy(void)
{
static const char * const canned1 =
"/*  Table of the types of arguments\n\
    The table is indexed by argument with each entry the\n\
    permitted type for that argument.\n\
*/\n\
\n\
static unsigned char argument_type_table_vec[] =\n\
  {\n\
    0,\n";

static const char * const canned1a =
"  };\n\
externaldef(uil_sym_glbl) unsigned char *argument_type_table =\n\
\t argument_type_table_vec;\n";

	FILE *outfil;             /* output file */
	int ndx;                  /* loop index */
	WmlResourceDefPtr resobj; /* resource object */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilSymArTy.h", "w+"))) {
		fputs("Couldn't open UilSymArTy.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);

	/**
	 * Create table entries, similar to writing sym_k...
	 */
	fputs(canned1, outfil);
	for (ndx=0; ndx < wml_obj_arg_ptr->cnt; ndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_arg_ptr->hvec[ndx].objptr;
		fprintf(outfil, "    sym_k_%s_value,\n", resobj->dtype_def->tkname);
	}

	fputs(canned1a, outfil);
	puts("Created UilSymArTy.h");
	fclose(outfil);
}

/**
 * Routine to write out UilSymRArg.h
 *
 * Related argument table
 */
static void wmlOutputUilSymRArg(void)
{
static const char * const canned1 =
"/*	Related argument table. Each non-zero entry is the code\n\
	of the related argument.\n\
 */\n\
\n\
static unsigned short int related_argument_table_vec[] =\n\
  {\n\
    0,\n";

static const char * const canned1a =
"  };\n\
externaldef(uil_sym_glbl) unsigned short int *related_argument_table =\n\
\t\trelated_argument_table_vec;\n";

	FILE *outfil;             /* output file */
	int ndx;                  /* loop index */
	WmlResourceDefPtr resobj; /* resource object */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilSymRArg.h", "w+"))) {
		fputs("Couldn't open UilSymRArg.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);

	/**
	 * Create table entries, similar to writing sym_k...
	 */
	fputs(canned1, outfil);
	for (ndx=0; ndx < wml_obj_arg_ptr->cnt; ndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_arg_ptr->hvec[ndx].objptr;
		fprintf(outfil, "    %d,\n", resobj->related_code);
	}

	fputs(canned1a, outfil);
	puts("Created UilSymRArg.h");
	fclose(outfil);
}

/**
 * Routine to write out UilUrmClas.h
 *
 * Table of convenience function names indexed by the sym_k_<class> literal
 *	for both widgets and gadgets
 * Table of resource names indexed by the sym_k_<argument>_arg and
 *	sym_k_<reason>_reason codes.
 */
static void wmlOutputUilUrmClas(void)
{
static const char * const canned1 =
"\n/*  Define mapping of UIL widget types to convenience functions.  */\n\
static char *uil_widget_funcs_vec[] = {\n\
  \"\",\t  /* NOT USED */\n";

static const char * const canned2 =
"};\n\
externaldef(uil_sym_glbl) char **uil_widget_funcs = uil_widget_funcs_vec;\n\
\n\
/*  Define mapping of UIL widget classes to matching gadget class.  */\n\
static unsigned short int uil_gadget_variants_vec[] = {\n\
  0,\t  /* NOT USED */\n";

static const char * const canned3 =
"};\n\
externaldef(uil_sym_glbl) unsigned short int *uil_gadget_variants =\n\
\t\tuil_gadget_variants_vec;\n\
\n\
/*  Define mapping of dialog types to non-dialog URM widget classes.  */\n\
static unsigned short int uil_urm_nondialog_class_vec[] = {\n\
  0,\t/* NOT USED */\n";

static const char * const canned4 =
"};\n\
externaldef(uil_sym_glbl) unsigned short int *uil_urm_nondialog_class =\n\
\t\tuil_urm_nondialog_class_vec;\n\
\n\
/*  Define mapping of widget controls to a (subtree) resource.  */\n\
static unsigned short int uil_urm_subtree_resource_vec[] = {\n\
  0,\t/* NOT USED */\n";

static const char * const canned5 =
"};\n\
externaldef(uil_sym_glbl) unsigned short int *uil_urm_subtree_resource =\n\
\t\tuil_urm_subtree_resource_vec;\n\
\n\
/*  Define mapping of arguments to toolkit names.  */\n\
static char *uil_argument_toolkit_names_vec[] = {\n\
  \"\",\t  /* NOT USED */\n";

static const char * const canned6 =
"};\n\
externaldef(uil_sym_glbl) char **uil_argument_toolkit_names =\n\
\t\tuil_argument_toolkit_names_vec;\n\
\n\
/*  Define mapping of reasons to toolkit names.  */\n\
static char *uil_reason_toolkit_names_vec[] = {\n\
  \"\",\t/* NOT USED */\n";

static const char * const canned7 =
"};\n\
externaldef(uil_sym_glbl) char **uil_reason_toolkit_names =\n\
\t\tuil_reason_toolkit_names_vec;\n";

	FILE *outfil;             /* output file */
	int ndx;                  /* loop index */
	WmlClassDefPtr    clsobj; /* class object */
	WmlResourceDefPtr resobj; /* argument/reason object */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilUrmClas.h", "w+"))) {
		fputs("Couldn't open UilUrmClas.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);

	/**
	 * Write entries for widgets
	 */
	fputs(canned1, outfil);
	for (ndx=0; ndx < wml_obj_class_ptr->cnt; ndx++) {
		clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[ndx].objptr;
		if (!clsobj->sym_code)
			continue;

		fprintf(outfil, clsobj->syndef->int_lit
		        ? "  \"%s\",\n" : "  \"%s\",\t\n",
		        clsobj->syndef->convfunc);
	}
	fputs(canned2, outfil);

	/**
	 * Write entries for gadget variants of widget classes
	 */
	for (ndx=0; ndx < wml_obj_class_ptr->cnt; ndx++) {
		clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[ndx].objptr;
		if (!clsobj->sym_code)
			continue;

		if (!clsobj->variant || clsobj->syndef->type == WmlClassTypeGadget) {
			fputs("  0,\n", outfil);
			continue;
		}

		fprintf(outfil, "  sym_k_%s_object,\n",
		        clsobj->variant->syndef->int_lit
		        ? clsobj->variant->syndef->int_lit
		        : clsobj->variant->syndef->name);
	}
	fputs(canned3, outfil);

	/*
	 * Write entries for non-dialog widgets
	 */
	for (ndx=0; ndx < wml_obj_class_ptr->cnt; ndx++) {
		clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[ndx].objptr;
		if (!clsobj->sym_code)
			continue;

		if (!clsobj->nondialog) {
			fputs("  0,\n", outfil);
			continue;
		}

		fprintf(outfil, "  sym_k_%s_object,\n",
		        clsobj->nondialog->syndef->int_lit
		        ? clsobj->nondialog->syndef->int_lit
		        : clsobj->nondialog->syndef->name);
	}
	fputs(canned4, outfil);

	/**
	 * Write entries for the resource a widget's controls map to
	 */
	for (ndx=0; ndx < wml_obj_class_ptr->cnt; ndx++) {
		clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[ndx].objptr;
		if (!clsobj->sym_code)
			continue;

		if (!clsobj->ctrlmapto) {
			fputs("  0,\n", outfil);
			continue;
		}

		fprintf(outfil, "  sym_k_%s_arg,\n", clsobj->ctrlmapto->tkname);
	}
	fputs(canned5, outfil);

	/**
	 * Write entries for arguments
	 */
	for (ndx=0; ndx < wml_obj_arg_ptr->cnt; ndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_arg_ptr->hvec[ndx].objptr;
		if (resobj->sym_code)
			fprintf(outfil, "  %s,\n", resobj->syndef->resliteral);
	}
	fputs(canned6, outfil);

	/**
	 * Write entries for reasons
	 */
	for (ndx=0; ndx < wml_obj_reason_ptr->cnt; ndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_reason_ptr->hvec[ndx].objptr;
		if (resobj->sym_code)
			fprintf(outfil, "  %s,\n", resobj->syndef->resliteral);
	}

	fputs(canned7, outfil);
	puts("Created UilUrmClas.h");
	fclose(outfil);
}

/**
 * Routine to write out UilConst.h
 *
 * A bit vector showing which arguments are constraints.
 */
static void wmlOutputUilConst(void)
{
static const char * const canned1 =
"/* Table indexed by argument indicating whether\n\
   argument is a constraint (TRUE) or a regular\n\
   argument (FALSE).  Each entry is one bit.\n\
   Index and mask macros are defined to simplify\n\
   access to the table\n\
*/\n\
\n\
static unsigned char constraint_tab_vec[] = {\n";

static const char * const canned1a =
"};\n\
externaldef(uil_sym_glbl) unsigned char *constraint_tab =\n\
\t\tconstraint_tab_vec;\n";

	FILE *outfil;             /* output file */
	int ndx;                  /* loop index */
	char maskbuf[100];        /* to constuct each mask */
	int bitno = 0;            /* current bit number, from code */
	WmlResourceDefPtr resobj; /* resource object */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilConst.h", "w+"))) {
		fputs("Couldn't open UilConst.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);

	/**
	 * Process the arguments in code order. We start with 1, and write out
	 * the mask after processing 8 codes.
	 */
	fputs(canned1, outfil);
	maskbuf[0] = '0';
	maskbuf[1] = '\0';

	for (ndx=0; ndx < wml_obj_arg_ptr->cnt; ndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_arg_ptr->hvec[ndx].objptr;
		if (!(bitno = resobj->sym_code & 7)) bitno = 8;
		if (resobj->syndef->type == WmlResourceTypeConstraint)
			strcat(maskbuf, bit_masks[bitno]);

		if (bitno < 8)
			continue;
		fprintf(outfil, "%s,\n", maskbuf);
		maskbuf[0] = '0';
		maskbuf[1] = '\0';
	}

	if (bitno != 8)
		fputs(maskbuf, outfil);
	fputs(canned1a, outfil);
	puts("Created UilConst.h");
	fclose(outfil);
}

/**
 * Routine to write out UilSymReas.h
 *
 * This file defines the reasons supported by each class. For each
 * reason, there is a bit vector with the bit for each supporting class
 * turned on if the reason is supported. There is then a vector pointing
 * to these bit vectors for all reasons. This vector is accessed by
 * sym_k_..._reason to find the reasons bit vector, then by sym_k_..._object
 * to check the bit.
 */
static void wmlOutputUilSymReas(void)
{
static const char * const canned1 =
"\n/*\n\
 * Bit vectors for each reason. The entries in the vector correspond\n\
 * to each class.\n\
 */\n";

static const char * const bvechdr =
"\n\
/* sym_k_%s_reason */\n\
static unsigned char reason_class_vec%d[] =\n\
  {\n";

static const char * const canned2 =
"\n/*\n\
 * Table of bit vectors accessed by sym_k_..._reason\n\
 */\n\
static unsigned char *allowed_reason_table_vec[] =\n\
  {\n\
  NULL,\t/* UNUSED */\n";

static const char * const canned3 =
"  };\n\
externaldef(uil_sym_glbl) unsigned char **allowed_reason_table =\n\
\t\tallowed_reason_table_vec;\n";

	FILE *outfil;             /* output file */
	int resndx;               /* outer loop index */
	int clsndx;               /* inner loop index */
	WmlResourceDefPtr resobj; /* current reason */
	WmlClassDefPtr clsobj;    /* current class object */
	WmlClassResDefPtr resref; /* class' resource reference */
	int itemno = 0;           /* item in byte */
	char maskbuf[500];        /* current mask buffer */
	char itembuf[100];        /* for current item */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilSymReas.h", "w+"))) {
		fputs("Couldn't open UilSymReas.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);
	fputs(canned1, outfil);

	/**
	 * Generate the bit vectors for each class. Outer loop on the reason node,
	 * inner loop on the class node.
	 */
	for (resndx = 0; resndx < wml_obj_reason_ptr->cnt; resndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_reason_ptr->hvec[resndx].objptr;
		fprintf(outfil, bvechdr, resobj->tkname, resobj->sym_code);
		maskbuf[0] = ' ';
		maskbuf[1] = '\0';

		/**
		 * inner loop on widget class.
		 */
		for (clsndx = 0; clsndx < wml_obj_class_ptr->cnt; clsndx++) {
			clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[clsndx].objptr;
			itemno = (clsobj->sym_code + 1) & 7;
			if ((resref = wmlResolveResIsMember(resobj, clsobj->reasons))) {
				if (resref->exclude != WmlAttributeTrue) {
					snprintf(itembuf, sizeof itembuf,
					         " _BIT_MASK(sym_k_%s_object) |", clsobj->tkname);
					assert(sizeof maskbuf >= strlen(maskbuf) + strlen(itembuf) + 3);
					strcat(maskbuf, itembuf);
					strcat(maskbuf, "\n ");
				}
			}

			if (!itemno) {
				fputs(maskbuf, outfil);
				fputs(" 0", outfil);
				maskbuf[0] = ',';
				maskbuf[1] = '\0';
			}
		}

		fprintf(outfil, itemno ? "%s 0};\n" : "};\n", maskbuf);
	}

	/**
	 * Write the vector of vectors.
	 */
	fputs(canned2, outfil);
	for (resndx = 0; resndx < wml_obj_reason_ptr->cnt; resndx++) {
		fprintf(outfil, "  reason_class_vec%d,\n",
		        ((WmlResourceDefPtr)wml_obj_reason_ptr->hvec[resndx].objptr)->sym_code);
	}
	fputs(canned3, outfil);

	/* close the output file */
	puts("Created UilSymReas.h");
	fclose(outfil);
}

/**
 * Routine to write out UilSymArTa.h
 *
 * This file defines the arguments supported by each class. For each
 * argument, there is a bit vector with the bit for each supporting class
 * turned on if the argument is supported. There is then a vector pointing
 * to these bit vectors for all arguments. This vector is accessed by
 * sym_k_..._arg to find the arguments bit vector, then by sym_k_..._object
 * to check the bit.
 */
static void wmlOutputUilSymArTa(void)
{
static const char * const canned1 =
"\n/*\n\
 * Bit vectors for each argument. The entries in the vector correspond\n\
 * to each class.\n\
 */\n";

static const char * const bvechdr =
"\n\
/* sym_k_%s_arg */\n\
static unsigned char arg_class_vec%d[] =\n\
  {\n";

static const char * const canned2 =
"\n/*\n\
 * Table of bit vectors accessed by sym_k_..._arg\n\
 */\n\
static unsigned char *allowed_argument_table_vec[] =\n\
  {\n\
  NULL,\t/* UNUSED */\n";

static const char * const canned3 =
"  };\n\
externaldef(uil_sym_glbl) unsigned char **allowed_argument_table =\n\
\t\tallowed_argument_table_vec;\n";

	FILE *outfil;             /* output file */
	int resndx;               /* outer loop index */
	int clsndx;               /* inner loop index */
	WmlResourceDefPtr resobj; /* current argument */
	WmlClassDefPtr clsobj;    /* current class object */
	WmlClassResDefPtr resref; /* class' resource reference */
	int itemno = 0;           /* item in byte */
	char maskbuf[500];        /* current mask buffer */
	char itembuf[100];        /* for current item */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilSymArTa.h", "w+"))) {
		fputs("Couldn't open UilSymArTa.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);
	fputs(canned1, outfil);

	/**
	 * Generate the bit vectors for each class. Outer loop on the argument node,
	 * inner loop on the class code.
	 */
	for (resndx = 0; resndx < wml_obj_arg_ptr->cnt; resndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_arg_ptr->hvec[resndx].objptr;
		fprintf(outfil, bvechdr, resobj->tkname, resobj->sym_code);
		maskbuf[0] = ' ';
		maskbuf[1] = '\0';

		/**
		 * inner loop on widget class.
		 */
		for (clsndx = 0; clsndx < wml_obj_class_ptr->cnt; clsndx++) {
			clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[clsndx].objptr;
			itemno = (clsobj->sym_code + 1) & 7;
			if ((resref = wmlResolveResIsMember(resobj, clsobj->arguments))) {
				if (resref->exclude != WmlAttributeTrue) {
					snprintf(itembuf, sizeof itembuf,
					         " _BIT_MASK(sym_k_%s_object) |", clsobj->tkname);
					assert(sizeof maskbuf >= strlen(maskbuf) + strlen(itembuf) + 3);
					strcat(maskbuf, itembuf);
					strcat(maskbuf, "\n ");
				}
			}

			if (!itemno) {
				fputs(maskbuf, outfil);
				fputs(" 0", outfil);
				maskbuf[0] = ',';
				maskbuf[1] = '\0';
			}
		}

		fprintf(outfil, itemno ? "%s 0};\n" : "};\n", maskbuf);
	}

	/**
	 * Write the vector of vectors.
	 */
	fputs(canned2, outfil);
	for (resndx = 0; resndx < wml_obj_arg_ptr->cnt; resndx++) {
		fprintf(outfil, "  arg_class_vec%d,\n",
		        ((WmlResourceDefPtr)wml_obj_arg_ptr->hvec[resndx].objptr)->sym_code);
	}
	fputs(canned3, outfil);

	/* close the input file */
	puts("Created UilSymArTa.h");
	fclose(outfil);
}

/**
 * Routine to write out UilSymChTa.h
 *
 * This file defines the automatic children supported by each class. For each
 * child, there is a bit vector with the bit for each supporting class
 * turned on if the child is supported. There is then a vector pointing
 * to these bit vectors for all children. This vector is accessed by
 * sym_k_..._child to find the child's bit vector, then by sym_k_..._object
 * to check the bit.
 */
static void wmlOutputUilSymChTa(void)
{
static const char * const canned1 =
"\n/*\n\
 * Bit vectors for each child. The entries in the vector correspond\n\
 * to each class.\n\
 */\n";

static const char * const bvechdr =
"\n\
/* sym_k_%s_child */\n\
static unsigned char child_class_vec%d[] =\n\
  {\n";

static const char * const canned2 =
"\n/*\n\
 * Table of bit vectors accessed by sym_k_..._child\n\
 */\n\
static unsigned char *allowed_child_table_vec[] =\n\
  {\n\
  NULL,\t/* UNUSED */\n";

static const char * const canned3 =
"  };\n\
externaldef(uil_sym_glbl) unsigned char **allowed_child_table =\n\
\t\tallowed_child_table_vec;\n";

	FILE *outfil;                 /* output file */
	int childndx;                 /* outer loop index */
	int clsndx;                   /* inner loop index */
	WmlChildDefPtr childobj;      /* current child */
	WmlClassDefPtr clsobj;        /* current class object */
	WmlClassChildDefPtr childref; /* class' child reference */
	int itemno = 0;               /* item in byte */
	char maskbuf[500];            /* current mask buffer */
	char itembuf[100];            /* for current item */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilSymChTa.h", "w+"))) {
		fputs("Couldn't open UilSymChTa.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);
	fputs(canned1, outfil);

	/**
	 * Generate the bit vectors for each class. Outer loop on the child node,
	 * inner loop on the class code.
	 */
	for (childndx = 0; childndx < wml_obj_child_ptr->cnt; childndx++) {
		childobj = (WmlChildDefPtr)wml_obj_child_ptr->hvec[childndx].objptr;
		fprintf(outfil, bvechdr, childobj->tkname, childobj->sym_code);
		maskbuf[0] = ' ';
		maskbuf[1] = '\0';

		/**
		 * inner loop on widget class.
		 */
		for (clsndx = 0; clsndx < wml_obj_class_ptr->cnt; clsndx++) {
			clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[clsndx].objptr;
			itemno = (clsobj->sym_code + 1) & 7;
			if ((childref = wmlResolveChildIsMember(childobj, clsobj->children))) {
				snprintf(itembuf, sizeof itembuf,
					     " _BIT_MASK(sym_k_%s_object) |", clsobj->tkname);
				assert(sizeof maskbuf >= strlen(maskbuf) + strlen(itembuf) + 3);
				strcat(maskbuf, itembuf);
				strcat(maskbuf, "\n ");
			}

			if (!itemno) {
				fputs(maskbuf, outfil);
				fputs(" 0", outfil);
				maskbuf[0] = ',';
				maskbuf[1] = '\0';
			}
		}

		fprintf(outfil, itemno ? "%s 0};\n" : "};\n", maskbuf);
	}

	/**
	 * Write the vector of vectors.
	 */
	fputs(canned2, outfil);
	for (childndx = 0; childndx < wml_obj_child_ptr->cnt; childndx++) {
		fprintf(outfil, "  child_class_vec%d,\n",
		        ((WmlChildDefPtr)wml_obj_child_ptr->hvec[childndx].objptr)->sym_code);
	}
	fputs(canned3, outfil);

	/* close the input file */
	puts("Created UilSymChTa.h");
	fclose(outfil);
}

/**
 * Routine to write out UilSymCtl.h
 *
 * This file defines the controls supported by each class. For each
 * object, there is a bit vector with the bit for each supporting class
 * turned on if the object is supported. There is then a vector pointing
 * to these bit vectors for all objects. This vector is accessed by
 * sym_k_..._object to find the objects bit vector, then by sym_k_..._object
 * to check the bit.
 */
static void wmlOutputUilSymCtl(void)
{
static const char * const canned1 =
"\n/*\n\
 * Bit vectors for each control. The entries in the vector correspond\n\
 * to each class.\n\
 */\n";

static const char * const bvechdr =
"\n\
/* sym_k_%s_object */\n\
static unsigned char object_class_vec%d[] =\n\
  {\n";

static const char * const canned2 =
"\n/*\n\
 * Table of bit vectors accessed by sym_k_..._object\n\
 */\n\
static unsigned char *allowed_control_table_vec[] =\n\
  {\n\
  NULL,\t/* UNUSED */\n";

static const char * const canned3 =
"  };\n\
externaldef(uil_sym_glbl) unsigned char **allowed_control_table =\n\
\t\tallowed_control_table_vec;\n";

	FILE *outfil;          /* output file */
	int ctlndx;            /* outer loop index */
	int clsndx;            /* inner loop index */
	WmlClassDefPtr ctlobj; /* current class allowing controls */
	WmlClassDefPtr clsobj; /* current class object */
	int itemno = 0;        /* item in byte */
	char maskbuf[500];     /* current mask buffer */
	char itembuf[100];     /* for current item */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilSymCtl.h", "w+"))) {
		fputs("Couldn't open UilSymCtl.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);
	fputs(canned1, outfil);

	/**
	 * Generate the bit vectors for each class. Outer loop on the class node,
	 * inner loop on the class code.
	 */
	for (ctlndx = 0; ctlndx < wml_obj_class_ptr->cnt; ctlndx++) {
		clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[ctlndx].objptr;
		fprintf(outfil, bvechdr, clsobj->tkname, clsobj->sym_code);
		maskbuf[0] = ' ';
		maskbuf[1] = '\0';

		/**
		 * inner loop on widget class.
		 */
		for (clsndx = 0; clsndx < wml_obj_class_ptr->cnt; clsndx++) {
			ctlobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[clsndx].objptr;
			itemno = (ctlobj->sym_code + 1) & 7;
			if (wmlResolveCtlIsMember(clsobj, ctlobj->controls)) {
				snprintf(itembuf, sizeof itembuf,
					     " _BIT_MASK(sym_k_%s_object) |", ctlobj->tkname);
				assert(sizeof maskbuf >= strlen(maskbuf) + strlen(itembuf) + 3);
				strcat(maskbuf, itembuf);
				strcat(maskbuf, "\n ");
			}

			if (!itemno) {
				fputs(maskbuf, outfil);
				fputs(" 0", outfil);
				maskbuf[0] = ',';
				maskbuf[1] = '\0';
			}
		}

		fprintf(outfil, itemno ? "%s 0};\n" : "};\n", maskbuf);
	}

	/**
	 * Write the vector of vectors.
	 */
	fputs(canned2, outfil);
	for (ctlndx = 0; ctlndx < wml_obj_class_ptr->cnt; ctlndx++) {
		fprintf(outfil, "  object_class_vec%d,\n",
		        ((WmlClassDefPtr)wml_obj_class_ptr->hvec[ctlndx].objptr)->sym_code);
	}
	fputs(canned3, outfil);

	/* close the input file */
	puts("Created UilSymCtl.h");
	fclose(outfil);
}

/**
 * Predicate to indicate if a class object is in a controls list.
 */
static int wmlResolveCtlIsMember(WmlClassDefPtr ctlobj, WmlClassCtrlDefPtr ctlref)
{
	while (ctlref) {
		if (ctlref->ctrl == ctlobj)
			return TRUE;
		ctlref = ctlref->next;
	}

	return FALSE;
}

/**
 * Routine to write out UilSymNam.h
 *
 * Tables of names of object indexed by their various sym_k_ literals.
 */
static void wmlOutputUilSymNam(void)
{
static const char * const canned1 =
"/*  Define mapping of sym_k_..._object codes to widget names.  */\n\
\n\
externaldef(uil_sym_glbl) int uil_max_object = %d;\n\
static char *uil_widget_names_vec[] = {\n\
    \"\",\t/* NOT USED */\n";

static const char * const canned2 =
"};\n\
externaldef(uil_sym_glbl) char **uil_widget_names =\n\
\t\tuil_widget_names_vec;\n\
\n\n\
/*  Define mapping of sym_k_..._arg codes to argument names.  */\n\
\n\
externaldef(uil_sym_glbl) int uil_max_arg = %d;\n\
static char *uil_argument_names_vec[] = {\n\
    \"\",\t/* NOT USED */\n";

static const char * const canned3 =
"};\n\
externaldef(uil_sym_glbl) char **uil_argument_names =\n\
\t\tuil_argument_names_vec;\n\
\n\n\
/*  Define mapping of sym_k_..._reason to reason names.  */\n\
\n\
externaldef(uil_sym_glbl) int uil_max_reason = %d;\n\
static char *uil_reason_names_vec[] = {\n\
    \"\",\t/* NOT USED */\n";

static const char * const canned4 =
"};\n\
externaldef(uil_sym_glbl) char **uil_reason_names =\n\
\t\tuil_reason_names_vec;\n\
\n\n\
/*  Define mapping of sym_k_..._enumval to enumeration value names.  */\n\
\n\
externaldef(uil_sym_glbl) int uil_max_enumset = %d;\n\
externaldef(uil_sym_glbl) int uil_max_enumval = %d;\n\
static char *uil_enumval_names_vec[] = {\n\
    \"\",\t/* NOT USED */\n";

static const char * const canned5 =
"};\n\
externaldef(uil_sym_glbl) char **uil_enumval_names =\n\
\t\tuil_enumval_names_vec;\n\
\n\n\
/*  Define mapping of sym_k_..._charset to enumeration value names.  */\n\
\n\
externaldef(uil_sym_glbl) int uil_max_charset = %d;\n\
static char *uil_charset_names_vec[] = {\n\
    \"\",\t/* NOT USED */\n\
    \"<userdefined>\",\n";

static const char * const canned6 =
"};\n\
externaldef(uil_sym_glbl) char **uil_charset_names =\n\
\t\tuil_charset_names_vec;\n\
\n\n\
/*  Define mapping of sym_k_..._child codes to child names.  */\n\
\n\
externaldef(uil_sym_glbl) int uil_max_child = %d;\n\
static char *uil_child_names_vec[] = {\n\
    \"\",\t/* NOT USED */\n";

static const char * const canned7 =
"};\n\
externaldef(uil_sym_glbl) char **uil_child_names =\n\
\t\tuil_child_names_vec;\n";

	FILE *outfil;                /* output file */
	int ndx;                     /* loop index */
	WmlClassDefPtr clsobj;       /* class object */
	WmlResourceDefPtr resobj;    /* argument/reason object */
	WmlEnumValueDefPtr evobj;    /* enumeration value object */
	WmlCharSetDefPtr csobj;      /* character set object */
	WmlChildDefPtr chobj;        /* child object */

	/**
	 * Open the output file. Write canned header.
	 */
	if (!(outfil = fopen("UilSymNam.h", "w+"))) {
		fputs("Couldn't open UilSymNam.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);

	/**
	 * Write entries for widgets
	 */
	fprintf(outfil, canned1, max_object_code);
	for (ndx = 0; ndx < wml_obj_class_ptr->cnt; ndx++) {
		clsobj = (WmlClassDefPtr)wml_obj_class_ptr->hvec[ndx].objptr;
		if (!clsobj->sym_code) continue;
		fprintf(outfil, "    \"%s\",\n", clsobj->syndef->name);
	}

	/**
	 * Write entries for arguments
	 */
	fprintf(outfil, canned2, max_arg_code);
	for (ndx = 0; ndx < wml_obj_arg_ptr->cnt; ndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_arg_ptr->hvec[ndx].objptr;
		if (!resobj->sym_code) continue;
		fprintf(outfil, "    \"%s\",\n", resobj->syndef->name);
	}

	/**
	 * Write entries for reasons
	 */
	fprintf(outfil, canned3, max_reason_code);
	for (ndx = 0; ndx < wml_obj_reason_ptr->cnt; ndx++) {
		resobj = (WmlResourceDefPtr)wml_obj_reason_ptr->hvec[ndx].objptr;
		if (!resobj->sym_code) continue;
		fprintf(outfil, "    \"%s\",\n", resobj->syndef->name);
	}

	/**
	 * Write entries for enumeration values
	 */
	fprintf(outfil, canned4, max_enumset_code, max_enumval_code);
	for (ndx = 0; ndx < wml_obj_enumval_ptr->cnt; ndx++) {
		evobj = (WmlEnumValueDefPtr)wml_obj_enumval_ptr->hvec[ndx].objptr;
		if (!evobj->sym_code) continue;
		fprintf(outfil, "    \"%s\",\n", evobj->syndef->name);
	}

	/**
	 * Write entries for character sets
	 */
	fprintf(outfil, canned5, max_charset_code);
	for (ndx = 0; ndx < wml_obj_charset_ptr->cnt; ndx++) {
		csobj = (WmlCharSetDefPtr)wml_obj_charset_ptr->hvec[ndx].objptr;
		if (!csobj->sym_code) continue;
		fprintf(outfil, "    \"%s\",\n", csobj->syndef->name);
	}

	/**
	 * Write entries for children
	 */
	fprintf(outfil, canned6, max_child_code);
	for (ndx = 0; ndx < wml_obj_child_ptr->cnt; ndx++) {
		chobj = (WmlChildDefPtr)wml_obj_child_ptr->hvec[ndx].objptr;
		if (!chobj->sym_code) continue;
		fprintf(outfil, "    \"%s\",\n", chobj->syndef->name);
	}
	fputs(canned7, outfil);

	/* close the output file */
	puts("Created UilSymNam.h");
	fclose(outfil);
}

/**
 * Routine to write out UilSymEnum.h
 *
 * This file defines the enumeration sets recognized by UIL. There is an
 * entry in this file for each enumeration set. The definitions are accessed
 * by the sym_k_..._enumset code. Each consists of a structure containing
 * a vector of enumeration value descriptors, each of which is the name
 * of the value and its value.
 *
 * UilSymEnum.h contains:
 *	- Vectors of value descriptors for each table entry
 *	- The table itself.
 *	- A table given the sym_k_..._enumset code for each argument which
 *	  has an enumeration set.
 *	- A table accessed by sym_k_..._enumval code giving the actual value
 *	  for each enumeration value.
 *
 * The typedefs for the tables are in UilSymGen.h
 */
static void wmlOutputUilSymEnum(void)
{
static const char * const canned1 =
"\n\
/*\n\
 * Enumeration value vectors for each enumeration set\n\
 */\n\
\n";

static const char * const valhdr =
"\n\
static unsigned short int enum_value_vec%d[] =\n\
  {\n";

static const char * const canned3 =
"\n\
/*\n\
 * Enumeration set descriptor table\n\
 */\n\
static UilEnumSetDescDef enum_set_table_vec[] =\n\
  {\n\
    {0,NULL},\n";

static const char * const canned4 =
"  };\n\
externaldef(uil_sym_glbl) UilEnumSetDescDef *enum_set_table =\n\
\t\tenum_set_table_vec;\n\
/*\n\
 * Enumeration set table, accessed by sym_k_..._arg code. Each non-zero entry\n\
 * is the sym_k_..._enumset code for the argument's enumeration set.\n\
 */\n\
static unsigned short int argument_enumset_table_vec[] =\n\
  {\n\
    0,\n";

static const char * const canned5 =
"  };\n\
externaldef(uil_sym_glbl) unsigned short int *argument_enumset_table =\n\
\t\targument_enumset_table_vec;\n\
/*\n\
 * Enumeration value table, accessed by sym_k_..._enumval code. Each entry is\n\
 * the actual value associated with the code.\n\
 */\n\
static int enumval_values_table_vec[] =\n\
  {\n\
  0,\n";

static const char * const canned5a =
"  };\n\
externaldef(uil_sym_glbl) int *enumval_values_table =\n\
\t\tenumval_values_table_vec;\n";

	FILE *outfil;            /* output file */
	int ndx;                 /* loop index */
	WmlEnumSetDefPtr es;     /* enumeration set object */
	WmlEnumSetValDefPtr esv; /* current enum set value list element */
	WmlEnumValueDefPtr ev;   /* current enumeration value object */
	WmlResourceDefPtr res;   /* resource object */

	/**
	 * Open the output file. Write the canned header stuff
	 */
	if (!(outfil = fopen("UilSymEnum.h", "w+"))) {
		fputs("Couldn't open UilSymEnum.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);

	/**
	 * Generate the enumeration value vectors for each enumeration set.
	 */
	fputs(canned1, outfil);
	for (ndx = 0; ndx < wml_obj_enumset_ptr->cnt; ndx++) {
		es = (WmlEnumSetDefPtr)wml_obj_enumset_ptr->hvec[ndx].objptr;
		fprintf(outfil, valhdr, es->sym_code);
		for (esv = es->values; esv; esv = esv->next)
			fprintf(outfil, "    %d,\n", esv->value->sym_code);
		fputs("  };\n", outfil);
	}

	/**
	 * Generate the enumeration set tables
	 */
	fputs(canned3, outfil);
	for (ndx = 0; ndx < wml_obj_enumset_ptr->cnt; ndx++) {
		es = (WmlEnumSetDefPtr)wml_obj_enumset_ptr->hvec[ndx].objptr;
		fprintf(outfil, "    {%d,enum_value_vec%d},\n",
		        es->values_cnt, es->sym_code);
	}

	/**
	 * Create enumset table entries for arguments, similar to writing sym_k...
	 */
	fputs(canned4, outfil);
	for (ndx = 0; ndx < wml_obj_arg_ptr->cnt; ndx++) {
		res = (WmlResourceDefPtr)wml_obj_arg_ptr->hvec[ndx].objptr;
		fprintf(outfil, "    %d,\n", res->enumset_def ? res->enumset_def->sym_code : 0);
	}

	/**
	 * Create the enumval values table.
	 */
	fputs(canned5, outfil);
	for (ndx = 0; ndx < wml_obj_enumval_ptr->cnt; ndx++) {
		ev = (WmlEnumValueDefPtr)wml_obj_enumval_ptr->hvec[ndx].objptr;
		fprintf(outfil, "  %s,\n", ev->syndef->enumlit);
	}
	fputs(canned5a, outfil);

	/* close the input file */
	puts("Created UilSymEnum.h");
	fclose(outfil);
}

/**
 * Routine to write out UilSymCSet.h
 *
 * This file specifies the various attributes for the character sets
 * recognized by UIL. There is a table for each of the following
 * attributes:
 *	- Standards name associated with the character set
 *	- Writing direction, from XmSTRING_DIRECTION_...
 *	- Parsing direction, from XmSTRING_DIRECTION_...
 *	- Bytes per character, from sym_k_..._charsize (in UilSymGen.h)
 *	- A pair of tables for recognizing $LANG settings:
 *		o a table of all names under which a character set might
 *		  be legally recognized (upper case).
 *		o the sym_k_..._charset code for each entry
 *		o a variable giving the number of entries in the table
 *
 * All tables are accessed by the sym_k_..._charset
 *
 */
static void wmlOutputUilSymCSet(void)
{
static const char * const canned1 =
"\n\
/*\n\
 * Character set XmString name table, accessed by sym_k_..._charset code.\n\
 * Each entry is the name which identifies the character set in a XmString.\n\
 */\n\
static char *charset_xmstring_names_table_vec[] =\n\
  {\n\
    0,\n\
    \"<userdefined>\",\n";

static const char * const canned2 =
"};\n\
externaldef(uil_sym_glbl) char **charset_xmstring_names_table =\n\
\t\tcharset_xmstring_names_table_vec;\n\
/*\n\
 * Character set writing direction table, accessed by sym_k_..._charset code.\n\
 * Each entry is the XmSTRING_DIRECTION_... code which identifies the\n\
 * writing direction for the character set in a XmString.\n\
 */\n\
static unsigned char charset_wrdirection_table_vec[] =\n\
  {\n\
    0,\n\
    0,\t/* userdefined */\n";

static const char * const canned3 =
"};\n\
externaldef(uil_sym_glbl) unsigned char *charset_writing_direction_table =\n\
\t\tcharset_wrdirection_table_vec;\n\
/*\n\
 * Character set parsing direction table, accessed by sym_k_..._charset code.\n\
 * Each entry is the XmSTRING_DIRECTION_... code which identifies the\n\
 * parsing direction for the character set in a XmString.\n\
 */\n\
static unsigned char charset_parsdirection_table_vec[] =\n\
  {\n\
    0,\n\
    0,\t/* userdefined */\n";

static const char * const canned4 =
"};\n\
externaldef(uil_sym_glbl) unsigned char *charset_parsing_direction_table =\n\
\t\tcharset_parsdirection_table_vec;\n\
/*\n\
 * Character set character size table, accessed by sym_k_..._charset code.\n\
 * Each entry is the sym_k_..._charsize literal which names the character\n\
 * size for the character set in a XmString.\n\
 */\n\
static unsigned char charset_charsize_table_vec[] =\n\
  {\n\
    0,\n\
    0,\t/* userdefined */\n";

static const char * const canned5 =
"};\n\
externaldef(uil_sym_glbl) unsigned char *charset_character_size_table =\n\
\t\tcharset_charsize_table_vec;\n\
/*\n\
 * All the names under which a character set may be legally named in a \n\
 * $LANG variable (upper case).\n\
 */\n\
static char *charset_lang_names_table_vec[] =\n\
  {\n";

static const char * const canned6 =
"};\n\
externaldef(uil_sym_glbl) char **charset_lang_names_table =\n\
\t\tcharset_lang_names_table_vec;\n\
/*\n\
 * The sym_k_..._charset codes for charset_lang_names\n\
 */\n\
static unsigned short int charset_lang_codes_table_vec[] =\n\
  {\n";

static const char * const canned7 =
"};\n\
externaldef(uil_sym_glbl) unsigned short int *charset_lang_codes_table =\n\
\t\tcharset_lang_codes_table_vec;\n\
/*\n\
 * The number of entries in charset_lang_..._table tables\n\
 */\n\
externaldef(uil_sym_glbl) unsigned short int charset_lang_table_max = %d;\n";

	FILE *outfil;        /* output file */
	int ndx;             /* loop index */
	int lang_max = 0;    /* max value for $LANG tables */
	int alias_ndx;       /* alias loop index */
	char uname[200];     /* name converted to upper case */
	WmlCharSetDefPtr cs; /* character set object */

	/**
	 * Open the output file. Write the canned header stuff
	 */
	if (!(outfil = fopen("UilSymCSet.h", "w+"))) {
		fputs("Couldn't open UilSymCSet.h", stderr);
		return;
	}
	fputs(canned_warn, outfil);

	/**
	 * Generate the standards name table
	 */
	fputs(canned1, outfil);
	for (ndx = 0; ndx < wml_obj_charset_ptr->cnt; ndx++) {
		cs = (WmlCharSetDefPtr)wml_obj_charset_ptr->hvec[ndx].objptr;
		if (!cs->sym_code) continue;

		if (!strcmp(cs->syndef->xms_name, "XmFONTLIST_DEFAULT_TAG") ||
		    !strcmp(cs->syndef->xms_name, "_MOTIF_DEFAULT_LOCALE")) {
			fprintf(outfil, "    %s,\t/* %s */\n",
			        cs->syndef->xms_name, cs->syndef->name);
		} else {
			fprintf(outfil, "    \"%s\",\t/* %s */\n",
			        cs->syndef->xms_name, cs->syndef->name);
		}
	}

	/**
	 * Generate the writing direction table
	 */
	fputs(canned2, outfil);
	for (ndx = 0; ndx < wml_obj_charset_ptr->cnt; ndx++) {
		cs = (WmlCharSetDefPtr)wml_obj_charset_ptr->hvec[ndx].objptr;
		if (!cs->sym_code) continue;

		switch (cs->syndef->direction) {
		case WmlCharSetDirectionLtoR:
			fprintf(outfil, "    XmSTRING_DIRECTION_L_TO_R,\t/* %s */\n",
			        cs->syndef->name);
			break;
		case WmlCharSetDirectionRtoL:
			fprintf(outfil, "    XmSTRING_DIRECTION_R_TO_L,\t/* %s */\n",
			        cs->syndef->name);
			break;
		}
	}

	/**
	 * Generate the parsing direction table
	 */
	fputs(canned3, outfil);
	for (ndx = 0; ndx < wml_obj_charset_ptr->cnt; ndx++) {
		cs = (WmlCharSetDefPtr)wml_obj_charset_ptr->hvec[ndx].objptr;
		if (!cs->sym_code) continue;

		switch (cs->syndef->parsedirection) {
		case WmlCharSetDirectionLtoR:
			fprintf(outfil, "    XmSTRING_DIRECTION_L_TO_R,\t/* %s */\n",
			        cs->syndef->name);
			break;
		case WmlCharSetDirectionRtoL:
			fprintf(outfil, "    XmSTRING_DIRECTION_R_TO_L,\t/* %s */\n",
			        cs->syndef->name);
			break;
		}
	}

	/**
	 * Generate the character size table
	 */
	fputs(canned4, outfil);
	for (ndx = 0; ndx < wml_obj_charset_ptr->cnt; ndx++) {
		cs = (WmlCharSetDefPtr)wml_obj_charset_ptr->hvec[ndx].objptr;
		if (!cs->sym_code) continue;

		switch (cs->syndef->charsize) {
		case WmlCharSizeOneByte:
			fprintf(outfil, "    sym_k_onebyte_charsize,\t/* %s */\n",
			        cs->syndef->name);
			break;
		case WmlCharSizeTwoByte:
			fprintf(outfil, "    sym_k_twobyte_charsize,\t/* %s */\n",
			        cs->syndef->name);
			break;
		case WmlCharSizeMixed1_2Byte:
			fprintf(outfil, "    sym_k_mixed1_2byte_charsize,\t/* %s */\n",
			        cs->syndef->name);
			break;
		}
	}

	/**
	 * Generate the $LANG name recognition table
	 */
	fputs(canned5, outfil);
	for (ndx = 0; ndx < wml_obj_charset_ptr->cnt; ndx++) {
		cs = (WmlCharSetDefPtr)wml_obj_charset_ptr->hvec[ndx].objptr;
		if (!cs->sym_code) continue;

		strcpy(uname, cs->syndef->name);
		wmlUpperCaseString(uname);
		fprintf(outfil, "    \"%s\",\t/* %s */\n", uname, cs->syndef->name);
		lang_max++;
		strcpy(uname, cs->syndef->xms_name);
		wmlUpperCaseString(uname);
		fprintf(outfil, "    \"%s\",\t/* %s */\n", uname, cs->syndef->name);
		lang_max++;

		for (alias_ndx = 0; alias_ndx < cs->syndef->alias_cnt; alias_ndx++) {
			strcpy(uname, cs->syndef->alias_list[alias_ndx]);
			wmlUpperCaseString(uname);
			fprintf(outfil, "    \"%s\",\t/* %s */\n", uname, cs->syndef->name);
			lang_max++;
		}
	}

	/**
	 * Generate the $LANG code lookup table, in upper case
	 */
	fputs(canned6, outfil);
	for (ndx = 0; ndx < wml_obj_charset_ptr->cnt; ndx++) {
		cs = (WmlCharSetDefPtr)wml_obj_charset_ptr->hvec[ndx].objptr;
		if (!cs->sym_code) continue;

		fprintf(outfil, "    sym_k_%s_charset,\n    sym_k_%s_charset,\n",
		        cs->syndef->name, cs->syndef->name);
		for (alias_ndx = 0; alias_ndx < cs->syndef->alias_cnt; alias_ndx++)
			fprintf(outfil, "    sym_k_%s_charset,\n", cs->syndef->name);
	}

	/**
	 * Generate the number of entries in the previous two tables
	 */
	fprintf(outfil, canned7, lang_max);

	/* close the output file */
	puts("Created UilSymCSet.h");
	fclose(outfil);
}

