/* Copyright(c) 1993
   The below program is used to display chinese character in screen
   without X window in LINUX.The program is protected under GNU copyleft
   .The detailed is as GNU's COPYING which i include it in the package.
   You can distribute this program freely.But YOU MUST DISTRIBUTE THE
   COMPLETE CODE IN THE PACKAGE.If you have modified the package,you
   must note it in README file and told others how to get the origin 
   version.
*/
/************************************************************************/
/*   Build Date 08/23/1993                                              */
/*        09/08/1993                                                    */
/*           (1) Add key F9 to swap between Chinese input and english   */
/*               input.                                                 */
/************************************************************************/
/* $Id: input.c,v 0.5 1993/09/15 18:35:48 root Exp root $ */

#define CHINESE_SYSTEM
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include "chinese.h"
#include "vga.h"
#include "fullsize.h"

static  MultipleTable *mtab[10];
static void clear_inputmethod();
typedef struct {
  /* all system */
  char _pbuf[MAX_READ_BUFFER];
  int _method;
  int _state;
  char _f11buf[5] ;
  char *_tokbuf;
  char *_cachebuf;
  int _full:1;
  /* BIG 5 */
  int _parn;
  int _par;
  /* Multitable */
  int _multi_init;
  MultipleTable *_nowtab;
  CHAR _buf[4];
  HITEMLIST *_hlist;
  int _starti;
  int _loc[10];
  int _ii;
  int _swap_input_method;
  /* Phone */
  int _key;
  int mule;
  WORD firstmatch;
} ConsoleSystemTable;

ConsoleSystemTable systemtab[CONS_NUM];
static ConsoleSystemTable *nowconsole;
#define pbuf         (nowconsole->_pbuf)
#define method       (nowconsole->_method)
#define state        (nowconsole->_state)
#define f11buf       (nowconsole->_f11buf)
#define tokbuf       (nowconsole->_tokbuf)
#define cachebuf     (nowconsole->_cachebuf)
#define parn         (nowconsole->_parn)
#define par          (nowconsole->_par)
#define nowtab       (nowconsole->_nowtab)
#define mbuf          (nowconsole->_buf)
#define hlist        (nowconsole->_hlist)
#define starti       (nowconsole->_starti)
#define mloc          (nowconsole->_loc)
#define ii           (nowconsole->_ii)
#define multi_init   (nowconsole->_multi_init)
#define swap_input_method (nowconsole->_swap_input_method)
#define isfull       (nowconsole->_full)
#define mkey         (nowconsole->_key)
#define firstmatch   (nowconsole->firstmatch)
#define mule         (nowconsole->mule)
static int seqhash(char c);
static char *addfull(char *,char c);
static void *inputmethod[10];
#define TAG_X 22
#define ERROR_X 75
#define BIG5_0 0xa2af
#define BIG5_A 0xa2cf
int BIG5_inputmethod(const char *,char *,int);
void mark_inputmethod(char *);
void alert_inputmethod();
FILE *debugfile=NULL;
int Multiple_inputmethod(char *,char *,int);
int Phone_inputmethod(CHAR *,CHAR *,int );
void input_init()
{
  int i;

  debugfile = fopen("/dev/tty8","w");
  method = 0;
  for(i=0;i<CONS_NUM;i++)
    {
      nowconsole = &systemtab[i];
      method = 0;
      state = 0;
      parn = 0;
      par = 0;
      mule = 0;
      tokbuf = f11buf;
      cachebuf = pbuf;
      multi_init  = 0;
      swap_input_method = 1;
      isfull = 0;
    }
  nowconsole = &systemtab[0];
  inputmethod[0] = (void *) BIG5_inputmethod;
  inputmethod[1] = (void *) Phone_inputmethod;
  for(i=2;i<10;i++)
    inputmethod[i] =  Multiple_inputmethod;
  Multiple_inputmethod(NULL,NULL,0);
  Phone_inputmethod(NULL,NULL,0);
}
/* F11 \033[23~ switch to text */



/* 
   cache the read input into pbuf[] ,the end of the input is 
   cachebuf.The function preread is very ill-style.It should be
   rewrite recently.
*/
  
