/* 
 * Motif
 *
 * 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 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
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: wmloutkey.c /main/8 1997/04/14 12:55:51 dbl $"
#endif
#endif

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


/*
*  (c) Copyright 1989, 1990, DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. */

/*
 * This module contains routines responsible for writing the .h files which
 * define the UIL lexer's keyword (token) tables. All files are written
 * into the current directory.
 *
 * Input:
 *	The resolved objects
 *	.dat files required to specify objects defined in Uil.y:
 *		keyword.dat
 *		reserved.dat
 *
 * Output:
 *	UilKeyTab.h
 *
 */


#include "wml.h"

#if defined(__STDC__)
#include <stdlib.h>
#include <string.h>
#endif
#include <stdio.h>


/*
 * Routines used only in this module
 */
void wmlKeyWBuildTables ();
void wmlKeyWClassTokens ();
void wmlKeyWGrammarTokens ();
int wmlKeyWGrammarClass ();
void wmlKeyWArgTokens ();
void wmlKeyWReasonTokens ();
void wmlKeyWCharsetTokens ();
void wmlKeyWEnumvalTokens ();
void wmlKeyWChildTokens ();
void wmlKeyWMakeTokens ();
void wmlOutputUilKeyTab ();
void wmlOutputUilKeyTabBody ();
void wmlTokenClassString ();
void wmlTokenSymKString ();
void wmlTokenTokenString ();
void wmlOutputUilTokName ();

/*
 * globals
 */

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

#define	GrTokenMax		200		/* limit on grammar tokens */
static int			grtok_max_val = 0;
static WmlGrammarTokenPtr	grtok_vec[GrTokenMax];



/*
 * Output control routine
 */

void wmlOutputKeyWordFiles ()

{

wmlKeyWBuildTables ();
wmlOutputUilKeyTab ();
wmlOutputUilTokName ();

}



/*
 * Routine to construct token tables for building UilKeyTab.h
 *
 * This routine constructs token entries for each token class which appears
 * in UilKeyTab.h (the token classes are defined in UilKeyDef.h). These
 * tokens are defined both by WML objects in object vectors, and by
 * tokens defined in Uil.y.
 */

void wmlKeyWBuildTables ()

{

int		ndx;


/*
 * Initialize the token vectors
 */
wmlInitHList (wml_tok_sens_ptr, 1000, TRUE);
wmlInitHList (wml_tok_insens_ptr, 1000, TRUE);
for ( ndx=0 ; ndx<GrTokenMax ; ndx++ )
    grtok_vec[ndx] = NULL;

/*
 * Read and enter the tokens from Uil.y (via tokens.dat)
 */
wmlKeyWGrammarTokens ();

/*
 * Enter the class, argument, reason, charset, child, and enumval tokens
 */
wmlKeyWClassTokens ();
wmlKeyWArgTokens ();
wmlKeyWReasonTokens ();
wmlKeyWCharsetTokens ();
wmlKeyWEnumvalTokens ();
wmlKeyWChildTokens ();

}



/*
 * Routine to read and enter tokens defined in Uil.y into the token tables.
 */

void wmlKeyWGrammarTokens ()

