/*
 *
 * UNICON - The Console Chinese & I18N
 * Copyright (c) 1999-2002
 *
 * This file is part of UNICON, a console Chinese & I18N
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * See the file COPYING directory of this archive
 * Author: see CREDITS
 */

#include 	<stdio.h>
#include 	<unistd.h>
#include 	<stdlib.h>
#include 	<stdarg.h>
#include	<string.h>
#include        <ctype.h>
#include        <time.h>
#include        <assert.h>
#include        <xl_hzinput.h>
#define         error       printf

static void UnloadInputMethod (hz_input_table * p);
static void ResetInput (HzInputTable_T * pClient);
static void FindAssociateKey (HzInputTable_T * pClient, int index);
static hz_input_table *LoadInputMethod (char *filename);
static void GetAssociatePhrases (HzInputTable_T * pClient, unsigned char *p);
static void LoadPhrase (HzInputTable_T * pClient, int phrno, char *tt);
static void FindMatchKey (HzInputTable_T * pClient);
static void FillAssociateChars (HzInputTable_T * pClient, int index);
static void FillMatchChars (HzInputTable_T * pClient, int j);

/***************************************************************************
 *                           variable defines                              *
 ***************************************************************************/
/* 6 bit a key mask */
unsigned long mask[] = {
  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
  0x3F000000, 0x3FFC0000, 0x3FFFF000, 0x3FFFFFC0, 0x3FFFFFFF, 0x3FFFFFFF,
  0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF
};

/***************************************************************************
 *                              public function                            *
 ***************************************************************************/
static hz_input_table *
LoadInputMethod (char *filename)
{
  int nread;
  FILE *fd;
  char phrase_filename[100], assoc_filename[100];
  hz_input_table *table;

  table = malloc (sizeof (hz_input_table));
  if (table == NULL)
    error ("Out of memory in LoadInputMethod");
  fd = fopen (filename, "r");
  if (fd == NULL)
    {
      error ("Cannot open input method %s", filename);
      fclose (fd);
      free (table);
      return NULL;
    }
  nread = fread (table, sizeof (hz_input_table), 1, fd);
  if (nread != 1)
    {
      error ("Cannot read file header %s", filename);
      return NULL;
    }
  if (strcmp (MAGIC_NUMBER, table->magic_number))
    {
      printf ("is not a valid tab file\n\n");
      return NULL;
    }
  table->item = (ITEM *) malloc (sizeof (ITEM) * table->TotalChar);
  //warn("Totalchar=%d\n",table->TotalChar);
  if (table->item == NULL)
    {
      error ("Gosh, cannot malloc enough memory");
      return NULL;
    }
  fread (table->item, sizeof (ITEM), table->TotalChar, fd);
  fclose (fd);

  if (table->PhraseNum > 0)
    {
      strcpy (phrase_filename, filename);
      strcat (phrase_filename, ".phr");
      strcpy (assoc_filename, filename);
      strcat (assoc_filename, ".lx");

      table->PhraseFile = fopen (phrase_filename, "r");
      table->AssocFile = fopen (assoc_filename, "r");

      if (table->PhraseFile == NULL || table->AssocFile == NULL)
	{
	  printf ("Load Phrase/Assoc File error!\n");
	  free (table);
	  return NULL;
	}
    }
  else
    {
      table->PhraseFile = table->AssocFile = NULL;
    }

  return table;
}

static void
GetAssociatePhrases (HzInputTable_T * pClient, unsigned char *p)
{
  int index, len = strlen (p);

  if (pClient->InputCount <= pClient->InputMatch)	/* All Match */
    {
      index = (int) p[len - 2] * 256 + p[len - 1];
      ResetInput (pClient);
      if (pClient->UseAssociateMode)
	{
	  FindAssociateKey (pClient, index);
	  pClient->CurrentPageIndex = pClient->StartKey;
	  pClient->MultiPageMode = 0;
	  FillAssociateChars (pClient, pClient->StartKey);
	  if (pClient->CurSelNum > 0)
	    {
	      pClient->IsAssociateMode = 1;
	    }
	}
    }
  else
    {
      int nCount = pClient->InputCount - pClient->InputMatch,
	nMatch = pClient->InputMatch, i;
      pClient->MultiPageMode =
	pClient->NextPageIndex = pClient->CurrentPageIndex = 0;
      pClient->InputCount = pClient->InputMatch = 0;

      for (i = 0; i < nCount; i++)
	pClient->save_InpKey[i] = pClient->InpKey[nMatch + i];

      bzero (pClient->InpKey, sizeof (pClient->InpKey));
      for (i = 1; i <= nCount; i++)	/* feed the additional keys */
	{
	  pClient->InpKey[pClient->InputCount] =
	    pClient->save_InpKey[pClient->InputCount++];
	  if (pClient->InputCount <= pClient->InputMatch + 1)
	    {
	      FindMatchKey (pClient);
	      pClient->MultiPageMode = 0;
	      pClient->CurrentPageIndex = pClient->StartKey;
	      FillMatchChars (pClient, pClient->StartKey);
	    }
	}
      if (pClient->InputMatch == 0)	/* left key has no match, delete */
	{
	  ResetInput (pClient);
	  return;
	}
    }
}