static void preread(char *buf,int len)
{
  char *ss = buf;
  int i,j;
  
  cachebuf = pbuf; 
  for(i=0;i<len;i++)
    {
      switch(state)
	{
	case 0:
	  if (*ss == 27)
	    {
	      state = 1;
	      tokbuf = f11buf;
	      *tokbuf = 27;
	      tokbuf++;
	    }
	  else
	    {
	      *cachebuf = *ss;
	      cachebuf++;
	    }
	  break;	   
	case 1:
	  if (*ss == '[')
	    {
	      state = 2;
	      *tokbuf= '[';
	      tokbuf++;
	    }
	  else
	    state = 0;
	  break;
	case 2:
	  if (*ss == '2')
	    {
	      state = 3;
	      *tokbuf++ = '2';
	    }
	  else
	    state = 0;
	  break;
	case 3:
	  switch(*ss)
	    {
	    case '3':
	      state = 4;
	      *tokbuf++ = '3';
	      break;
	    case '4':
	      state = 5;
	      *tokbuf++ = '4';
	      break;
	    case '1':
	      state = 6;
	      *tokbuf++='1';
	      break;
	    case '0':
	      state = 7;
	      *tokbuf++ = '0';
	      break;
	    }
	  break;
	case 4:
	  if (*ss == '~')
	    {
	      tokbuf = f11buf;
	      state = 0;
	      mule = (mule)? 0:1;
	      ch_inputmethod(-1);
	    }
	  break;
	case 5:
	  if (*ss == '~')
	    {
	      isfull = (isfull)? 0 : 1;
	      tokbuf = f11buf;
	      state = 0;
	      ch_inputmethod(-1);
	    }
	  else
	    state = 0;
	  break;
	case 6:
	  if (*ss == '~')
	    {
	      int oldx = ch_wherex();
	      int oldy = ch_wherey();

	      ch_goto_systemarea(TAG_X);
	      ch_system_showstr("Select a input method(0-9) ");
	      ch_gotoxy(oldx,oldy);

	      tokbuf = f11buf;
	      state = 100;
	    }
	  else
	    state = 0;
	  break;
	case 7:
	  if (*ss == '~')
	    {
	      int tmp;
	      
	      if (method == 0)
		{
		  ch_inputmethod(swap_input_method);
		  swap_input_method = 0;
		}
	      else
		{
		  clear_inputmethod();
		  swap_input_method = method;
		  ch_inputmethod(0);
		}
	      state = 0;
	      tokbuf = f11buf;
	    }
	  else
	    state = 0;
	  break;
	case 100:
	  if (*ss <='9' && *ss >='0')
	    {
	      int oldx = ch_wherex();
	      int oldy = ch_wherey();

	      ch_inputmethod(*ss-'0');
	      ch_goto_systemarea(TAG_X);
	      ch_system_showstr("                          ");
	      ch_gotoxy(oldx,oldy);
	      
	      state = 0;
	    }
	  else
	    alert_inputmethod();
	  break;
	}
      
      
      if ((state == 0) && (tokbuf != f11buf))
	{
	  memcpy(cachebuf,f11buf,tokbuf-f11buf);
	  cachebuf += (tokbuf-f11buf);
	  *cachebuf++ = *ss;
	  tokbuf = f11buf;
	}
      ss++;
    }
}

int _cread(char *buf,int len)
{
  return _ccread(0,buf,len);
}

int _ccread(int fd,char *buf,int len)
{
  INTFUNC m;
  int oldlen=len;
  
  if (!isfull)
    oldlen = (len>MAX_READ_BUFFER)? MAX_READ_BUFFER:len;
  else
    oldlen = (len>MAX_READ_BUFFER/2)? MAX_READ_BUFFER/2:len;
  len = read(fd,buf,oldlen);

  preread(buf,len);

  if (cachebuf == pbuf)
    if (len <= 0)
      return 0;
    else
      return _ccread(fd,buf,oldlen);

  if (method == 0)
    {
      len = cachebuf-pbuf;
      if (isfull)
	{
	  char *ssbuf = pbuf;
	  char *ddbuf = buf;

	  while(ssbuf != cachebuf)
	    ddbuf = addfull(ddbuf,*ssbuf++);
	  len = ddbuf-buf;
	}
      else
	memcpy(buf,pbuf,len);

      cachebuf = pbuf;
	
      return len;
    }
  else
    {
      m = (INTFUNC) inputmethod[method-1];
      if (m)
	{
	  len = m(pbuf,buf,cachebuf-pbuf);
	  cachebuf = pbuf;
	  return len;
	}
      else
	{
	  memcpy(buf,pbuf,cachebuf-pbuf);
	  cachebuf = pbuf;
	  return cachebuf-pbuf;
	}
    }
}

int ch_read_from_buffer(char *sbuf,char *dbuf,int len)
{
  INTFUNC m;
  int oldlen=len;
  
  len = (len >MAX_READ_BUFFER)? MAX_READ_BUFFER : len;

  preread(sbuf,len);

  if (cachebuf == pbuf)
    return 0;
  
  if (method == 0)
    {
      len = cachebuf-pbuf;
      if (isfull)
	{
	  char *ssbuf = pbuf;
	  char *ddbuf = dbuf;

	  while(ssbuf != cachebuf)
	    ddbuf = addfull(ddbuf,*ssbuf++);
	  len = ddbuf-dbuf;
	}
      else
	memcpy(dbuf,pbuf,len);

      cachebuf = pbuf;
      return len;
    }
  else
    {
      m = (INTFUNC) inputmethod[method-1];
      if (m)
	{
	  len = m(pbuf,dbuf,cachebuf-pbuf);
	  cachebuf = pbuf;
	  return len;
	}
      else
	{
	  memcpy(dbuf,pbuf,cachebuf-pbuf);
	  cachebuf = pbuf;
	  return cachebuf-pbuf;
	}
    }
}