{

FILE			*infil;		/* input file (tokens.dat) */
int			scanres;	/* result of fscanf */
int			lineno = 1;	/* current line number */
char			token[100];	/* current token */
char			class[100];	/* current class */
int			tokval;		/* current token id (as value) */
WmlGrammarTokenPtr	grtok;		/* new grammar token */
int			ndx;
char			sens_name[100];	/* for case-insensitive name */


/*
 * Read tokens.dat. Recognize and save all tokens. Some are saved in the
 * global tokens vector so they will be put into UilKeyTab.h. All are
 * saved in an ordered vector to write UilTokName.h
 *
 * Special handling is required for tokens whose yacc definition conflicts
 * with common literals. In these cases, the token literal does not map
 * directly to its keyword in the language, and must be mapped as a special
 * case:
 *	UILTRUE		-> true/TRUE
 *	UILFALSE	-> false/FALSE
 *	UILfile	 	-> file/FILE
 *	UILeof	 	-> eof/EOF
 */
infil = fopen ("tokens.dat", "r");
if ( infil == NULL )
    {
    printf ("\nCouldn't open tokens.dat");
    return;
    }

while ( TRUE )
    {
    scanres = fscanf (infil, "%s %d %s", token, &tokval, class);
    if ( scanres == EOF ) break;
    if ( scanres != 3 )
	{
	printf ("\nBadly formatted at line %d in tokens.dat", lineno);
	continue;
	}
    lineno += 1;

/*
 * Convert the token class, and construct a grammar token.
 */
    grtok = (WmlGrammarTokenPtr) malloc(sizeof(WmlGrammarToken));
    grtok->class = wmlKeyWGrammarClass (class);
    grtok->token = wmlAllocateString (token);
    grtok->val = tokval;

/*
 * Save the token in the grammar token vector, indexed by its value
 * (for UilTokName.h)
 */
if ( grtok->val < GrTokenMax )
    {
    grtok_vec[grtok->val] = grtok;
    if ( grtok->val > grtok_max_val )
	grtok_max_val = grtok->val;
    }
else
    printf ("\nToken id %d for %s exceed GrTokenMax",
	    grtok->val, grtok->token);

/*
 * Enter tokens which appear in the keyword tables as keyword tokens.
 * These have their lower case names entered as the case-insensitive
 * keyword token string. Do special token literal mapping.
 */
    switch ( grtok->class )
	{
	case WmlTokenClassKeyword:
	case WmlTokenClassReserved:
	    strcpy (sens_name, grtok->token);
	    for ( ndx=0 ; ndx<(int)strlen(sens_name) ; ndx++ )
		sens_name[ndx] = _lower(sens_name[ndx]);
	    if ( strcmp(sens_name,"uiltrue") == 0 )
		strcpy (sens_name, "true");
	    if ( strcmp(sens_name,"uilfalse") == 0 )
		strcpy (sens_name, "false");
	    if ( strcmp(sens_name,"uilfile") == 0 )
		strcpy (sens_name, "file");
	    if ( strcmp(sens_name,"uileof") == 0 )
		strcpy (sens_name, "eof");
	    wmlKeyWMakeTokens (sens_name, grtok->class, (ObjectPtr)grtok);
	}
    }

fclose (infil);

}



/*
 * This routine translates a string identifying a token class into
 * its matching internal literal.
 */
int wmlKeyWGrammarClass (token)
    char		*token;

{

if ( strcmp(token,"argument") == 0 )
    return WmlTokenClassArgument;
if ( strcmp(token,"charset") == 0 )
    return WmlTokenClassCharset;
if ( strcmp(token,"color") == 0 )
    return WmlTokenClassColor;
if ( strcmp(token,"enumval") == 0 )
    return WmlTokenClassEnumval;
if ( strcmp(token,"font") == 0 )
    return WmlTokenClassFont;
if ( strcmp(token,"identifier") == 0 )
    return WmlTokenClassIdentifier;
if ( strcmp(token,"keyword") == 0 )
    return WmlTokenClassKeyword;
if ( strcmp(token,"literal") == 0 )
    return WmlTokenClassLiteral;
if ( strcmp(token,"reason") == 0 )
    return WmlTokenClassReason;
if ( strcmp(token,"reserved") == 0 )
    return WmlTokenClassReserved;
if ( strcmp(token,"special") == 0 )
    return WmlTokenClassSpecial;
if ( strcmp(token,"unused") == 0 )
    return WmlTokenClassUnused;
if ( strcmp(token,"class") == 0 )
    return WmlTokenClassClass;
if (strcmp(token,"child") == 0) return WmlTokenClassChild;

printf ("\nUnrecognized token class %s", token);
return 0;

}



/*
 * Routine to process the class objects and enter them in the token tables.
 * Aliases are also entered, under their own names.
 */

void wmlKeyWClassTokens ()