static void
ResetInput (HzInputTable_T * pClient)
{
  bzero (pClient->InpKey, sizeof (pClient->InpKey));
  bzero (pClient->seltab, sizeof (pClient->seltab));
  pClient->MultiPageMode = 0,
    pClient->NextPageIndex = 0, pClient->CurrentPageIndex = 0;
  pClient->CurSelNum = 0, pClient->InputCount = 0, pClient->InputMatch = 0;
  pClient->IsAssociateMode = 0;	/* lian xiang */
}

static void
FindAssociateKey (HzInputTable_T * pClient, int index)
{
  FILE *fp = pClient->cur_table->AssocFile;
  int ofs[2], offset;

  if (index < 0xB0A1)
    {
      pClient->StartKey = pClient->EndKey = 0;
      return;			/* no match */
    }

  offset = (index / 256 - 0xB0) * 94 + index % 256 - 0xA1;
  fseek (fp, offset * sizeof (int), SEEK_SET);
  fread (ofs, sizeof (int), 2, fp);
  pClient->StartKey = 72 * 94 + 1 + ofs[0];
  pClient->EndKey = 72 * 94 + 1 + ofs[1];
}

/* phrno: Phrase Number, return in tt */
static void
LoadPhrase (HzInputTable_T * pClient, int phrno, char *tt)
{
  FILE *fp = pClient->cur_table->PhraseFile;
  int ofs[2], len;

  fseek (fp, (phrno + 1) * 4, SEEK_SET);
  fread (ofs, 4, 2, fp);
  len = ofs[1] - ofs[0];

  if (len > 128 || len <= 0)
    {
      error ("phrase error %d\n", len);
      strcpy (tt, "error");
      return;
    }

  ofs[0] += (pClient->cur_table->PhraseNum + 1) * 4;
  /* Add the index area length */
  fseek (fp, ofs[0], SEEK_SET);
  fread (tt, 1, len, fp);
  tt[len] = 0;
}

/* After add/delete a char, search the matched char/phrase, update the
   pClient->StartKey/pClient->EndKey key,  save the related keys at first, 
   if no match is found, we may restore its original value
*/
static void
FindMatchKey (HzInputTable_T * pClient)
{
  pClient->save_StartKey = pClient->StartKey;
  pClient->save_EndKey = pClient->EndKey;
  pClient->save_MultiPageMode = pClient->MultiPageMode;
  pClient->save_NextPageIndex = pClient->NextPageIndex;
  pClient->save_CurrentPageIndex = pClient->CurrentPageIndex;

  pClient->val1 = pClient->InpKey[4] | (pClient->InpKey[3] << 6) |
    (pClient->InpKey[2] << 12) | (pClient->InpKey[1] << 18) |
    (pClient->InpKey[0] << 24);
  pClient->val2 = pClient->InpKey[9] | (pClient->InpKey[8] << 6) |
    (pClient->InpKey[7] << 12) | (pClient->InpKey[6] << 18) |
    (pClient->InpKey[5] << 24);

  if (pClient->InputCount == 1)
    pClient->StartKey = pClient->cur_table->KeyIndex[pClient->InpKey[0]];
  else
    pClient->StartKey = pClient->CharIndex[pClient->InputCount - 1];
  pClient->EndKey = pClient->cur_table->KeyIndex[pClient->InpKey[0] + 1];
  for (; pClient->StartKey < pClient->EndKey; pClient->StartKey++)
    {
      pClient->key1 = (pClient->cur_table->item[pClient->StartKey].key1 &
		       mask[pClient->InputCount + 5]);
      pClient->key2 = (pClient->cur_table->item[pClient->StartKey].key2 &
		       mask[pClient->InputCount]);

      if (pClient->key1 > pClient->val1)
	break;
      if (pClient->key1 < pClient->val1)
	continue;
      if (pClient->key2 < pClient->val2)
	continue;
      break;
    }
  pClient->CharIndex[pClient->InputCount] = pClient->StartKey;
}