char *_cgets(char *buf,int len)
{
  INTFUNC m;

  len = (len>MAX_READ_BUFFER)? MAX_READ_BUFFER:len;
  len = strlen(fgets(buf,len,stdin));
  preread(buf,len);
  if (cachebuf == pbuf)
    if (len == 0)
      return NULL;
    else
      return _cgets(buf,len);
  if (method == 0)
    {
      if (isfull)
	{
	  char *ssbuf = pbuf;
	  char *ddbuf = buf;

	  while(ssbuf != cachebuf)
	    ddbuf = addfull(ddbuf,*ssbuf++);
	}
      else
	memcpy(buf,pbuf,len);

      cachebuf = pbuf;
      return buf;
    }
  else
    {
      m = (INTFUNC) inputmethod[method-1];
      if (m)
	{
	  len = m(pbuf,buf,cachebuf-pbuf);
	  buf[len]=0;
	  cachebuf = pbuf;
	  return buf;
	}
      else
	{
	  memcpy(pbuf,buf,cachebuf-pbuf);
	  buf[cachebuf-pbuf] = 0;
	  cachebuf = pbuf;
	  return buf;
	}
    }
}

void alert_inputmethod()
{
  ch_showch(7);
}

void show_inputmethod(int c,int loc)
{
  int oldx,oldy;
  oldx = ch_wherex();
  oldy = ch_wherey();
  ch_goto_systemarea(TAG_X+loc*2);
  ch_showBIG5(c);
  ch_gotoxy(oldx,oldy);

}
void clear_inputmethod()
{
  int oldx,oldy,i;

  oldx = ch_wherex();
  oldy = ch_wherey();
  
  for(i=0;i<4;i++)
    {
      ch_goto_systemarea(TAG_X+i*2);
      ch_showBIG5(0xa140);
    }
  ch_gotoxy(oldx,oldy);

}
void error_inputmethod()
{
  int oldx = ch_wherex();
  int oldy = ch_wherey();
  
  ch_goto_systemarea(ERROR_X);
  ch_system_showstr("ERROR");
  ch_gotoxy(oldx,oldy);
}
void mark_inputmethod(char *s)
{
  int oldx = ch_wherex();
  int oldy = ch_wherey();
  int i;

  ch_goto_systemarea(TAG_X-13);
  if (mule)
      ch_system_showch('M');
  else
      ch_system_showch(' ');
  ch_goto_systemarea(TAG_X-12);
  if (isfull)
    ch_system_showstr("[全]");
  else
    ch_system_showstr("[半]");
  ch_goto_systemarea(TAG_X-8);
  for(i=0;i<6;i++)
    if (*s)
      ch_system_showch(*s++);
    else
      break;
  ch_gotoxy(oldx,oldy);
}
  
void slot_inputmethod(int slot,WORD big5)
{
  int oldx = ch_wherex();
  int oldy = ch_wherey();
  ch_goto_systemarea(TAG_X+16+slot*4);
  ch_system_showch('1'+slot);
  ch_showBIG5(big5);
  ch_gotoxy(oldx,oldy);
}
void clearslot_inputmethod()
{
  int oldx = ch_wherex();
  int oldy = ch_wherey();
  
  ch_goto_systemarea(TAG_X+16);
  ch_system_clreol();
  ch_gotoxy(oldx,oldy);
}
    
int ch_inputmethod(int i)
{
  INTFUNC m;
  if (i == -1 )
    {
      if (method == 0)
	{
	    mark_inputmethod("[英數]");
	    return;
	}
      m = inputmethod[method-1];
      m(NULL,NULL,-1);
      return;
    }
  
  if (i > 10)
    return;

  method = i;
  if (method == 0)
    mark_inputmethod("[英數]");
    
  else if (method == 1)
    BIG5_inputmethod(NULL,NULL,-1);
  else if ( method == 2)
    Phone_inputmethod(NULL,NULL,-1);
  else
    Multiple_inputmethod(NULL,NULL,i-2);
}
void ch_change_input(int newconsole)
{
  nowconsole = &systemtab[newconsole];
}
void ch_input_redraw()
{
  ch_inputmethod(-1);
}

static char *addfull(char *dbuf,char c)
{
  if ((c >=32) && (c <=126))
    {
      if (mule)
	if (ch_codesystem() == CODE_BIG5)
	  {
	    unsigned cc;
	    *dbuf++=27;*dbuf++='$';*dbuf++='(';
	    *dbuf++ = '0';
	    cc = (FULL_SIZE_FONT_CODE[(int)c-32][1]-0xa1)*(0xff-0xa1+0x7f-0x40)
	        +FULL_SIZE_FONT_CODE[(int)c-32][0]-
		(FULL_SIZE_FONT_CODE[(int)c-32][0]<0x7f ? 0x40 : 0x62);
	    *dbuf++ = (cc / (0xff-0xa1) +0xa1)&0x7f;
	    *dbuf++ = ((cc % (0xff-0xa1)) +0xa1)&0x7f;
	    *dbuf++= 27;*dbuf++='(';*dbuf++='B';
	    return dbuf;
	  }
      *dbuf++ = FULL_SIZE_FONT_CODE[(int)c-32][1];
      *dbuf++ = FULL_SIZE_FONT_CODE[(int)c-32][0];
    }
  else
    *dbuf++ = c;
  return dbuf;
}