{

int			ndx;		/* loop index */
WmlClassDefPtr		clsobj;		/* class object */
WmlSynClassDefPtr	synobj;		/* syntactic object */
int			alias_ndx;	/* alias loop index */


/*
 * Make tokens for all class entries
 */
for ( ndx=0 ; ndx<wml_obj_class_ptr->cnt ; ndx++ )
    {
    clsobj = (WmlClassDefPtr) wml_obj_class_ptr->hvec[ndx].objptr;
    synobj = clsobj->syndef;
    wmlKeyWMakeTokens (synobj->name, WmlTokenClassClass, (ObjectPtr)clsobj);
    for ( alias_ndx=0 ; alias_ndx<synobj->alias_cnt ; alias_ndx++ )
	wmlKeyWMakeTokens (synobj->alias_list[alias_ndx],
			   WmlTokenClassClass,
			   (ObjectPtr)clsobj);
    }

}



/*
 * Routine to process the argument objects and enter them in the token tables.
 * Aliases are also entered, under their own names.
 */

void wmlKeyWArgTokens ()

{

int			ndx;		/* loop index */
WmlResourceDefPtr	resobj;		/* resource object */
WmlSynResourceDefPtr	synobj;		/* syntactic object */
int			alias_ndx;	/* alias loop index */


/*
 * Make tokens for all argument entries
 */
for ( ndx=0 ; ndx<wml_obj_arg_ptr->cnt ; ndx++ )
    {
    resobj = (WmlResourceDefPtr) wml_obj_arg_ptr->hvec[ndx].objptr;
    synobj = resobj->syndef;
    wmlKeyWMakeTokens (synobj->name, WmlTokenClassArgument, (ObjectPtr)resobj);
    for ( alias_ndx=0 ; alias_ndx<synobj->alias_cnt ; alias_ndx++ )
	wmlKeyWMakeTokens (synobj->alias_list[alias_ndx],
			   WmlTokenClassArgument,
			   (ObjectPtr)resobj);
    }

}



/*
 * Routine to process the reason objects and enter them in the token tables.
 */

void wmlKeyWReasonTokens ()

{

int			ndx;		/* loop index */
WmlResourceDefPtr	resobj;		/* resource object */
WmlSynResourceDefPtr	synobj;		/* syntactic object */
int			alias_ndx;	/* alias loop index */


/*
 * Make tokens for all reason entries
 */
for ( ndx=0 ; ndx<wml_obj_reason_ptr->cnt ; ndx++ )
    {
    resobj = (WmlResourceDefPtr) wml_obj_reason_ptr->hvec[ndx].objptr;
    synobj = resobj->syndef;
    wmlKeyWMakeTokens (synobj->name, WmlTokenClassReason, (ObjectPtr)resobj);
    for ( alias_ndx=0 ; alias_ndx<synobj->alias_cnt ; alias_ndx++ )
	wmlKeyWMakeTokens (synobj->alias_list[alias_ndx],
			   WmlTokenClassReason,
			   (ObjectPtr)resobj);
    }

}


/*
 * Routine to process the child objects and enter them in the token tables.
 */

void wmlKeyWChildTokens ()

{

int			ndx;		/* loop index */
WmlChildDefPtr		childobj;	/* child object */
WmlSynChildDefPtr	synobj;		/* syntactic object */

/*
 * Make tokens for all child entries
 */
for ( ndx=0 ; ndx<wml_obj_child_ptr->cnt ; ndx++ )
    {
    childobj = (WmlChildDefPtr) wml_obj_child_ptr->hvec[ndx].objptr;
    synobj = childobj->syndef;
    wmlKeyWMakeTokens (synobj->name, WmlTokenClassChild, (ObjectPtr)childobj);
    }

}



/*
 * Routine to process the charset objects and enter them in the token tables.
 */

void wmlKeyWCharsetTokens ()