/*  Find the matched chars/phrases and fill it into SelTab
    The starting checked index is j 
 
    The Selection Line 1xxx 2xxx,  80-20=60 60/2=30 chinese chars only
    0-9 Selection can contain only 30 chinese chars

    SelectionXMax-SelectionX-20

#define SelectionXMax  78
#define MAX_SEL_LENGTH (SelectionXMax-SelectionX-18)
*/

static void
FillAssociateChars (HzInputTable_T * pClient, int index)
{
  unsigned char str[25];
  int PhraseNo, CurLen = 0;

  pClient->CurSelNum = 0;
  while (pClient->CurSelNum < pClient->cur_table->MaxDupSel &&
	 index < pClient->EndKey && CurLen < pClient->MAX_SEL_LENGTH)
    {
      fseek (pClient->cur_table->AssocFile, index << 2, SEEK_SET);
      fread (&PhraseNo, sizeof (int), 1, pClient->cur_table->AssocFile);
      LoadPhrase (pClient, PhraseNo, str);
      strcpy (pClient->seltab[pClient->CurSelNum], str + 2);
      CurLen += strlen (pClient->seltab[pClient->CurSelNum++]);
      index++;
    }

  /* check if more than one page */
  if (index < pClient->EndKey &&
      pClient->CurSelNum == pClient->cur_table->MaxDupSel)
    {
      /* has another matched key, so enter pClient->MultiPageMode, 
         has more pages */
      pClient->NextPageIndex = index;
      pClient->MultiPageMode = 1;
    }
  else if (pClient->MultiPageMode)
    pClient->NextPageIndex = pClient->StartKey;	/* rotate selection */
  else
    pClient->MultiPageMode = 0;
}

static void
FillMatchChars (HzInputTable_T * pClient, int j)
{
  int SelNum = 0, CurLen = 0;
  //bzero( pClient->seltab, sizeof( pClient->seltab ) );

  while ((pClient->cur_table->item[j].key1 &
	  mask[pClient->InputCount + 5])
	 == pClient->val1 &&
	 (pClient->cur_table->item[j].key2 &
	  mask[pClient->InputCount])
	 == pClient->val2 &&
	 SelNum < pClient->cur_table->MaxDupSel &&
	 j < pClient->EndKey && CurLen < pClient->MAX_SEL_LENGTH)
    {
      if (pClient->cur_table->item[j].ch < 0xA1A1)
	LoadPhrase (pClient, pClient->cur_table->item[j].ch,
		    pClient->seltab[SelNum]);
      else
	{
	  memcpy (&pClient->seltab[SelNum],
		  &(pClient->cur_table->item[j].ch), 2);
	  pClient->seltab[SelNum][2] = '\0';
	}
      CurLen += strlen (pClient->seltab[SelNum++]);
      j++;
    }
  if (SelNum == 0)		/* some match found */
    {
      pClient->StartKey = pClient->save_StartKey;
      pClient->EndKey = pClient->save_EndKey;
      pClient->MultiPageMode = pClient->save_MultiPageMode;
      pClient->NextPageIndex = pClient->save_NextPageIndex;
      pClient->CurrentPageIndex = pClient->save_CurrentPageIndex;
      return;			/* keep the original selection */
    }

  pClient->CurSelNum = SelNum;

  for (SelNum = pClient->CurSelNum; SelNum < 16; SelNum++)
    pClient->seltab[SelNum][0] = '\0';	/* zero out the unused area */
  pClient->InputMatch = pClient->InputCount;	/* until now we have some matches */

  /* check if more than one page */
  if (j < pClient->EndKey &&
      (pClient->cur_table->item[j].key1 &
       mask[pClient->InputCount + 5]) == pClient->val1 &&
      (pClient->cur_table->item[j].key2 &
       mask[pClient->InputCount]) == pClient->val2 &&
      pClient->CurSelNum == pClient->cur_table->MaxDupSel)
    {
      /* has another matched key, so enter pClient->MultiPageMode, 
         has more pages */
      pClient->NextPageIndex = j;
      pClient->MultiPageMode = 1;
    }
  else if (pClient->MultiPageMode)
    {
      pClient->NextPageIndex = pClient->StartKey;	/* rotate selection */
    }
  else
    pClient->MultiPageMode = 0;
}