int BIG5_inputmethod(const char *sbuf,char *dbuf,int len)
{

  int i,j,cc;
  char *dd = dbuf;
  char c;
  
  if (sbuf == NULL || dbuf == NULL || len == 0)
    {
      if (isfull)
	mark_inputmethod("[BIG5] [FULL]");
      else
	mark_inputmethod("[BIG5] [HALF]");
      clear_inputmethod();
      parn = 0;
      return 0;
    }
  for(i=0;i<len;i++)
    {
      c = *sbuf++;
      if (c <='9' && c >= '0')
	{
	  par = par*16+c-'0';
	  show_inputmethod(BIG5_0+c-'0',parn);
	  parn++;
	}
      else if (c <='F' && c >= 'A')
	{
	  par = par*16+c-'A'+10;
	  show_inputmethod(BIG5_A+c-'A',parn);
	  parn++;
	}
      else if ( c <= 'f' && c >= 'a')
	{
	  par = par*16+c-'A'+10;
	  show_inputmethod(BIG5_A + c-'a',parn);
	  parn++;
	}
      else if (c == '\b'|| c == 127)
	{
	  if (parn != 0)
	    {
	      parn--;
	      par /= 16;
	      show_inputmethod(0xa140,parn);
	    }
	  else
	    *dbuf++ = '\b';
	}
      else if ( c == 27 )
	{
	  if (parn != 0)
	    {
	      for(j=0;j<parn;j++)
		show_inputmethod(0xa140,j);
	      parn = 0;
	      par = 0;
	    }
	  else
	    *dbuf++ = 27;
	}
      else
	{
	  /* Full size font input */
	  if (isfull)
	    dbuf = addfull(dbuf,c);
	  else
	    *dbuf++ = c;
	}
      if (parn == 4)
	{
	  cc = tran_code(CODE_BIG5,par/256,par%256);
	  if (cc == 0xffff)
	    alert_inputmethod();
	  else
	    {
	      if (mule && ch_codesystem() == CODE_BIG5)
		{
		  int b1,b2;

		  b1 = par / 256;
		  b2 = par % 256;
		  cc = (b1-0xa1)*(0xff-0xa1+0x7f-0x40)+b2 - 
		             (b2 < 0x7f ? 0x40 : 0x62);
		  *dbuf++= 27;*dbuf++='$';*dbuf++='(';
		  if (par >= 0xc6a1)
		    *dbuf++ = '0';
		  else
		    *dbuf++ = '1';
		  *dbuf++ = cc / (0xff-0xa1)+ 0x21;
		  *dbuf++ = (cc % (0xff-0xa1))+0x21;
		  *dbuf++ = 27;*dbuf++='(';*dbuf++='B';
		}
	       else
		 {
		   *dbuf++ = par/256;
		   *dbuf++ = par % 256;
		 }
	     }
	   parn = par = 0;
	   for(i=0;i<4;i++)
	     show_inputmethod(0xa140,i);
	 }
     }
   return dbuf-dd;
 }




 /* Multiple input method driver */
 static void loadtable(int ,char *);
 /*static char *select_table(char **,char *,CHAR *,HITEMLIST *);*/
 static int hashvalue(char *);

 int Multiple_inputmethod(char *sbuf,char *dbuf,int len)
 {
   char *file,*dd;
   CHAR c;
   int i,j,select_word;
   InputHead *head;
   HASH2 *h2;

   FILE *def;

   /* initial internal database */

   if (sbuf == NULL && dbuf == NULL && len == 0)
     {
       if (multi_init)
	 return 0;
       multi_init = 1;
       for(i=0;i<10;i++)
	 mtab[i] = NULL;
       file = getenv("MULTIPLE");
       if (file == NULL)
	 file = "/etc/multitab";


       def = fopen(file,"r");
       if (def != NULL)
	 {
	   char *bb;
	   int tloc;

	   while(fgets(pbuf,1024,def))
	     {
	       bb = pbuf;
	       while(isspace(*bb)&&*bb) bb++;
	       if (*bb <='9' && *bb >= '0')
		 {
		   tloc  = *bb-'1';
		   bb++;
		   while(isspace(*bb)&&*bb) bb++;
		   if (*bb)
		     {
		       char *be = bb+1;
		       while(!isspace(*be)&&*be) be++;
		       *be = 0;
		       loadtable(tloc,bb);
		     }
		 }
	     }
	   fclose(def);
	 }
       else
	 {
	   adm_end();
	   fprintf(debugfile,"The input method file or MULTIPLE undefined\n");
	   exit(-1);
	 }
     }
   else if (dbuf == NULL && sbuf == NULL && len == -1)
     {
       if (nowtab)
	 mark_inputmethod(nowtab->head.mark);
       else
	 mark_inputmethod("[ERR ]");
       head = &(nowtab->head);
       for(i=0;i<((parn <= 4)? parn:4);i++)
	 show_inputmethod(head->cmap.CHKEY[head->mapkey[mbuf[i]]],i);
       if (parn == 6)
	 parn = 5;
     }

   if (dbuf == NULL && sbuf == NULL && len > 0)
     {
       nowtab = mtab[len-1];
       if (nowtab)
	 mark_inputmethod(nowtab->head.mark);
       else
	 mark_inputmethod("[ERR ]");
       parn = 0;
       clearslot_inputmethod();
       for(i=0;i<4;i++)
	 show_inputmethod(0xa140,i);
       return 0;
     }
   /* main input method drivers */
   dd = dbuf;
   if (nowtab == NULL)
     {
       alert_inputmethod();
       return 0;
     }
   head = &nowtab->head;

   for(i=0;i<len;i++)
     {
       if (parn == 5)
	 {
	   if (hlist->num == 0)
	     {
	       alert_inputmethod();
	       parn = 0;
	       for(j=0;j<4;j++)
		 show_inputmethod(0xa140,j);
	       i--;
	       continue;
	     }
	   for(i=0;i<10;i++)
	     mloc[i] = -1;
	   ii = 0;
	   j = starti;
	   for(ii=0;ii<9;ii++)
	     {
	       while((*(int *)mbuf) != (*(int *)(hlist->map[j].seqs))&&
		     (j < hlist->num)) 
		 j++;
	      if (j >= hlist->num)
		break;
	      mloc[ii] = j;

	      j++;
	    }
	  if (ii == 1 && starti == 0)
	    {
	      if (mloc[0] != -1)
		{
		  if (mule)
		    if (ch_codesystem() == CODE_BIG5)
		      {
			int ccc;
			unsigned char b1,b2;
			b1 = hlist->map[mloc[0]].word.code[1];
			b2 = hlist->map[mloc[0]].word.code[0];
			ccc = (b1-0xa1)*(0xff-0xa1+0x7f-0x40)+b2-
			  (b2<0x7f? 0x40 : 0x62);
			*dbuf++ =27;*dbuf++ ='$';*dbuf++ ='(';
			if (((b1 << 8)|b2) < 0xc6a1)
			  *dbuf++ = '0';
			else 
			  *dbuf++ = '1';
			*dbuf++ =ccc / (0xff-0xa1)+0x21;
			*dbuf++ =(ccc % (0xff-0xa1))+0x21;
			*dbuf++ =27;*dbuf++ ='(';*dbuf++ ='B';
			for(j=0;j<4;j++)
			  show_inputmethod(0xa140,j);
			parn=0;
			i--;
			continue;
		      }
		  *dbuf++ = hlist->map[mloc[0]].word.code[1];
		  *dbuf++ = hlist->map[mloc[0]].word.code[0];
		  parn = 0;
		  for(j=0;j<4;j++)
		    show_inputmethod(0xa140,j);
		  i--;
		  continue;
		}
	      else
		{
		  alert_inputmethod();
		  parn = 0;
		  i--;
		  continue;
		}
	    }
	  if (ii == 0)
	    {
	      if (starti == 0)
		{
		  for(j=0;j<4;j++)
		    show_inputmethod(0xa140,j);
		  parn = 0;
		}
	      starti = 0;i--;
	      continue;
	    }
	  else
	    starti = mloc[ii-1]+1;
	  for(j=0;j<ii;j++)
	      slot_inputmethod(j,hlist->map[mloc[j]].word.big5);
	  parn = 6;
	  i--;
	  continue;
	}
      if (parn == 6)
	{
	  if (*sbuf == ' ')
	    {
	      sbuf++;
	      parn = 5;
	      continue;
	    }
	  else if (*sbuf == 27)
	    {
	      select_word = 0;
	      parn = 0;
	      sbuf++;
	      clearslot_inputmethod();
	      clear_inputmethod();
	      continue;
	    }
	  else if ((*sbuf<='9') && (*sbuf>='1'))
	    {
	      if ((*sbuf-'1')<ii)
		{
		  select_word = *sbuf - '1';
		  sbuf++;
		}
	      else
		{
		  select_word = 0;
		  i--;
		  clearslot_inputmethod();
		  clear_inputmethod();
		}
	    }
	  else if (head->mapkey[*sbuf]!= 255)
	    {
	      i--;
	      clearslot_inputmethod();
	      select_word = 0;
	      clear_inputmethod();
	    }
	  else
	    *dbuf++ = *sbuf++;
	      
	  if (select_word >=0)
	    {
	      if (mule)
		{
		  if (ch_codesystem() == CODE_BIG5)
		    {
		      int ccc;
		      unsigned char b1,b2;
		      b1 = hlist->map[mloc[select_word]].word.code[1];
		      b2 = hlist->map[mloc[select_word]].word.code[0];
		      ccc = (b1-0xa1)*(0xff-0xa1+0x7f-0x40)+b2-
			(b2<0x7f? 0x40 : 0x62);
		      *dbuf++ =27;*dbuf++ ='$';*dbuf++ ='(';
		      if (((b1 << 8)|b2) < 0xc6a1)
			*dbuf++ = '0';
		      else 
			*dbuf++ = '1';
		      *dbuf++ =ccc / (0xff-0xa1)+0x21;
		      *dbuf++ =(ccc % (0xff-0xa1))+0x21;
		      *dbuf++ =27;*dbuf++ ='(';*dbuf++ ='B';
		      parn=0;
		      clear_inputmethod();
		      clearslot_inputmethod();
		      continue;
		    }
		}
	      
	      *dbuf++ = hlist->map[mloc[select_word]].word.code[1];
	      *dbuf++ = hlist->map[mloc[select_word]].word.code[0];
	      parn = 0;
	      clear_inputmethod();
	      clearslot_inputmethod();
	    }	
	      
	  continue;
	}
    
	      
      switch(*sbuf)
	{
	case ' ':
	  if (parn == 0)
	    {
	      *dbuf++ = ' ';
	    }
	  else
	    {
	      if (parn < 4)
		for(j=parn;j<4;j++)
		  mbuf[j] = 255;
	      h2 = &(nowtab->hash[seqhash(mbuf[0])]);
	      hlist = &(h2->item[hashvalue(mbuf)]);
	      
	      if (hlist == NULL || hlist->num == 0)
		{
		  alert_inputmethod();
		  for(j=0;j<4;j++)
		    show_inputmethod(0xa140,j);
		  parn = 0;
		  continue;
		}
	      else
		{
		  parn = 5;
		  starti = 0;
		  i--;
		  continue;
		}
	    }
	  break;
	case '\b':
	case 127:
	  if (parn == 0)
	    *dbuf++ = '\b';
	  else
	    {
	      parn--;
	      show_inputmethod(0xa140,parn);
	    }
	  break;
	case 27:
	  if (parn == 0)
	    *dbuf++ = 27;
	  else
	    {
	      clear_inputmethod();
	      parn = 0;
	    }
	  break;
	default:
	  c = *sbuf;
	  if (head->mapkey[c]!= 255)
	    {
	      if (parn == 4)
		alert_inputmethod();
	      else
		{
		  show_inputmethod(head->cmap.CHKEY[head->mapkey[c]],parn);
		  
		  mbuf[parn] = head->mapkey[c];
		  parn++;
		  
		}
	    }
	  else
	    {
	      if (!isfull)
		*dbuf++ = *sbuf;
	      else
		dbuf = addfull(dbuf,*sbuf);
	    }
	      
	}
      sbuf++;
    }
  return dbuf-dd;
}
	
      
	    