{

int			ndx;		/* loop index */
WmlCharSetDefPtr	csobj;		/* character set object */
WmlSynCharSetDefPtr	synobj;		/* syntactic object */
int			alias_ndx;	/* alias loop index */


/*
 * Make tokens for all charset entries
 */
for ( ndx=0 ; ndx<wml_obj_charset_ptr->cnt ; ndx++ )
    {
    csobj = (WmlCharSetDefPtr) wml_obj_charset_ptr->hvec[ndx].objptr;
    synobj = csobj->syndef;
    wmlKeyWMakeTokens (synobj->name, WmlTokenClassCharset, (ObjectPtr)csobj);
    for ( alias_ndx=0 ; alias_ndx<synobj->alias_cnt ; alias_ndx++ )
	wmlKeyWMakeTokens (synobj->alias_list[alias_ndx],
			   WmlTokenClassCharset,
			   (ObjectPtr)csobj);
    }

}



/*
 * Routine to process the enumval objects and enter them in the token tables.
 */

void wmlKeyWEnumvalTokens ()

{

int			ndx;		/* loop index */
WmlEnumValueDefPtr	esobj;		/* enumeration value object */
WmlSynEnumValueDefPtr	synobj;		/* syntactic object */


/*
 * Make tokens for all enumval entries
 */
for ( ndx=0 ; ndx<wml_obj_enumval_ptr->cnt ; ndx++ )
    {
    esobj = (WmlEnumValueDefPtr) wml_obj_enumval_ptr->hvec[ndx].objptr;
    synobj = esobj->syndef;
    wmlKeyWMakeTokens (synobj->name, WmlTokenClassEnumval, (ObjectPtr)esobj);
    }

}



/*
 * Routine to create tokens and enter them in the token list.
 *
 * This routine constructs a case-sensitive and a case-insensitive token
 * and enters them the token vectors.
 */
void wmlKeyWMakeTokens (sens_name, class, obj)
    char		*sens_name;
    int			class;
    ObjectPtr		obj;

{

WmlKeyWTokenPtr		senstok;	/* case-sensitive token */
WmlKeyWTokenPtr		insenstok;	/* case-insensitive token */
char			insens_name[100];
int			ndx;


/*
 * Create both tokens, with one having an upper-case name. The names are
 * entered only in the order vector, not in the token itself.
 */
senstok = (WmlKeyWTokenPtr) malloc (sizeof(WmlKeyWToken));
insenstok = (WmlKeyWTokenPtr) malloc (sizeof(WmlKeyWToken));
senstok->class = class;
senstok->objdef = obj;
insenstok->class = class;
insenstok->objdef = obj;

strcpy (insens_name, sens_name);
for ( ndx=0 ; ndx<(int)strlen(insens_name) ; ndx++ )
    insens_name[ndx] = _upper (insens_name[ndx]);

wmlInsertInKeyList(wml_tok_sens_ptr, sens_name, senstok);
wmlInsertInKeyList(wml_tok_insens_ptr, insens_name, insenstok);
}


/*
 * Routine to output UilKeyTab.h
 *
 * This routine dumps the tokens defined in the token tables into
 * UilKeyTab.h. Both the case-sensitive and case-insensitive token
 * lists are used.
 */

void wmlOutputUilKeyTab ()

