/*
Copyright 1990-2003 Sun Microsystems, Inc. All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions: The above copyright notice and this
permission notice shall be included in all copies or substantial
portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


Except as contained in this notice, the names of The Open Group and/or
Sun Microsystems, Inc. shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from The Open Group and/or Sun Microsystems,
Inc., as applicable.


X Window System is a trademark of The Open Group

OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
logo, LBX, X Window System, and Xinerama are trademarks of the Open
Group. All other trademarks and registered trademarks mentioned herein
are the property of their respective owners. No right, title or
interest in or to any trademark, service mark, logo or trade name of
Sun Microsystems, Inc. or its licensors is granted.

*/

/* txt2bin.c */

#include <stdio.h>
#include "codetable.h"
#include "ctfile.h"

#define MAX_LINE_LEN	256

typedef struct _dynNode {
    unsigned char key;		/* the input key */
    char     *hzptr;		/* HZ strings */
    struct _dynNode *next;	/* next node in the same level */
    struct _dynNode *son;	/* next node down one level */
} dynNode;

static dynNode rootNode = {
    '\0', NULL, (struct _dynNode *)NULL, (struct _dynNode *)NULL
};

static dynNode *root = &rootNode;	/* root pointer to the dynNode */

CodeTableStruct hzCodeTable;

tableNode *nodeList;		/* all Nodes will be linearized to put here */
unsigned char *hzList;		/* all HZ codes will be put here */
unsigned  int pNodeList;	/* pointer to Node List */
unsigned  int pHZList;		/* pointer to HZ List */

static int totalHZbytes = 0;	/* total bytes of HZs */
static int totalTableNode = 1;	/* total # of Node nodes (including root) */

int lineno = 0;
unsigned int clen = 0;

char comment[MAX_COMMENT_LEN];
keyPrompt keyprompt[MAX_USEDCODES_NUM];
functionKey functionkey[MAX_FUNCTIONKEY_NUM];

/*
 * When we read the file line by line, keys-HZs mapping are inserted
 * into the dynNode.  After all lines are finished, the dynNode is
 * reorganized (optimized and linearized) into a static tableNode structures,
 *
 * Phrase (string of multiple hanzi) is embedded into hanzi strings.
 * A phrase is start with 2 bytes: (1, n), where n is the length
 * of the phrase in byte.  { The tag (0, n) is not good for strcpy, etc. }
 */

typedef struct _str_int {
	char  *string;
	int   value;
} string_value_pair;

string_value_pair selectkeymode_str_val[] = {
	{ NUMBER0_MODE_STR, NUMBER0_MODE },
	{ NUMBER_MODE_STR, NUMBER_MODE },
	{ LOWER_MODE_STR,  LOWER_MODE },
	{ UPPER_MODE_STR,  UPPER_MODE },
	{ NULL,            NUMBER_MODE }
};

int str2val(string_value_pair *str_val, char *str)
{
	while (str_val->string) {
/*
		printf("%d: %s\n", str_val->value, str_val->string);
*/
		if (!strncasecmp (str_val->string, str, strlen(str_val->string)))
	    		return (str_val->value);
		str_val++;
    	}
    	return (str_val->value);
}

char *val2str(string_value_pair *str_val, int value)
{
	while (str_val->string) {
		if (str_val->value == value)
	    		return (str_val->string);
		str_val++;
    	}
    	return (str_val->string);
}

char *skip_space(char *s)
{
        while (*s && (*s==' ' || *s=='\t')) s++;
        return s;
}

char *to_space(char *s)
{
	while (*s && !isspace(*s)) s++;
        return s;
}

/* convert string like "^A" to integrate */
int convert_octnum(buf)
char buf[];
{
	register char *p1 = buf, *p2 = buf;
	int bCtrlStatus = 0;
	int num_functionkey = 0;

	while (*p1) {
        	if (isspace(*p1) || (*p1&0x80)) {   
            		p1++;
            		continue;
        	}
        	if (*p1 == '^') {
			bCtrlStatus = 1;
            		p1++;
			continue;
		}
		if (bCtrlStatus) {
/*
			printf("Ctrl: %c, upper(%c): %c, 0x%x, 0x%x\n",
				*p1, *p1, toupper(*p1),
				toupper(*p1), toupper(*p1)|0x80); 
*/
			if (*p1 >= 'a' && *p1 <= 'z') {
				*p2++ = toupper(*p1) | 0x80;
			} else if (*p1 >= 'A' && *p1 <= 'Z') {
				*p2++ = *p1 | 0x80;
			} else if (index(",/;'[]-=", *p1)) {
				*p2++ = *p1 | 0x80;
			} else if (*p1 == '?') {
				*p2++ = '/' | 0x80;
			} else if (*p1 == '<') {
				*p2++ = ',' | 0x80;
			} else if (*p1 == '>') {
				*p2++ = '.' | 0x80;
			} else if (*p1 == ':') {
				*p2++ = ';' | 0x80;
			}

			p1++;
			bCtrlStatus = 0;
			continue;
        	}
        	*p2++ = *p1++;

		num_functionkey++;
		if (num_functionkey >= MAX_FUNCTIONKEY_LEN)
			break;

    	}
	*p2 = '\0';

	return(0);
}