static int addmap(WordMap *m)
{
  HASH2 *h2;
  HITEMLIST *hhlist;
  int hv;
  WordMap *destmap;
  

  h2 = &(nowtab->hash[seqhash(m->seqs[0])]);
  hv = hashvalue(m->seqs);
  hhlist = &(h2->item[hv]);
  if (hhlist->map == NULL)
    {    
      hhlist->num = 0;
      hhlist->maxnum = 5;
      destmap = hhlist->map = (WordMap *) malloc(sizeof(WordMap)*5);
      if (hlist->map == NULL)
	return -1;
    }
  else
    destmap = hhlist->map;

  if (hhlist->num == hhlist->maxnum)
    {
      hhlist->maxnum+=5;
      hhlist->map = realloc(hhlist->map,sizeof(WordMap)*hhlist->maxnum);
      if (hhlist->map == NULL)
	return -1;
    }
  memcpy(&(hhlist->map[hhlist->num++]),m,sizeof(WordMap));
  return 0;
}


static void loadtable(int loc,char *name)
{
  FILE *def;
  WordMap m;
  int cc,i,j;
  
  def = fopen(name,"rb");
  if (def == NULL)
    {
      fprintf(debugfile,"Can't open %s\n",name);
      return ;
    }
  mtab[loc] = (MultipleTable *) malloc(sizeof(MultipleTable));
  if (mtab[loc] == NULL)
    return;
  fread(&(mtab[loc]->head),sizeof(InputHead),1,def);
  nowtab = mtab[loc];
  cc = 0;
  for(i=0;i<256;i++)
    if (mtab[loc]->head.keymap[i] != 0)
      cc++;
  
  nowtab->hash = (HASH2 *) malloc(sizeof(HASH2)*cc);
  nowtab->num = cc;
  for(i=0;i<cc;i++)
    for(j=0;j<HASH2_SIZE;j++)
      nowtab->hash[i].item[j].map = NULL;
  if (nowtab->hash == NULL)
    return;
  while(fread(&m,sizeof(WordMap),1,def))
    {
      if (addmap(&m) != 0)
	return;
    }
  fclose(def);
  fprintf(debugfile,"successful load multiple table %s into %d\n",name,loc);
}