{

char			*canned1 =
"\n/*    case sensitive keyword table    */\n\
static key_keytable_entry_type key_table_vec[] =\n\
  {\n";

char			*canned2 =
"  };\n\
externaldef(uil_sym_glbl) key_keytable_entry_type *key_table =\n\
\t\tkey_table_vec;\n\n\
/*    Maximum length of a keyword, and table size    */\n\
externaldef(uil_sym_glbl) int key_k_keyword_max_length = %d;\n\
externaldef(uil_sym_glbl) int key_k_keyword_count = %d;\n\n\
/*    case insensitive keyword table    */\n\
static key_keytable_entry_type key_table_case_ins_vec[] =\n\
  {\n";

char			*canned3 =
"  };\n\
externaldef(uil_sym_glbl) key_keytable_entry_type *key_table_case_ins =\n\
\t\tkey_table_case_ins_vec;\n";


FILE			*outfil;	/* output file */
int			ndx;		/* loop index */
int			maxlen = 0;	/* max keyword length */
int			maxkey = 0;	/* # entries in keyword table */


/*
 * Open the output file.
 */
outfil = fopen ("UilKeyTab.h", "w");
if ( outfil == NULL )
    {
    printf ("\nCouldn't open UilKeyTab.h");
    return;
    }
fprintf (outfil, canned_warn);

/*
 * Print the case sensitive and insensitive tables
 */
fprintf (outfil, canned1);
wmlOutputUilKeyTabBody (outfil, wml_tok_sens_ptr, &maxlen, &maxkey);
fprintf (outfil, canned2, maxlen, maxkey);
wmlOutputUilKeyTabBody (outfil, wml_tok_insens_ptr, &maxlen, &maxkey);
fprintf (outfil, canned3);

/*
 * close the output file
 */
printf ("\nCreated UilKeyTab.h");
fclose (outfil);

}



/*
 * Routine to output the body of a keyword table
 */
void wmlOutputUilKeyTabBody (outfil, tokvec, maxlen, maxkey)
    FILE			*outfil;
    DynamicHandleListDefPtr	tokvec;
    int				*maxlen;
    int				*maxkey;

{

int			ndx;		/* loop index */
WmlKeyWTokenPtr		tok;		/* current token */
char			*tokstg;	/* string for token (keyword) */
char			tkclass[100];	/* token class string */
char			tksym[100];	/* token sym_k string */
char			tktoken[100];	/* token tkn_k_num string */


/*
 * Loop over all tokens, and put out an entry for each.
 */
for ( ndx=0 ; ndx<tokvec->cnt ; ndx++ )
    {
    tok = (WmlKeyWTokenPtr) tokvec->hvec[ndx].objptr;
    tokstg = tokvec->hvec[ndx].objname;
    wmlTokenClassString (tkclass, tok);
    wmlTokenSymKString (tksym, tok);
    wmlTokenTokenString (tktoken, tok);
    fprintf (outfil, "    {%s, %s, %d, %s, \"%s\"},\n",
	     tkclass,
	     tksym,
	     strlen(tokstg),
	     tktoken,
	     tokstg);
    if ( (int)strlen(tokstg) > *maxlen )
	*maxlen = strlen (tokstg);
    *maxkey += 1;
    }

}



/*
 * Routine to return the string for a token class, tkn_k_class_...
 */
void wmlTokenClassString (dststg, tok)
    char		*dststg;
    WmlKeyWTokenPtr	tok;

{

switch ( tok->class )
    {
    case WmlTokenClassArgument:
        strcpy (dststg, "tkn_k_class_argument");
	return;
    case WmlTokenClassCharset:
        strcpy (dststg, "tkn_k_class_charset");
	return;
    case WmlTokenClassEnumval:
        strcpy (dststg, "tkn_k_class_enumval");
	return;
    case WmlTokenClassKeyword:
        strcpy (dststg, "tkn_k_class_keyword");
	return;
    case WmlTokenClassReason:
        strcpy (dststg, "tkn_k_class_reason");
	return;
    case WmlTokenClassReserved:
        strcpy (dststg, "tkn_k_class_reserved");
	return;
    case WmlTokenClassClass:
        strcpy (dststg, "tkn_k_class_class");
	return;
    case WmlTokenClassChild:
        strcpy (dststg, "tkn_k_class_child");
	return;
    }

}



/*
 * Routine to return the string for a sym_k_... for some object
 */
void wmlTokenSymKString (dststg, tok)
    char		*dststg;
    WmlKeyWTokenPtr	tok;