static void Warning(str)
char *str;
{
    	fprintf (stderr, "Warning: %s (at line %d)\n", str, lineno);
}

static void Error(str)
char *str;
{
    	fprintf (stderr, "%s (at line %d)\n", str, lineno);
    	exit (1);
}

static dynNode *NewNode(key, son, next)
unsigned char key;
dynNode *son;
dynNode *next;
{
	register dynNode *t = (dynNode *) malloc (sizeof(dynNode));

	if (t == NULL)
		Error ("Run out of memory");
	t->hzptr = NULL;
	t->key = key;
	t->son = son;
	t->next = next;
	if (key)
		totalTableNode++ ;
	return (t);
}

int get_HZ_item(char *hzstr, int *hzlen, int encode)
{
	int str_len = 0;
	
	if (*hzstr == HZ_PHRASE_TAG) {
		/* phrase */
		str_len = *(hzstr+1) + 2;
	} else if (*hzstr) {
		/* hanzi */
		str_len = get_char_len_by_encodeid(encode, hzstr);
	}

	*hzlen = str_len;
	return(0);
}

int check_if_duplicate(char *whole_str, char *hzstr, int hzlen, int encode)
{
	int str_pos, str_len, item_len;
	char *phz;

	str_len = strlen(whole_str);
	str_pos = 0;
	while(str_pos < str_len) {
		phz = whole_str + str_pos;
		if(*phz == 0) break;

		get_HZ_item(phz, &item_len, encode);
		if (item_len == hzlen) {
			if(!strncmp((char *)hzstr, (char *)phz, hzlen))
				return(1);
		}
		str_pos += item_len;
	}

	return(0);
}

#define TEMP_BUFFER_LEN 4096
static int Append_HZ_Into_Node(node, hzptr)
dynNode *node;
char *hzptr;
{
	char buffer[TEMP_BUFFER_LEN];
	int str_pos, str_len, item_len;
	char *phz;

	int encode = hzCodeTable.Encode;

	memset(buffer, 0, TEMP_BUFFER_LEN);
	if (node->hzptr != NULL)
		strncpy(buffer, node->hzptr, TEMP_BUFFER_LEN);

	str_len = strlen(hzptr);
	str_pos = 0;
	while(str_pos < str_len) {
		phz = hzptr + str_pos;
		if(*phz == 0) break;

		get_HZ_item(phz, &item_len, encode);

		if (!check_if_duplicate(buffer, phz, item_len, encode)) {
			if (item_len + strlen(buffer) < TEMP_BUFFER_LEN)
				strncat(buffer, phz, item_len);
		}
		str_pos += item_len;
	}

	str_len = strlen(buffer);
	if (node->hzptr == NULL)
		node->hzptr = (char *)malloc (str_len + 1);
	else
		node->hzptr = (char *)realloc (node->hzptr, str_len + 1);

	if (node->hzptr) {
		strcpy(node->hzptr, buffer);
		node->hzptr[str_len] = '\0';
	}

	return(0);
}

/* 
 * InsertNode -- insert the keys-HZs pair into dynNode structure
 */