showtable(int loc)
{
  MultipleTable *nnowtab;
  HASH2 *h2;
  HITEMLIST *hhlist;
  WordMap *m;
  int i,j,k;

  nnowtab = mtab[loc];
  for(i=0;i<nnowtab->num;i++)
    {
      
      h2 = &(nnowtab->hash[i]);
      for(j=0;j<HASH2_SIZE;j++)
	{
	  hhlist = &h2->item[j];
	  if (hhlist->num != 0)
	    {
	      
	      for(k=0;k<hhlist->num;k++)
		{
		  m = &hhlist->map[k];
		}
	    }
	}
    }
}


static int hashvalue(char *s)
{
  return (s[1]*16708+s[2]*708+s[3])%HASH2_SIZE;
}
static int seqhash(char c)
{
  return (c % 10);
}
FILE *chinese_debug=NULL;
fdebug(char *s,int len)
{
  if (chinese_debug != NULL)
    fwrite(s,1,len,chinese_debug);
}


/* Phone */
static void Phone_loadtable();
static CHAR *Phone_key(CHAR *,CHAR);
static void Phone_display();
static CHAR *Phone_select(CHAR *dbuf,CHAR);
static void Phone_redisplay();
#include "phone.h"
static PHONE *PhoneTable;
static int PhoneTableSize;
static CHAR phonetr[4][128];
static int mul1,mul2;
int Phone_inputmethod(CHAR *sbuf,CHAR *dbuf,int len)
{
  CHAR *dd = dbuf;
  int i;

  if (sbuf == NULL || dbuf == NULL)
    {
      parn = 0;
      for(i=0;i<4;i++) mbuf[i] = ' ';
      if (len == 0)
	{
	  Phone_loadtable();
	  return;
	}
      Phone_redisplay();
      mark_inputmethod("[注音]");
      return;
    }
  
  while(len > 0)
    {
      len--;
      switch(parn)
	{
	case 0:
	case 1:
	  dbuf = Phone_key(dbuf,*sbuf);
	  break;
	default:
	  if (parn >=6)
	    dbuf = Phone_select(dbuf,*sbuf);
	  break;
	}
      sbuf++;
    }
  return dbuf - dd;
}