void
Simulate_putstr (char *p, HzInputTable_T * pClient)
{
  int index, len = strlen (p);

  if (pClient->InputCount <= pClient->InputMatch)	/* All Match */
    {
      index = (int) p[len - 2] * 256 + p[len - 1];
      ResetInput (pClient);
      if (pClient->UseAssociateMode)
	{
	  FindAssociateKey (pClient, index);
	  pClient->CurrentPageIndex = pClient->StartKey;
	  pClient->MultiPageMode = 0;
	  FillAssociateChars (pClient, pClient->StartKey);
	  if (pClient->CurSelNum > 0)
	    {
	      pClient->IsAssociateMode = 1;
	    }
	}
    }
  else
    {
      int nCount = pClient->InputCount - pClient->InputMatch,
	nMatch = pClient->InputMatch, i;

      pClient->MultiPageMode = pClient->NextPageIndex =
	pClient->CurrentPageIndex = 0;
      pClient->InputCount = pClient->InputMatch = 0;

      for (i = 0; i < nCount; i++)
	pClient->save_InpKey[i] = pClient->InpKey[nMatch + i];

      bzero (pClient->InpKey, sizeof (pClient->InpKey));
      for (i = 1; i <= nCount; i++)	/* feed the additional keys */
	{
	  pClient->InpKey[pClient->InputCount] =
	    pClient->save_InpKey[pClient->InputCount++];
	  if (pClient->InputCount <= pClient->InputMatch + 1)
	    {
	      FindMatchKey (pClient);
	      pClient->MultiPageMode = 0;
	      pClient->CurrentPageIndex = pClient->StartKey;
	      FillMatchChars (pClient, pClient->StartKey);
	    }
	}
      if (pClient->InputMatch == 0)	/* left key has no match, delete */
	{
	  ResetInput (pClient);
	  return;
	}
    }
}

int
CCE_KeyFilter (HzInputTable_T * pClient, u_char key, char *buf, int *len)
{
  int inkey = 0, vv;
  char *is_sel_key = (char *) 0;
  // long b = 0;
  switch (key)
    {
    case '\010':		/* BackSpace Ctrl+H */
    case '\177':		/* BackSpace */
      if (pClient->InputCount > 0)
	{
	  pClient->InpKey[--pClient->InputCount] = 0;
	  if (pClient->InputCount == 0)
	    {
	      ResetInput (pClient);
	    }
	  else if (pClient->InputCount < pClient->InputMatch)
	    {
	      FindMatchKey (pClient);
	      pClient->MultiPageMode = 0;
	      pClient->CurrentPageIndex = pClient->StartKey;
	      FillMatchChars (pClient, pClient->StartKey);
	    }
	  return 1;
	}
      else
	return 0;
      break;
    case '\033':		/* ESCAPE */
/*    case 0x09:  *//* tab key */
      if (pClient->InputCount > 0)
	ResetInput (pClient);
      else
	return 0;
      break;
    case '<':
    case '-':
    case ',':
    case '[':
      if (pClient->MultiPageMode)
	{
	  if (pClient->CurrentPageIndex > pClient->StartKey)
	    pClient->CurrentPageIndex = pClient->CurrentPageIndex -
	      pClient->cur_table->MaxDupSel;
	  else
	    pClient->CurrentPageIndex = pClient->StartKey;
	  if (pClient->IsAssociateMode)
	    FillAssociateChars (pClient, pClient->CurrentPageIndex);
	  else
	    FillMatchChars (pClient, pClient->CurrentPageIndex);
	  return 1;
	}
      else
	return 1;
      break;
    case '>':
    case ']':
    case '.':
    case '=':
      if (pClient->MultiPageMode)
	{
	  pClient->CurrentPageIndex = pClient->NextPageIndex;
	  if (pClient->IsAssociateMode)
	    FillAssociateChars (pClient, pClient->CurrentPageIndex);
	  else
	    FillMatchChars (pClient, pClient->CurrentPageIndex);
	  return 1;
	}
      else
	return 1;
      break;
    case ' ':
      if (pClient->CurSelNum == 0)
	return 0;
      if (pClient->seltab[0][0])
	{
	  strcpy (buf, pClient->seltab[0]);
	  *len = strlen (buf);
	  Simulate_putstr (buf, pClient);
	  return 2;
	}
      break;
    default:
      inkey = pClient->cur_table->KeyMap[key];
      is_sel_key = strchr (pClient->cur_table->selkey, key);
      vv = is_sel_key - pClient->cur_table->selkey;
      /* selkey index, strchr may return NULL */
      /* if a key is simultaneously inkey & is_sel_key, 
         then selkey first? */
      if ((!inkey && !is_sel_key) ||
	  (!inkey && is_sel_key && (pClient->CurSelNum == 0 ||
				    pClient->seltab[vv][0] == 0)))
	{
	  pClient->IsAssociateMode = 0;
	  ResetInput (pClient);
	  return 0;
	}
      if (is_sel_key && pClient->CurSelNum > 0 && pClient->seltab[vv][0])
	{
	  strcpy (buf, pClient->seltab[vv]);
	  *len = strlen (buf);
	  Simulate_putstr (buf, pClient);
	  return 2;
	}

      /* now it must be inkey? */
      pClient->IsAssociateMode = 0;
      if (inkey >= 1 && pClient->InputCount < MAX_INPUT_LENGTH)
	pClient->InpKey[pClient->InputCount++] = inkey;
      if (pClient->InputCount <= pClient->InputMatch + 1)
	{
	  FindMatchKey (pClient);
	  pClient->CurrentPageIndex = pClient->StartKey;
	  pClient->MultiPageMode = 0;
	  FillMatchChars (pClient, pClient->StartKey);
	  if (pClient->InputCount >= pClient->cur_table->MaxPress &&
	      pClient->CurSelNum == 1 && pClient->cur_table->last_full)
	    {			// left only one selection
	      strcpy (buf, pClient->seltab[0]);
	      *len = strlen (buf);
	      Simulate_putstr (buf, pClient);
	      return 2;
	    }
	  // printf ("key::%c::0x%x\n", key, key);
	  return 1;
	}
      return 1;
    }				/* switch */
  return 0;
}

