/*
  Copyright 2002-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.

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

#define MAX_LINE_LEN	256

typedef struct _dynNode {
  int keycode;
  int modifier;
  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,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[] = {
  { 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;

  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++;
  }
  *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(keycode, modifier, son, next)
     int keycode;
     int modifier;
     dynNode *son;
     dynNode *next;
{
  register dynNode *t = (dynNode *) malloc (sizeof(dynNode));

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

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

  kc=mo=0;

  if ((tok = (char *)strtok((char *)kptr,":")) == (char *)NULL){
    tok = "";
  }
  kc = atoi(tok);
  if ((tok = (char *)strtok((char *)NULL,":")) == (char *)NULL){
    tok = "";
  }
  mo = atoi(tok);
  flag = 0;
  printf("InsertNode: kc[%d], mo[%d], tlen[%d]\n",kc,mo,tlen);
  while (tlen--) {
    /*
      printf("tlen [%d]\n",tlen);
    */
    if(flag){
      if ((tok = (char *)strtok((char *)NULL,":")) == (char *)NULL){
        tok = "";
      }
      kc = atoi(tok);
      if ((tok = (char *)strtok((char *)NULL,":")) == (char *)NULL){
        tok = "";
      }
      mo = atoi(tok);
      printf("InsertNode: kc[%d], mo[%d], tlen[%d]\n",kc,mo,tlen);
    }
    flag = 1;
    if (tptr->son == NULL) {
      tptr->son = NewNode(kc, mo, (dynNode *)NULL, (dynNode *)NULL);
      tptr = tptr->son;
    } else if ((tptr->son->keycode > kc) || ((tptr->son->keycode == kc) && (tptr->son->modifier < mo))) {
      tptr->son = NewNode(kc, mo, (dynNode *)NULL, tptr->son);
      tptr = tptr->son;
    } else if ((tptr->son->keycode == kc) && (tptr->son->modifier == mo)) {
      tptr = tptr->son;
    } else {
      tptr = tptr->son;
      while ((tptr->next != NULL) && ((tptr->next->keycode < kc) || (tptr->next->keycode == kc) && (tptr->next->modifier < mo))) {
	tptr = tptr->next;	/* try next */
      }
      if ((tptr->next == NULL) || (tptr->next->keycode > kc) || ((tptr->next->keycode == kc) && (tptr->next->modifier > mo))) {
	tptr->next = NewNode(kc, mo, (dynNode *)NULL, tptr->next);
	tptr = tptr->next;
      } else {	/* tptr->next->key == key */
	tptr = tptr->next;
      }
    }
    kc=mo=0;
  }

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

  if (tptr->son == NULL) {
    tptr->son = NewNode (0,0, (dynNode *)NULL, (dynNode *)NULL);
    tptr->son->hzptr = (char *)malloc (strlen (hzptr) + 1);
    if (tptr->son->hzptr == NULL)
      Error ("Run out of memory");
    strcpy (tptr->son->hzptr, hzptr);
  } else if (tptr->son->keycode != 0) {
    /* new key should be the 1st son, the old one becomes the next */
    tptr->son = NewNode(0,0, (dynNode *)NULL, tptr->son);
    tptr->son->hzptr = (char *)malloc (strlen (hzptr) + 1);
    if (tptr->son->hzptr == NULL)
      Error ("Run out of memory");
    strcpy (tptr->son->hzptr, hzptr);
  } else {
    tptr->son->hzptr = (char *)realloc (tptr->son->hzptr,
					strlen (tptr->son->hzptr) + strlen (hzptr) + 1);
    if (tptr->son->hzptr == NULL)
      Error ("Run out of memory");
    strcat (tptr->son->hzptr, 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->keycode == 0) {
    char *hzptr = tptr->hzptr;

    while (*hzptr) {
      if (*hzptr != HZ_PHRASE_TAG) {
	/* a single 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].keycode = tptr->keycode;
    nodeList[ pNodeList].modifier = tptr->modifier;
    pNodeList++;
    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("keycode: %d\n", nodeList[i].keycode);
      printf("modifier: %d\n", nodeList[i].modifier);
      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->keycode != 0)
    printf("[%d] [%d]", tptr->keycode, tptr->modifier);

  if (tptr->hzptr)
    printf("PrintNode: [%s]\n", tptr->hzptr);

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

}

void PrintTableInfo()
{
  int i;

  printf("Lname:%s\n", hzCodeTable.Lname);
  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()
{
  strcpy(hzCodeTable.Lname, DEFAULT_CODETABLE_NAME);
  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 count, token_len;

  int flag_section = DEFAULT_SECTION;

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

    count = token_len = 0;
    lineno++;

    if((line_buf[0] == '#') && (line_buf[1] == '#')){
      /*
	printf("COMMENTS \n");
      */
      continue;
    }

    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')
	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, LOCALE_STR, strlen(LOCALE_STR)))) {
	value_str = skip_space(key+strlen(LOCALE_STR));
	if ((*value_str == '\0') || (*value_str == '\n'))
	  continue;

	strcpy(hzCodeTable.Lname, value_str);
	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;

	strcpy(hzCodeTable.Cname, value_str);
	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 PHRASE_SECTION:
      /*
	printf("line:%s====\n", key);
      */
      ptr = key;
      kptr = keybuf;

      /* get key string */
      while (*ptr && (*ptr!='\t') && (!(*ptr & 0x80))){
        if(*ptr == ':') count++;
	*(kptr++) = *(ptr++);
      }
      token_len = (count+1)/2;
      *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 == '#') && (*sptr++ == '#')){
	    printf("Comment in the phrase line \n");
	    break; 
	    }
	  */

	  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, token_len);
				
	  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);
}