static CHAR *Phone_key(CHAR *dbuf,CHAR c)
{
  int i;
  CHAR cc;

  switch(c)
    {
    case '\b':
    case 127:
      for(i=3;i>=0;i--)
	if (mbuf[i] != ' ')
	  {
	    mbuf[i] = ' ';
	    break;
	  }
      if (i == -1)
	*dbuf++ = '\b';
      else
	Phone_redisplay();
      return dbuf;
    case 27:
      if (parn != 0)
	{
	  for(i=0;i<4;i++)
	    mbuf[i] = ' ';
	  Phone_redisplay();
	  parn = 0;
	}
      else
	*dbuf++ = c;
      return dbuf;
    default:
      cc = toupper(c);
      if (cc >= 128)
	*dbuf++ = c;
      else
	{
	  if (phonetr[0][cc] != 255 && cc != ' ')
	    {
	      mbuf[0] = cc;
	      parn = 1;
	    }
	  else if (phonetr[1][cc] != 255 && cc != ' ')
	    {
	      mbuf[1] = cc;
	      parn = 1;
	    }
	  else if (phonetr[2][cc] != 255 && cc != ' ')
	    {
	      mbuf[2] = cc;
	      parn = 1;
	    }
	  else if (phonetr[3][cc] != 255)
	    {
	      parn = 1;
	      mbuf[3] = cc;
	      Phone_redisplay();
	      mkey = (phonetr[0][mbuf[0]]*mul1+phonetr[1][mbuf[1]])*256
		     +phonetr[2][mbuf[2]]*mul2+phonetr[3][mbuf[3]];
	      for(i=0;i<PhoneTableSize;i++)
		if (mkey == PhoneTable[i].index.key)
		  break;
	      if (i == PhoneTableSize)
		{
		  alert_inputmethod();
		  for(i=0;i<4;i++)
		    mbuf[i] = ' ';
		  Phone_redisplay();
		  error_inputmethod();
		  parn = 0;
		}
	      else
		{
		  parn = 5;
		  starti = firstmatch = i;
		  Phone_display();

		  return dbuf;
		}
	    }
	  else
	    *dbuf++ = c;
	}
      Phone_redisplay();
      
      return dbuf;
    }
}
	  
static void Phone_display()
{
  int i;

  clearslot_inputmethod();

  for(i=0;i<9;i++)
    if (PhoneTable[starti+i].index.key != mkey)
      break;
    else
      {
	mloc[i] = PhoneTable[starti+i].chinese.big5;
	slot_inputmethod(i,mloc[i]);
      }
       
  if (i == 9)
    starti += 9;
  else
    starti = firstmatch;
  parn = 6+i;
}