long
CCE_KeyPressed (HzInputTable_T * pClient, u_char key)
{
  int inkey = 0, vv;
  char *is_sel_key = (char *) 0;
  switch (key)
    {
    case '\177':		/* BackSpace */
      if (pClient->InputCount > 0)
	{
	  pClient->InpKey[--pClient->InputCount] = 0;
	  if (pClient->InputCount == 0)
	    {
	      ResetInput (pClient);
	      return 1;
	    }
	  else if (pClient->InputCount < pClient->InputMatch)
	    {
	      FindMatchKey (pClient);
	      pClient->MultiPageMode = 0;
	      pClient->CurrentPageIndex = pClient->StartKey;
	      FillMatchChars (pClient, pClient->StartKey);
	    }
	}
      else
	return 0;
      break;
    case '\033':		/* ESCAPE */
      ResetInput (pClient);
      break;
    case '[':
      if (pClient->MultiPageMode)
	{
	  if (pClient->CurrentPageIndex > pClient->StartKey)
	    pClient->CurrentPageIndex =
	      pClient->CurrentPageIndex - pClient->cur_table->MaxDupSel;
	  else
	    pClient->CurrentPageIndex = pClient->StartKey;
	  if (pClient->IsAssociateMode)
	    FillAssociateChars (pClient, pClient->CurrentPageIndex);
	  else
	    FillMatchChars (pClient, pClient->CurrentPageIndex);
	}
      else
	return 0;
      break;
    case ']':
      if (pClient->MultiPageMode)
	{
	  pClient->CurrentPageIndex = pClient->NextPageIndex;
	  if (pClient->IsAssociateMode)
	    FillAssociateChars (pClient, pClient->CurrentPageIndex);
	  else
	    FillMatchChars (pClient, pClient->CurrentPageIndex);
	}
      else
	return 0;
      break;
    case ' ':
      ResetInput (pClient);
      return 0;
    default:
      inkey = pClient->cur_table->KeyMap[key];
      is_sel_key = strchr (pClient->cur_table->selkey, key);
      vv = is_sel_key - pClient->cur_table->selkey;
      /* selkey index, strchr may return NULL */

      /* if a key is simultaneously inkey & is_sel_key, 
         then selkey first? */
      if ((!inkey && !is_sel_key) ||
	  (!inkey && is_sel_key &&
	   (pClient->CurSelNum == 0 || pClient->seltab[vv][0] == 0)))
	{
	  pClient->IsAssociateMode = 0;
	  ResetInput (pClient);
	  break;
	}
      if (is_sel_key && pClient->CurSelNum > 0 && pClient->seltab[vv][0])
	{
	  // ResetInput(pClient);
	  break;
	}
      /* now it must be inkey? */
      pClient->IsAssociateMode = 0;
      if (inkey >= 1 && pClient->InputCount < MAX_INPUT_LENGTH)
	pClient->InpKey[pClient->InputCount++] = inkey;

      if (pClient->InputCount <= pClient->InputMatch + 1)
	{
	  FindMatchKey (pClient);
	  pClient->CurrentPageIndex = pClient->StartKey;
	  pClient->MultiPageMode = 0;
	  FillMatchChars (pClient, pClient->StartKey);
	}
      else
	return 0;
      break;
    }				/* switch */
  return (long) pClient->CurSelNum;
}