static void InsertNode(kptr, hzptr)
char *kptr;
char *hzptr;
{
	register dynNode *tptr = root;

	while (*kptr) {
		unsigned char key = *kptr++;

		if (tptr->son == NULL) {
	    		tptr->son = NewNode(key, (dynNode *)NULL, (dynNode *)NULL);
	    		tptr = tptr->son;
		} else if (tptr->son->key > key) {
	    		/* new key should be the 1st son, the old one becomes the next */
	    		tptr->son = NewNode(key, (dynNode *)NULL, tptr->son);
	    		tptr = tptr->son;
		} else if (tptr->son->key == key) {
	    		tptr = tptr->son;
		} else {
	    		/* ASSERT: (tptr->son->key < key) */
	    		tptr = tptr->son;
	    		while ((tptr->next != NULL) && (tptr->next->key < key)) {
	        		tptr = tptr->next;	/* try next */
	    		}
	    		/* ASSERT: (tptr->next == NULL) || (tptr->next->key >= key) */
	    		if ((tptr->next == NULL) || (tptr->next->key > key)) {
				/* add it here (to keep it sorted) */
				tptr->next = NewNode(key, (dynNode *)NULL, tptr->next);
				tptr = tptr->next;
	    		} else {	/* tptr->next->key == key */
				tptr = tptr->next;
	    		}
		}
    	}

    	/* come to the end of the key string kptr */

    	if (tptr->son == NULL) {
		tptr->son = NewNode ('\0', (dynNode *)NULL, (dynNode *)NULL);
    	} else if (tptr->son->key != '\0') {
		/* new key should be the 1st son, the old one becomes the next */
		tptr->son = NewNode('\0', (dynNode *)NULL, tptr->son);
    	}
	Append_HZ_Into_Node(tptr->son, hzptr);

    	totalHZbytes += strlen (hzptr);
}

/*
 * Linearize -- make the node tree into a linear array, for I/O.
 *		returns the number of choices under the node.
 */
static int Linearize(idxNode, tablenode)
unsigned int idxNode;
register dynNode *tablenode;
{
	register dynNode *tptr = tablenode->son;
	register unsigned int i, hzlen;
	dynNode *tptr2;
	unsigned int bNodeList = pNodeList;
	unsigned int bHZList = pHZList;
	int numChoice = 0;

	/* if leaf node */
	if (tptr->key == '\0') {
		char *hzptr = tptr->hzptr;

		while (*hzptr) {
			if (*hzptr != HZ_PHRASE_TAG) {
				/* a single Chinese character */
				hzlen = get_char_len_by_encodeid(hzCodeTable.Encode, hzptr);
			} else {
				/* a phrase:  "PHRASE flag" | length | Phrase String */
				hzlen = *(hzptr+1) + 2;
	    		}
			for (i = 0; i < hzlen; i++) {
		    		hzList[pHZList++] = *hzptr++;
			}

	    		numChoice ++ ;
		}
		tptr = tptr->next;
	}

	tptr2 = tptr;	/* save for second pass */
	while (tptr) {
		nodeList[ pNodeList++ ].key = tptr->key;
		tptr = tptr->next;
	}

    	nodeList[ idxNode ].pos_NextKey = bNodeList;
    	nodeList[ idxNode ].num_NextKeys = pNodeList - bNodeList;
    	nodeList[ idxNode ].pos_HZidx = bHZList;
    	nodeList[ idxNode ].num_HZchoice = numChoice;

	/* linearize every sibling node */
    	for (tptr = tptr2, i = bNodeList; tptr; i++, tptr = tptr->next) {
		numChoice += Linearize (i, tptr); 
    	}

/*
	printf("%c === num:%d\n", tptr2->key ,numChoice);
*/
    	return (numChoice);
}

/*
 * BuildTableNode -- reorganize the dynNode into static tableNode structure
 */
static void BuildTableNode()
{
	nodeList = (tableNode *) calloc (totalTableNode, sizeof(tableNode));
	hzList = (unsigned char *) malloc (totalHZbytes);
	if ((! hzList) || (! nodeList)) {
		perror ("BuildTableNode");
		exit (1);
	}

	pNodeList = 1;	/* 0 is the root, start from index 1 */
	pHZList = 0;

	(void) Linearize(0, root);
	nodeList[0].num_HZchoice = 0;	/* no choice for the upmost node */
	nodeList[0].pos_HZidx = 0;

	/* ASSERT: pNodeList = totalTableNode, pHZList = totalHZbytes/2 */
	hzCodeTable.sizeNodeList = pNodeList;
	hzCodeTable.sizeHZList = pHZList;
}

void PrintNodeList()
{
	int i;

	for (i=0; i<totalTableNode; i++)
	{
		printf("id :%d\n", i);
		printf("key: %c\n", nodeList[i].key);
		printf("num_NextKeys: %d\n", nodeList[i].num_NextKeys);
		printf("num_HZchoice: %d\n", nodeList[i].num_HZchoice);
		printf("pos_NextKey: %d\n", nodeList[i].pos_NextKey);
		printf("pos_HZidx: %d\n", nodeList[i].pos_HZidx);
		printf("\n");
	}
}