static CHAR *Phone_select(CHAR *dbuf,CHAR c)
{
  int i;

  switch(c)
    {
    case ' ':
      Phone_display();
      return dbuf;
    case 27:
      for(i=0;i<4;i++)
	mbuf[i] = ' ';
      Phone_redisplay();
      parn = 0;
      return dbuf;
    default:
      if (c >='1' && c <='9')
	if (c-'1'< parn-6)
	  {
	    c = c-'1';
	    if (mule)
	      {
		if (ch_codesystem() == CODE_BIG5)
		  {
		    int b1,b2,ccc;
		    b1 = ((CHAR *)&mloc[c])[1];
		    b2 = *(CHAR*)&mloc[c];
		    ccc = (b1-0xa1)*(0xff-0xa1+0x7f-0x40)+b2-
		          (b2<0x7f? 0x40:0x62);
		    *dbuf++=27;*dbuf++='$';*dbuf++='(';
		    if (ch_codesystem() == CODE_BIG5)
		      if (mloc[c] >= 0xc6a1)
			*dbuf++ = '1';
		      else
			*dbuf++ = '0';
		    *dbuf++ = ccc / (0xff-0xa1)+0x21;
		    *dbuf++ = (ccc % (0xff-0xa1))+0x21;
		    *dbuf++=27;*dbuf++='(';*dbuf++='B';
		    for(i=0;i<4;i++)
		      mbuf[i] = ' ';
		    clearslot_inputmethod();
		    Phone_redisplay();
		    parn = 0;
		    return dbuf;
		  }
	      }

	    *dbuf++ = ((CHAR *)&mloc[c])[1];
	    *dbuf++ = *(CHAR *)&mloc[c];
	    for(i=0;i<4;i++)
	      mbuf[i] = ' ';
	    clearslot_inputmethod();
	    Phone_redisplay();
	    parn = 0;
	    return dbuf;
	  }
      *dbuf++ = c;
      return dbuf;
    }
}
      
static void Phone_redisplay()
{
  int i;
  for(i=0;i<4;i++)
    if (mbuf[i] == ' ')
      show_inputmethod(0xa140,i);
    else
      show_inputmethod(char_to_phone[mbuf[i]-44],i);
}
      

static void Phone_loadtable()
{
  int i,j;
  char *phone;
  FILE *in;
  char buf[100];
  char cc[128][4];

  phone = getenv("PHONETABLE");
  if (phone == NULL)
    phone = "/usr/local/chinese/phone.def";
  in = fopen(phone,"r");
  if (in == NULL)
    {
      fprintf(debugfile,"Can't load phone table %s\n",phone);
      PhoneTable = NULL;
      return;
    }
  PhoneTableSize = 0;
  for(i=0;i<128;i++)
    for(j=0;j<4;j++)
      cc[i][j] = 0;
  
  while(fgets(buf,100,in))
    {
      if (buf[0] == ' ' && buf[1] == ' ' && buf[2] == ' ' && buf[3] == ' ' )
	continue;
      cc[buf[0]][0] = 1;
      cc[buf[1]][1] = 1;
      cc[buf[2]][2] = 1;
      cc[buf[3]][3] = 1;
      PhoneTableSize++;
    }
  for(mul1=i=0;i < 128;i++)
    if (cc[i][0])
      {
	phonetr[0][i] = mul1;
	mul1++;
      }
    else
      phonetr[0][i] = 255;

  for(mul1 = i =0;i<128;i++)
    if (cc[i][1] == 1)
      {
	phonetr[1][i] = mul1;
	mul1++;
      }
    else
      phonetr[1][i] = 255;

  for(mul2 = i = 0;i < 128;i++)
    if (cc[i][2] == 1)
      {
	phonetr[2][i] = mul2;
	mul2++;
      }
    else
      phonetr[2][i] = 255;

  for(mul2 = i = 0;i < 128;i++)
    if (cc[i][3] == 1)
      {
	phonetr[3][i] = mul2;
	mul2++;
      }
    else
      phonetr[3][i] = 255;

  PhoneTable = (PHONE *) malloc(sizeof(PHONE)*PhoneTableSize);
  if (PhoneTable == NULL)
    {
      fprintf(debugfile,"Out of memory in allocate phone table\n");
      return;
    }
  fseek(in,0,SEEK_SET);
  i = 0;
  while(fgets(buf,100,in))
    {
      PhoneTable[i].index.key =(phonetr[0][buf[0]]*mul1+phonetr[1][buf[1]])*256
	                       +phonetr[2][buf[2]]*mul2+phonetr[3][buf[3]];
      PhoneTable[i].chinese.code[0] = buf[6];
      PhoneTable[i].chinese.code[1] = buf[5];
      i++;
    }
  fclose(in);
  fprintf(debugfile,"Phone table loaded size = %d\n",i);
}