char *
szGetSelItem (HzInputTable_T * pClient, int vv)
{
  if (pClient->CurSelNum > 0 && pClient->seltab[vv][0])
    return pClient->seltab[vv];
  return NULL;
}

/*************************************************************************
 *                        public function                                *
 *************************************************************************/
void
CCE_InputInit (HzInputTable_T * p)
{
  memset (p, 0, sizeof (HzInputTable_T));
  p->MaxSelectLen = 72;
  p->MAX_SEL_LENGTH = p->MaxSelectLen - 8;
}

static void
InputCleanup (hz_input_table * p)
{
  UnloadInputMethod (p);
  // UnloadSysPhrase ();
  // UnloadUserPhrase ();
}

static void
UnloadInputMethod (hz_input_table * p)
{
  if (p == NULL)
    return;
  if (p->PhraseFile)
    fclose (p->PhraseFile);
  if (p->AssocFile)
    fclose (p->AssocFile);
  free (p->item);
  free (p);
}

hz_input_table *
CCE_LoadMethod (char *szName)
{
  hz_input_table *p;
  p = LoadInputMethod (szName);
  if (p == NULL)
    return NULL;
  return p;
}

void
CCE_UnloadMethod (hz_input_table * p)
{
  InputCleanup (p);
}

char *
CCE_DoSelectItem (HzInputTable_T * p, u_long vv, char *s)
{
  if (vv < p->CurSelNum && p->seltab[vv][0])
    {
      strcpy (s, p->seltab[vv]);
      GetAssociatePhrases (p, s);
      // ResetInput (p);
      return s;
    }
  return NULL;
}

int
CCE_ConfigureInputArea (HzInputTable_T * p, int MaxSelectLen)
{
  p->MaxSelectLen = MaxSelectLen;
  p->MAX_SEL_LENGTH = p->MaxSelectLen - 8;
  return 1;
}

int
CCE_GetInputDisplay (HzInputTable_T * p, char *buf)
{
  int i, len = p->InputCount;
  char c;
  char *q = buf;

  if (p->InputCount == 0)
    return 0;
  for (i = 0; i <= len; i++)
    {
      if (i < p->InputCount)
	c = p->cur_table->KeyName[p->InpKey[i]];
      else
	c = ' ';
      if (i == p->InputMatch && p->InputCount > p->InputMatch && i != 0)
	*q++ = '-';
      *q++ = c;
    }
  *q = '\0';
  return 1;
}

int
CCE_GetSelectDisplay (HzInputTable_T * p, char *buf)
{
  int i, pos = 0, len;
  char buf1[256];

  buf[0] = '\0';
  if (p->CurSelNum == 0)
    return 0;
  /* not first page */
  if (p->MultiPageMode && p->CurrentPageIndex != p->StartKey)
    strcat (buf, "< ");
  for (i = 0; i < p->CurSelNum; i++)
    {
      if (!p->seltab[i][0])
	{
	  if (i == 0)
	    continue;
	  else
	    break;
	}
      if (i != 9)
	sprintf (buf1, "%d%s ", i + 1, p->seltab[i]);
      else
	sprintf (buf1, "0%s ", p->seltab[i]);
      len = strlen (buf1);
      if (pos + len + 1 >= p->MaxSelectLen)
	break;
      strcat (buf, buf1);
      pos += len + 1;
    }
  /* not last page */
  if (p->MultiPageMode && p->NextPageIndex != p->StartKey)
    strcat (buf, "> ");
  return i;
}