void PrintNode (tptr)
dynNode *tptr;
{
	if (tptr == NULL) return;

	if (tptr->key != '\0')
		printf("%c", tptr->key);

	if (tptr->hzptr)
		printf("%s=\n", tptr->hzptr);

	PrintNode(tptr->son);
	PrintNode(tptr->next);
	printf("\n");

}

void PrintTableInfo()
{
	int i;

	printf("Cname:%s\n", hzCodeTable.Cname);
	printf("WildChar:%s\n", hzCodeTable.WildChar);
	printf("UsedCodes:%s\n", hzCodeTable.UsedCodes);
	printf("MaxCodes:%d\n", hzCodeTable.MaxCodes);
	printf("Encode:%d\n", hzCodeTable.Encode);
	printf("sizeNodeList:%d\n", hzCodeTable.sizeNodeList);
	printf("sizeHZList:%d\n", hzCodeTable.sizeHZList);

	printf("key_prompt\n");
	for (i=0; i<MAX_USEDCODES_NUM; i++)
	{
		if (keyprompt[i].prompt[0])
			printf("%c:  %s\n", i, keyprompt[i].prompt);
	}

	printf("function_key\n");
	for (i=0; i<MAX_FUNCTIONKEY_NUM; i++)
	{
		if (functionkey[i].keylist[0])
			printf("%d:  %d\n", i, functionkey[i].keylist[0]);
	}
	comment[clen] = '\0';
	printf("comment is \n%s\n", comment);
}

static void InitTable()
{
	memset((char *)(&hzCodeTable), 0, sizeof(CodeTableStruct));

	strcpy(hzCodeTable.UUID, DEFAULT_CODETABLE_UUID);
	strcpy(hzCodeTable.Version, DEFAULT_CODETABLE_VERSION);
	strcpy(hzCodeTable.Author, DEFAULT_CODETABLE_AUTHOR);
	strcpy(hzCodeTable.Copyright, DEFAULT_CODETABLE_COPYRIGHT);
	strcpy(hzCodeTable.Hinting, DEFAULT_CODETABLE_HINTING);
	strcpy(hzCodeTable.Cname, DEFAULT_CODETABLE_NAME);
	strcpy(hzCodeTable.UsedCodes, DEFAULT_USEDCODES);
	strcpy(hzCodeTable.WildChar, DEFAULT_WILDCHARS);
	hzCodeTable.Encode = 0;	
	hzCodeTable.MaxCodes = DEFAULT_MAXCODES & 0xff;	

	hzCodeTable.sizeHZList = 0;
	hzCodeTable.sizeNodeList = 0;
	hzCodeTable.bSectionsFlag = 0;

	hzCodeTable.nKeyByKeyMode = ON_MODE;
	hzCodeTable.nHelpInfoMode = OFF_MODE;
	hzCodeTable.nAutoSelectMode = OFF_MODE;
	hzCodeTable.nKeyPromptMode = ON_MODE;
	hzCodeTable.nDisplayOnSpotMode = ON_MODE;
	hzCodeTable.nSelectKeyMode = NUMBER_MODE;

	memset(&(keyprompt[0]), 0, sizeof(keyprompt));
	memset(&(functionkey[0]), 0, sizeof(functionkey));
}

/*
 * ReadInput -- read and parse Input Text CodeTable format file
 */