{

WmlClassDefPtr		clsobj;		/* class object */
WmlResourceDefPtr	resobj;		/* resource object */
WmlCharSetDefPtr	csobj;		/* character set object */
WmlEnumValueDefPtr	esobj;		/* enumeration value object */
WmlChildDefPtr		chobj;		/* child object */


switch ( tok->class )
    {
    case WmlTokenClassArgument:
	resobj = (WmlResourceDefPtr) tok->objdef;
	sprintf (dststg, "sym_k_%s_arg", resobj->tkname);
	return;
    case WmlTokenClassCharset:
	csobj = (WmlCharSetDefPtr) tok->objdef;
	sprintf (dststg, "sym_k_%s_charset", csobj->syndef->name);
	return;
    case WmlTokenClassEnumval:
	esobj = (WmlEnumValueDefPtr) tok->objdef;
	sprintf (dststg, "sym_k_%s_enumval", esobj->syndef->name);
	return;
    case WmlTokenClassKeyword:
        strcpy (dststg, "0");
	return;
    case WmlTokenClassReason:
	resobj = (WmlResourceDefPtr) tok->objdef;
	sprintf (dststg, "sym_k_%s_reason", resobj->tkname);
	return;
    case WmlTokenClassReserved:
        strcpy (dststg, "0");
	return;
    case WmlTokenClassClass:
        clsobj = (WmlClassDefPtr) tok->objdef;
	sprintf (dststg, "sym_k_%s_object", clsobj->tkname);
	return;
    case WmlTokenClassChild:
        chobj = (WmlChildDefPtr) tok->objdef;
	sprintf (dststg, "sym_k_%s_child", chobj->tkname);
	return;
    }

}



/*
 * Routine to return the string for a token number, tkn_k_num_...
 */
void wmlTokenTokenString (dststg, tok)
    char		*dststg;
    WmlKeyWTokenPtr	tok;

{

WmlGrammarTokenPtr	grtok;		/* grammar token */


switch ( tok->class )
    {
    case WmlTokenClassArgument:
        strcpy (dststg, "ARGUMENT_NAME");
	return;
    case WmlTokenClassCharset:
        strcpy (dststg, "CHARSET_NAME");
	return;
    case WmlTokenClassEnumval:
        strcpy (dststg, "ENUMVAL_NAME");
	return;
    case WmlTokenClassReason:
        strcpy (dststg, "REASON_NAME");
	return;
    case WmlTokenClassKeyword:
    case WmlTokenClassReserved:
	grtok = (WmlGrammarTokenPtr) tok->objdef;
        strcpy (dststg, grtok->token);
	return;
    case WmlTokenClassClass:
        strcpy (dststg, "CLASS_NAME");
	return;
    case WmlTokenClassChild:
        strcpy (dststg, "CHILD_NAME");
	return;
    }

}



/*
 * routine to output UilTokName.h
 */

void wmlOutputUilTokName ()

{

char			*canned1 =
"/*\tToken name table */\n\
static char *tok_token_name_table_vec[] = \n\
  {\n";

char			*canned2 =
"  };\n\
externaldef(uil_sym_glbl) char **tok_token_name_table =\n\
\t\ttok_token_name_table_vec;\n\n\
/*\tNumber of entries in table */\n\
externaldef(uil_sym_glbl) int tok_num_tokens = %d;\n";


FILE			*outfil;	/* output file */
int			ndx;		/* loop index */
WmlGrammarTokenPtr	grtok;		/* current grammar token */


/*
 * Open the output file.
 */
outfil = fopen ("UilTokName.h", "w");
if ( outfil == NULL )
    {
    printf ("\nCouldn't open UilTokName.h");
    return;
    }
fprintf (outfil, canned_warn);
fprintf (outfil, canned1);

/*
 * Print the token name entries
 * Note: vector size is max_val + 1 for zeroth token
 */
for ( ndx=0 ; ndx<grtok_max_val+1 ; ndx++ )
    {
    grtok = grtok_vec[ndx];
    if ( grtok != NULL )
	fprintf (outfil, "    \"%s\",\n", grtok->token);
    else
	fprintf (outfil, "    \"UNKNOWN_TOKEN\",\n");
    }

/*
 * close the output file
 */
fprintf (outfil, canned2, grtok_max_val+1);
printf ("\nCreated UilTokName.h");
fclose (outfil);

}