static void ReadInput(ifile)
FILE *ifile;
{

	char line_buf[256], line[MAX_LINE_LEN];
	char keybuf[MAX_LINE_LEN], valuebuf[MAX_LINE_LEN];
	char *key, *value_str, *kptr, *sptr, *vptr;
	register char *ptr;
	int  endofstr, ret, len, line_index;

	int flag_section = DEFAULT_SECTION;

 	while(fgets(line_buf, 255, ifile) != NULL) {

		lineno++;

		value_str = line_buf;
		ptr = skip_space(value_str);

		if (*ptr == '\0') break;

		/* if is space line, get new line */
		if (flag_section != COMMENT_SECTION) {
			if (*ptr == '\n' || *ptr == '#')
				continue;
		}

		line_index = 0;
		while(*ptr != '\n' && *ptr != '\0' && line_index < MAX_LINE_LEN) 
			line[line_index++] = *ptr++;

		/* trim right space */
		while (isspace(line[line_index-1])) line_index--;
		line[line_index] = '\0';

		key = line;
		len = strlen(line);
/*
		printf("len:%d, %s\n", strlen(line), line);
*/
		if (line[0] == '[' && line[len-1] == ']') {

			/* get section name of the item */
			ptr = line + 1;
			while(isspace(*ptr)) ptr++;
			key = ptr;

			ptr = line + len - 2;
			while(isspace(*ptr)) ptr--;
			*(ptr+1) = '\0';

			if (!*key) continue;

			if (!(strncasecmp(key, DESCRIPTION_STR, strlen(DESCRIPTION_STR)))) {

				flag_section = DESCRIPTION_SECTION;
				continue;

	    		} else if (!(strncasecmp(key, COMMENT_STR, strlen(COMMENT_STR)))) {

				BITSET(hzCodeTable.bSectionsFlag , COMMENT_SECTION);
				flag_section = COMMENT_SECTION;
				continue;

	    		} else if (!(strncasecmp(key, KEYPROMPT_STR, strlen(KEYPROMPT_STR)))) {

				BITSET(hzCodeTable.bSectionsFlag , KEYPROMPT_SECTION);
				flag_section = KEYPROMPT_SECTION;
				continue;

	    		} else if (!(strncasecmp(key, FUNCTIONKEY_STR, strlen(FUNCTIONKEY_STR)))) {
	
				BITSET(hzCodeTable.bSectionsFlag , FUNCTIONKEY_SECTION);
				flag_section = FUNCTIONKEY_SECTION;
				continue;

			} else if (!(strncasecmp(key, PHRASE_STR, strlen(PHRASE_STR)))) {

				BITSET(hzCodeTable.bSectionsFlag , PHRASE_SECTION);
				flag_section = PHRASE_SECTION;
				continue;

	    		} else if (!(strncasecmp(key, SINGLE_STR, strlen(SINGLE_STR)))) {

				BITSET(hzCodeTable.bSectionsFlag , SINGLE_SECTION);
				flag_section = SINGLE_SECTION;
				continue;

			}
	    		else if (!(strncasecmp(key, OPTIONS_STR, strlen(OPTIONS_STR)))) {

				BITSET(hzCodeTable.bSectionsFlag , OPTIONS_SECTION);
				flag_section = OPTIONS_SECTION;
				continue;

			}
		}

		switch (flag_section) {
		
		case DEFAULT_SECTION:
			break;

		case DESCRIPTION_SECTION:
			if (!(strncasecmp(key, UUID_STR, strlen(UUID_STR)))) {
				value_str = skip_space(key+strlen(UUID_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				strncpy(hzCodeTable.UUID, value_str, MAX_UUID_LEN - 1);
				break;
			}

			if (!(strncasecmp(key, VERSION_STR, strlen(VERSION_STR)))) {
				value_str = skip_space(key+strlen(VERSION_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				strncpy(hzCodeTable.Version, value_str, MAX_VERSION_LEN - 1);
				break;
			}

			if (!(strncasecmp(key, ICONPATH_STR, strlen(ICONPATH_STR)))) {
				value_str = skip_space(key+strlen(ICONPATH_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				strncpy(hzCodeTable.IconPath, value_str, MAX_ICON_PATH_LEN - 1);
				break;
			}

			if (!(strncasecmp(key, AUTHOR_STR, strlen(AUTHOR_STR)))) {
				value_str = skip_space(key+strlen(AUTHOR_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				strncpy(hzCodeTable.Author, value_str, MAX_AUTHOR_NAME_LEN - 1);
				break;
			}

			if (!(strncasecmp(key, COPYRIGHT_STR, strlen(COPYRIGHT_STR)))) {
				value_str = skip_space(key+strlen(COPYRIGHT_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				strncpy(hzCodeTable.Copyright, value_str, MAX_COPYRIGHT_LEN - 1);
				break;
			}

			if (!(strncasecmp(key, HINTING_STR, strlen(HINTING_STR)))) {
				value_str = skip_space(key+strlen(HINTING_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				strncpy(hzCodeTable.Hinting, value_str, MAX_HINTING_LEN - 1);
				break;
			}

			if (!(strncasecmp(key, NAME_STR, strlen(NAME_STR)))) {
				value_str = skip_space(key+strlen(NAME_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				strncpy(hzCodeTable.Cname, value_str, MAX_CHNAME_LEN - 1);
				break;
			}

			if (!(strncasecmp(key, ENCODE_STR, strlen(ENCODE_STR)))) {
				value_str = skip_space(key+strlen(ENCODE_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				hzCodeTable.Encode = get_encodeid_from_name(value_str);
				hzCodeTable.Output_Encode = hzCodeTable.Encode;
				break;
			}

			if (!(strncasecmp(key, USEDCODES_STR, strlen(USEDCODES_STR)))) {
				value_str = skip_space(key+strlen(USEDCODES_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				strncpy(hzCodeTable.UsedCodes, value_str, MAX_USEDCODES_NUM);
				break;
			}

			if (!(strncasecmp(key, WILDCHAR_STR, strlen(WILDCHAR_STR)))) {
				value_str = skip_space(key+strlen(WILDCHAR_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				strncpy(hzCodeTable.WildChar, value_str, MAX_WILDCHAR_NUM);
				break;
			}

			if (!(strncasecmp(key, MAXCODES_STR, strlen(MAXCODES_STR)))) {
				value_str = skip_space(key+strlen(MAXCODES_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

				hzCodeTable.MaxCodes = atoi(value_str) & 0xff;
				break;
			}

			break;

		case OPTIONS_SECTION:
/*
			printf("Options Section ====\n");
			printf("OPTION_OPEN_STR:%s\n", OPTION_OPEN_STR);
*/

			if (!(strncasecmp(key,KEYBYKEY_MODE_STR,strlen(KEYBYKEY_MODE_STR)))){
				value_str = skip_space(key+strlen(KEYBYKEY_MODE_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;
/*
				printf("keybykey: %s\n", value_str);
*/
				if (!(strncasecmp(value_str,OPTION_OPEN_STR, strlen(OPTION_OPEN_STR))))
					hzCodeTable.nKeyByKeyMode = ON_MODE;
				else 
					hzCodeTable.nKeyByKeyMode = OFF_MODE;
				break;
			}

			if (!(strncasecmp(key,HELPINFO_MODE_STR,strlen(HELPINFO_MODE_STR)))){
				value_str = skip_space(key+strlen(HELPINFO_MODE_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;
/*
				printf("HelpInfo: %s\n", value_str);
*/
				if (!(strncasecmp(value_str,OPTION_OPEN_STR, strlen(OPTION_OPEN_STR))))
					hzCodeTable.nHelpInfoMode = ON_MODE;
				else 
					hzCodeTable.nHelpInfoMode = OFF_MODE;
				break;
			}

			if (!(strncasecmp(key,AUTOSELECT_MODE_STR,strlen(AUTOSELECT_MODE_STR)))){
				value_str = skip_space(key+strlen(AUTOSELECT_MODE_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;
/*
				printf("AutoSelect: %s\n", value_str);
*/
				if (!(strncasecmp(value_str,OPTION_OPEN_STR, strlen(OPTION_OPEN_STR))))
					hzCodeTable.nAutoSelectMode = ON_MODE;
				else 
					hzCodeTable.nAutoSelectMode = OFF_MODE;
				break;
			}

			if (!(strncasecmp(key,KEYPROMPT_MODE_STR,strlen(KEYPROMPT_MODE_STR)))){
				value_str = skip_space(key+strlen(KEYPROMPT_MODE_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;
/*
				printf("KeyPromptMode: %s\n", value_str);
*/
				if (!(strncasecmp(value_str,OPTION_OPEN_STR, strlen(OPTION_OPEN_STR))))
					hzCodeTable.nKeyPromptMode = ON_MODE;
				else 
					hzCodeTable.nKeyPromptMode = OFF_MODE;
				break;
			}

			if (!(strncasecmp(key,DISPLAYONSPOT_MODE_STR,strlen(DISPLAYONSPOT_MODE_STR)))){
				value_str = skip_space(key+strlen(DISPLAYONSPOT_MODE_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;
/*
				printf("DisplayOnSpotMode: %s\n", value_str);
*/
				if (!(strncasecmp(value_str,OPTION_OPEN_STR, strlen(OPTION_OPEN_STR))))
					hzCodeTable.nDisplayOnSpotMode = ON_MODE;
				else 
					hzCodeTable.nDisplayOnSpotMode = OFF_MODE;
				break;
			}

			if (!(strncasecmp(key,SELECTKEY_MODE_STR,strlen(SELECTKEY_MODE_STR)))){
				value_str = skip_space(key+strlen(SELECTKEY_MODE_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;
/*
				printf("SelectKeyMode: %s\n", value_str);
*/
				hzCodeTable.nSelectKeyMode = str2val(selectkeymode_str_val, value_str);
				break;
			}

			break;

		case COMMENT_SECTION:
			ptr = line_buf;
			while (*ptr && clen < MAX_COMMENT_LEN)
				comment[clen++] = *ptr++;
			break;
		
		case FUNCTIONKEY_SECTION:
			if (!(strncasecmp(key,PAGEUP_KEY_STR,strlen(PAGEUP_KEY_STR)))){
				value_str = skip_space(key+strlen(PAGEUP_KEY_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

/*
				printf("pageup: %s\n", value_str);
*/
				ret = convert_octnum(value_str);
				if (ret == -1)
					Error("FunctionKey Error Defination");

				strncpy(functionkey[PAGEUP_KEY_ID].keylist, value_str, MAX_FUNCTIONKEY_LEN);
				break;
			}

			if (!(strncasecmp(key,PAGEDOWN_KEY_STR,strlen(PAGEDOWN_KEY_STR)))){
				value_str = skip_space(key+strlen(PAGEDOWN_KEY_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

/*
				printf("pagedown: %s\n", value_str);
*/
				ret = convert_octnum(value_str);
				if (ret == -1)
					Error("FunctionKey Error Defination");

				strncpy(functionkey[PAGEDOWN_KEY_ID].keylist, value_str, MAX_FUNCTIONKEY_LEN);
			}

			if (!(strncasecmp(key,BACKSPACE_KEY_STR,strlen(BACKSPACE_KEY_STR)))){
				value_str = skip_space(key+strlen(BACKSPACE_KEY_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

/*
				printf("backspace: %s\n", value_str);
*/
				ret = convert_octnum(value_str);
				if (ret == -1)
					Error("FunctionKey Error Defination");

				strncpy(functionkey[BACKSPACE_KEY_ID].keylist, value_str, MAX_FUNCTIONKEY_LEN);
				break;
			}
			
			if (!(strncasecmp(key,CLEARALL_KEY_STR,strlen(CLEARALL_KEY_STR)))){
				value_str = skip_space(key+strlen(CLEARALL_KEY_STR));
				if ((*value_str == '\0') || (*value_str == '\n'))
					continue;

/*
				printf("deleteall: %s\n", value_str);
*/
				ret = convert_octnum(value_str);
				if (ret == -1)
					Error("FunctionKey Error Defination");

				strncpy(functionkey[CLEARALL_KEY_ID].keylist, value_str, MAX_FUNCTIONKEY_LEN);
			}

			break;

		case KEYPROMPT_SECTION:
			ptr = key;
			kptr = keybuf;

			/* get key string */
			while (*ptr && (*ptr!=' ') && (*ptr!='\t') && (!(*ptr & 0x80))){
				*(kptr++) = *(ptr++);
			}

			*kptr = '\0';

			/* if no key string or no prompt string */
			if (!(*ptr) || !(keybuf[0])) break;

			/* get prompt characters string */
			value_str = skip_space(ptr);
			
			/* if no single character string */
			if ((*value_str == '\0') || (*value_str == '\n'))
				break;

			/* only get first string */
			vptr = value_str;
			sptr = to_space(vptr);
			*sptr = '\0';
/*
			printf("key:%s, keyprompt:%s====\n", keybuf, value_str);
*/
			strncpy(keyprompt[keybuf[0]].prompt, value_str, MAX_KEYPROMPT_LEN);
			break;

		case SINGLE_SECTION:
			ptr = key;
			kptr = keybuf;

			/* get key string */
			while (*ptr && (*ptr!=' ') && (*ptr!='\t') && (!(*ptr & 0x80))){
				*(kptr++) = tolower(*(ptr++));
			}

			*kptr = '\0';

			/* if no key string or no single string */
			if (!(*ptr) || !(keybuf[0])) break;

			/* get single characters string */
			value_str = skip_space(ptr);
			
			/* if no single character string */
			if ((*value_str == '\0') || (*value_str == '\n'))
				break;

			/* only get first string */
			vptr = value_str;
			sptr = to_space(vptr);
			*sptr = '\0';
/*
			printf("key:%s, value:%s====\n", keybuf, value_str);
*/
			InsertNode(keybuf, value_str);	

			break;

		case PHRASE_SECTION:
/*
			printf("line:%s====\n", key);
*/
			ptr = key;
			kptr = keybuf;

			/* get key string */
			while (*ptr && (*ptr!=' ') && (*ptr!='\t') && (!(*ptr & 0x80))){
				*(kptr++) = tolower(*(ptr++));
			}

			*kptr = '\0';

			/* if no key string or no phrase string */
			if (!(*ptr) || !(keybuf[0])) break;

			/* get phrase string */
			value_str = skip_space(ptr);
			
			/* if no phrase character string */
			if ((*value_str == '\0') || (*value_str == '\n'))
				break;

/*
			printf("key:%s, value:%s====\n", keybuf, value_str);
*/
			/* seperate the phrase string into single phrase */
			vptr = value_str;
			endofstr = 0;
			while (*vptr)
			{
				sptr = vptr;
				if (*sptr == '#') break; /* comment string */

				vptr = to_space(sptr);

				if (*vptr == '\0' || *vptr == '\n')
					endofstr = 1;

				*vptr = '\0';
				valuebuf[0] = HZ_PHRASE_TAG;
				valuebuf[1] = (unsigned char)(strlen(sptr));
/*
				printf("str:%s, strlen:%d\n", sptr, strlen(sptr));
*/
				strcpy(valuebuf+2, sptr);
				InsertNode(keybuf, valuebuf);
				
				if (endofstr)
					break;

				vptr = skip_space(vptr + 1);
				if (*vptr == '\n')
					break;
			}
			break;
		}
	} 
}

void Output (ofile)
FILE *ofile;
{
	int ver = CODETABLE_VERSION;

	/* write CodeTable File Flag */
	fwrite (CODETABLE_FLAG, strlen(CODETABLE_FLAG), 1, ofile);     

	/* write CodeTable Version Flag */
    	fwrite((char *)(&ver), sizeof(int), 1, ofile); 

	/* write CodeTable Header Structure */
    	if ((fwrite(&hzCodeTable, sizeof(CodeTableStruct), 1, ofile)) == 0)
    	{
		perror ("Writing output file");
		exit (1);
    	}

	/* write CodeTable Node List */
	if ((fwrite(nodeList, sizeof(tableNode), hzCodeTable.sizeNodeList, ofile))
	    	!= hzCodeTable.sizeNodeList) 
    	{
		perror ("Writing output file");
		exit (1);
    	}

	/* write CodeTable HanZi List */
	if ((fwrite(hzList, sizeof(unsigned char), hzCodeTable.sizeHZList, ofile))
	    	!= hzCodeTable.sizeHZList)
    	{
		perror ("Writing output file");
		exit (1);
    	}

	/* if [Key_Prompt] section exist, write CodeTable Key Prompt List */
	if (GETBIT(hzCodeTable.bSectionsFlag, KEYPROMPT_SECTION))
	{
		if ((fwrite(&(keyprompt[0]), MAX_USEDCODES_NUM, sizeof(keyPrompt), ofile))
	    		!= sizeof(keyPrompt))
    		{
			perror ("Writing output file");
			exit (1);
    		}
	}

	/* if [Function_Key] section exist, write CodeTable Function Key List */
	if (GETBIT(hzCodeTable.bSectionsFlag, FUNCTIONKEY_SECTION))
	{
		if ((fwrite(&(functionkey[0]),MAX_FUNCTIONKEY_NUM,sizeof(functionKey), ofile))
	    		!= sizeof(functionKey))
    		{
			perror ("Writing output file");
			exit (1);
    		}
	}
		
	/* if [Comment] section exist, write CodeTable Comment List */
	if (GETBIT(hzCodeTable.bSectionsFlag, COMMENT_SECTION))
	{
    		if ((fwrite((char *)(&clen), sizeof(unsigned int), 1, ofile)) == 0) 
    		{
			perror ("Writing output file");
			exit (1);
    		}

		if ((fwrite(comment, 1, clen, ofile)) != clen)
    		{
			perror ("Writing output file");
			exit (1);
    		}
	}
}

main(argc, argv)
int argc;
char *argv[];
{
	FILE *ifile, *ofile;
        char *inputfile_name = "wbtest.txt";
        char *outputfile_name = "test.data";

        if (argc != 3)
        {
                printf("%s inputfile outputfile\n", argv[0]);
                exit(0);
        }

        inputfile_name = argv[1];
        outputfile_name = argv[2];

/*
        printf("inputfile:%s, outputfile:%s\n",inputfile_name, outputfile_name);
*/

	ifile = fopen(inputfile_name, "r");
	if (! ifile) 
	{
	    	perror(inputfile_name);
	    	exit(1);
	}

	ofile = fopen(outputfile_name, "w+");
	if (! ofile) 
	{
		fclose(ifile);
	    	exit(1);
	}

	InitTable();

	ReadInput(ifile);
	fclose(ifile);

/*
    	PrintNode(root);
*/
    	BuildTableNode();
/*
	PrintTableInfo();
	PrintNodeList();
*/
	Output(ofile);
	fclose(ofile);

	exit(0);
}

