/* # skkinput (Simple Kana-Kanji Input)
 * kanji.c --- kanji code
 * This file is part of skkinput.
 * Copyright (C) 1997
 * Takashi SAKAMOTO (sakamoto@yajima.kuis.kyoto-u.ac.jp)
 *
 * 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, 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 skkinput; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdio.h>
#include <stdlib.h>

#include "commondef.h"
#include "kanji.h"

#ifdef DEBUG
int dump_myCharset
( struct myChar *string )
{
  while( string->chara != '\0' ){
    switch( string->charset ){
    case CHARSET_ASCII :
      printf( "ASCII:             0x%02X (%c)\n",
	      string->chara, string->chara ) ;
      break ;
#if 0
    case CHARSET_JISX0201_ROMAN :
      printf( "JISX0201-ROMAN:    0x%02X (%c)\n",
	      string->chara, string->chara ) ;
      break ;
    case CHARSET_JISX0201_KATAKANA :
      printf( "JISX0201-KATAKANA: 0x%02X \n",
	      string->chara ) ;
      break ;
#endif
    case CHARSET_JISX0208_1978 :
      printf( "JISX0208-1978:     0x%04X \n",
	      string->chara ) ;
      break ;
    case CHARSET_JISX0208_1983 :
      printf( "JISX0208-1983:     0x%04X \n",
	      string->chara ) ;
      break ;
    case CHARSET_JISX0212_1990 :
      printf( "JISX0212-1990:     0x%04X \n",
	      string->chara ) ;
      break ;
    default :
      break ;
    }
    string ++ ;
  }
  return NOERR ;
}
#endif

/*
 * バッファを初期化する関数。
 */
void init_kanjibuffer( struct KanjiBuffer *buf )
{
  buf->buffer  = buf->internal ;
  buf->bufsize = TEXTMAXLEN ;
  buf->usage   = 0 ;
  MYCHAR_SET_END_OF_STRING( buf->buffer[ 0 ] ) ;
  return ;
}

/*
 *
 */
void add_kanjibuffer
( struct KanjiBuffer *buf, struct myChar chara )
{
  if( ( buf->usage + 1 ) >= buf->bufsize ){
    if( buf->buffer == buf->internal ){
      /* TEXTBUFSIZE = TEXTMAXLEN + 1 である。理由は簡単で、最後の NUL 
       * 文字を入れるスペースが必要だから。*/ 
      buf->bufsize = ( TEXTBUFSIZE + TEXTMAXLEN ) ;
      buf->buffer = malloc
	( sizeof( struct myChar ) * ( buf->bufsize + 1 ) ) ;
      memcpy
	( buf->buffer, buf->internal, 
	  sizeof( struct myChar ) * buf->usage ) ;
    } else {
      buf->bufsize += TEXTBUFSIZE ;
      buf->buffer = realloc
	( buf->buffer, sizeof( struct myChar ) * ( buf->bufsize + 1 ) ) ;
    }
  }
  buf->buffer[ buf->usage ++ ] = chara ;
  MYCHAR_SET_END_OF_STRING( buf->buffer[ buf->usage ] ) ;
  return ;
}

void add_kanjiStringToKanjiBuffer
( struct KanjiBuffer *buf, struct myChar *string, int length )
{
  int buflength = ( ( length / TEXTBUFSIZE ) + 1 ) * TEXTBUFSIZE ;

  if( ( buf->usage + length ) >= buf->bufsize ){
    if( buf->buffer == buf->internal ){
      buf->bufsize = TEXTBUFSIZE + buflength ;
      buf->buffer = malloc
	( sizeof( struct myChar ) * ( buf->bufsize + 1 ) ) ;
      memcpy
	( buf->buffer, buf->internal, 
	  sizeof( struct myChar ) * buf->usage ) ;
    } else {
      buf->bufsize += buflength ;
      buf->buffer = realloc
	( buf->buffer, sizeof( struct myChar ) * ( buf->bufsize + 1 ) ) ;
    }
  }
  memcpy
    ( buf->buffer + buf->usage, string, sizeof( struct myChar ) * length ) ;
  buf->usage += length ;
  MYCHAR_SET_END_OF_STRING( buf->buffer[ buf->usage ] ) ;
  return ;
}

/*
 */
void close_kanjibuffer( struct KanjiBuffer *buf )
{
  if( buf->buffer != buf->internal )
    free( buf->buffer ) ;
  init_kanjibuffer( buf ) ;
  return ;
}

/*
 * ISO2022JP の G0 集合が何に変化するかを解析する関数。
 */
int iso2022jp_G0charset
( unsigned char **string, int charset )
{
  unsigned char *ptr = *string ;

  if( *( ptr ++ ) != 0x1b )
    return charset ;

  switch( *( ptr ++ ) ){
  case '\0' :
    return ERR ;
  case '(' :
    switch( *( ptr ++ ) ){
    case '\0' :
      return ERR ;
      /* G0 集合に ASCII を指示する。*/
    case 'B' :
      charset = ISO2022JP_CHARSET_ASCII ;
      break ;
      /* G0 集合に JISX0201 ROMAN を指示する。*/
    case 'J' :
      charset = ISO2022JP_CHARSET_JISX0201_ROMAN ;
      break ;
    case 'I' :
      charset = ISO2022JP_CHARSET_JISX0201_KATAKANA ;
      break ;
    default :
      /* 知らないエスケープシーケンスを見付けた場合…。*/
      break ;
    }
    break ;
  case '$' :
    switch( *( ptr ++ ) ){
      /* 予期せぬファイルの終了。*/
    case '\0' :
      return ERR ;
      /* G0 集合に JISX0208-1978 …そんなフォントあるのかなあ…を指
	 示する。*/
    case '@' :
      charset = ISO2022JP_CHARSET_JISX0208_1978 ;
      break ;
      /* G0 集合に GB2312-1980 を指示する。*/
    case 'A' :
      charset = ISO2022JP_CHARSET_GB2312_1980 ;
      break ;
      /* G0 集合に JISX0208-1983 を指示する。*/
    case 'B' :
      charset = ISO2022JP_CHARSET_JISX0208_1983 ;
      break ;
    case '(' :
      switch( *( ptr ++ ) ){
	/* 予期せぬファイルの終了。*/
      case '\0' :
	return ERR ;
	/* G0 集合に JISX0208-1978 を指示する。*/
      case '@' :
	charset = ISO2022JP_CHARSET_JISX0208_1978 ;
	break ;
	/* G0 集合に JISX0208-1983 を指示する。*/
      case 'B':
	charset = ISO2022JP_CHARSET_JISX0208_1983 ;
	break ;
	/* G0 集合に JISX0212 を指示する。*/
      case 'D' :
	charset = ISO2022JP_CHARSET_JISX0212_1990 ;
	break ;
	/* 集合に KSC5601-1987 を指示する。*/
      case 'C' :
	charset = ISO2022JP_CHARSET_KSC5601_1987 ;
	break ;
      default :
	/* 知らないエスケープシーケンスを見付けた場合…。*/
	break ;
      }
      break ;
    default :
      /* 知らないエスケープシーケンスを見付けた場合…。*/
      break ;
    }
    break ;
  case '.' :
    switch( *( ptr ++ ) ){
    case '\0' :
      return ERR ;
      /* 96 文字集合を指示する。*/
    case 'A' :
      charset = ISO2022JP_CHARSET_ISO8859_1 ;
      break ;
    case 'B' :
      charset = ISO2022JP_CHARSET_ISO8859_2 ;
      break ;
    case 'C' :
      charset = ISO2022JP_CHARSET_ISO8859_3 ;
      break ;
    case 'D' :
      charset = ISO2022JP_CHARSET_ISO8859_4 ;
      break ;
    case 'F' :
      charset = ISO2022JP_CHARSET_ISO8859_7 ;
      break ;
    case 'G' :
      charset = ISO2022JP_CHARSET_ISO8859_6 ;
      break ;
    case 'H' :
      charset = ISO2022JP_CHARSET_ISO8859_8 ;
      break ;
    case 'L' :
      charset = ISO2022JP_CHARSET_ISO8859_5 ;
    case 'M' :
      charset = ISO2022JP_CHARSET_ISO8859_9 ;
      break ;
    default :
      break ;
    }
    break ;
  default :
    /* 知らないエスケープシーケンスを見付けた場合…。*/
    break ;
  }
  *string = ptr ;
  return charset ;
}

/*
 * ISO-2022-JP 漢字コードの文字列を内部コードの文字列に変換する関数。
 *---
 * ただし、ロッキングシフトがきちんと動作していません。SI/SO ってどう
 * しよう？ 何だか正しい使い方があるみたいだけど、ISO-2022-JP の規格書っ
 * て何処にあるのかな？ iso-2022-jp.txt には SI/SO についての記述は無
 * さそうですけど。
 */
int iso2022jp_stringToMycharset
( unsigned char *string, struct myChar **wstring )
{
  int charset, length, mychar_length ;
  struct myChar *ptr ;

  /* G0 に割り当てられている文字コードは最初はアスキーのこと。*/
  charset      = CHARSET_ASCII ;
  ptr           = NULL ;
  mychar_length = 0 ;
  if( ( length = strlen( string ) ) < 0 ){
    if( wstring != NULL )
      *wstring = NULL ;
    return False ;
  }
  if( wstring != NULL ){
    ptr = ( struct myChar * )malloc
      ( sizeof( struct myChar ) * ( ( length + 1 ) ) ) ;
    *wstring = ptr ;
  }
  while( *string != '\0' ){
    /* エスケープシーケンスを発見しました。charset を交換致します。*/
    if( ( charset =
	  iso2022jp_G0charset( &string, charset ) ) == ERR ){
      break ;
    }
    /* もしここで文字列が終わっていたら…。*/
    if( *string == '\0' )
      break ;
    switch( charset ){
      /* 94 文字集合 */
    case ISO2022JP_CHARSET_ASCII :
    case ISO2022JP_CHARSET_JISX0201_ROMAN :
      if( ptr != NULL ){
	/* ASCII は ISO8859-1 の左半面に同居させてもらう。それが良いか
	 * は分からないが。*/
	ptr->charset = CHARSET_ISO8859_1 ;
	ptr->chara   = *string ;
	ptr ++ ;
      }
      mychar_length ++ ;
      string ++ ;
      break ;
    case ISO2022JP_CHARSET_JISX0201_KATAKANA :
      if( ptr != NULL ){
	/* ASCII は ISO8859-1 の左半面に同居させてもらう。それが良いか
	 * は分からないが。*/
	ptr->charset = CHARSET_JISX0201_1976 ;
	ptr->chara   = ( *string ) | 0x80 ;
	ptr ++ ;
      }
      mychar_length ++ ;
      string ++ ;
      break ;
      /* 94^n 文字集合…。でも二文字しか見てないけど…。*/
    case ISO2022JP_CHARSET_JISX0208_1978 :
    case ISO2022JP_CHARSET_JISX0208_1983 :
    case ISO2022JP_CHARSET_JISX0212_1990 :
    case ISO2022JP_CHARSET_GB2312_1980 :
    case ISO2022JP_CHARSET_KSC5601_1987 :
      if( ptr != NULL ){
	ptr->charset = CHARSET_JISX0208_1978 + 
	  ( charset - ISO2022JP_CHARSET_JISX0208_1978 ) ;
	ptr->chara   = ( unsigned short )
	  ( ( ( *string ) << 8 ) | ( *( string + 1 ) ) ) ; 
	ptr ++ ;
      }
      string ++ ;
      string ++ ;
      mychar_length ++ ;
      break ;
    case ISO2022JP_CHARSET_ISO8859_1 :
    case ISO2022JP_CHARSET_ISO8859_2 :
    case ISO2022JP_CHARSET_ISO8859_3 :
    case ISO2022JP_CHARSET_ISO8859_4 :
    case ISO2022JP_CHARSET_ISO8859_5 :
    case ISO2022JP_CHARSET_ISO8859_6 :
    case ISO2022JP_CHARSET_ISO8859_7 :
    case ISO2022JP_CHARSET_ISO8859_8 :
    case ISO2022JP_CHARSET_ISO8859_9 :
      if( ptr != NULL ){
	if( ( *string ) & 0x80 ){
	  ptr->charset = CHARSET_ISO8859_1 + 
	    ( charset - ISO2022JP_CHARSET_ISO8859_1 ) ;
	} else {
	  ptr->charset = CHARSET_ASCII ;
	}
	ptr->chara = *string ;
	ptr ++ ;
      }
      mychar_length ++ ;
      string ++ ;
      break ;
    default :
      string ++ ;
      break ;
    }
  }
  if( ptr != NULL ){
    ptr->charset = CHARSET_ASCII ;
    ptr->chara   = '\0' ;
    /* きちんと大きさを揃える…取り過ぎていた筈だから。足りなくなるこ
     * とはありえない。*/
    if( mychar_length != length ){
      ptr = ( struct myChar * )realloc
	( *wstring, sizeof( struct myChar ) * ( mychar_length + 1 ) ) ;
      *wstring = ptr ;
    }
  }
  return mychar_length ;
}

/*
 * Extended Unix Code (EUC漢字コード)を内部コードに変換する関数。
 *----
 * 今度は真面目に JISX0201-1978 から JISX0212-1990 まで扱えるようにし
 * ました。以前は出来なかったし。
 */
int extendedUnixCode_stringToMycharset
( unsigned char *string, struct myChar **wstring )
{
  int length, mychar_length ;
  int chara ;
  struct myChar *ptr = NULL ;

  /* wstring が NULL だったら、様子見になる。どの程度の容量が必要にな
   * るのかとか…。必要量は元のテキストの文字列長よりは長くなることは
   * ないを利用している。それで最初に適当にとってから、後からサイズ変
   * 更している。*/
  mychar_length = 0 ;
  length = strlen( string ) ;
  if( wstring != NULL ){
    ptr = *wstring = ( struct myChar * )
      malloc( sizeof( struct myChar ) * ( length + 1 ) ) ;
  }
  while( *string != '\0' ){
    if( *string & 0x80 ){
      chara = *string ++ ;
      if( *string == '\0' )
	goto exit_while ;
      switch( chara ){
	/* SS2 (シングルシフト) が来た場合。*/
      case 0x8E :
	if( ptr != NULL ){
	  ptr->charset = CHARSET_JISX0201_1976 ;
	  ptr->chara   = ( *string ) | 0x80 ;
	  ptr ++ ;
	}
	mychar_length ++ ;
	string ++ ;
	break ;
	/* SS3 */
      case 0x8F :
	chara = *string ++ ;
	if( *string == '\0' )
	  goto exit_while ;
	if( ptr != NULL ){
	  ptr->charset = CHARSET_JISX0212_1990 ;
	  /* 各バイトの最上位ビット(MSB)に 1 が立っているので、落とし
	   * ておく。*/
	  ptr->chara   = ( ( chara << 8 ) | *string ) & 0x7F7F ;
	  ptr ++ ;
	}
	mychar_length ++ ;
	string ++ ;
	break ;
      default :
	if( ptr != NULL ){
	  ptr->charset = CHARSET_JISX0208_1983 ;
	  /* 各バイトの最上位ビット(MSB)に 1 が立っているので、落とし
	   * ておく。*/
	  ptr->chara   = ( ( chara << 8 ) | *string ) & 0x7F7F ;
	  ptr ++ ;
	}
	mychar_length ++ ;
	string ++ ;
	break ;
      }
    } else {
      if( ptr != NULL ){
	ptr->charset = CHARSET_ASCII ;
	ptr->chara   = ( *string ) ;
	ptr ++ ;
      }
      mychar_length ++ ;
      string ++ ;
    }
  }
exit_while:
  if( ptr != NULL ){
    /* きちんと終端しましょう、と。*/
    ptr->charset = CHARSET_ASCII ;
    ptr->chara   = '\0' ;
    /* きちんと大きさを揃える…取り過ぎていた筈だから。足りなくなるこ
     * とはありえない。*/
    if( mychar_length != length ){
      ptr = ( struct myChar * )realloc
	( *wstring, sizeof( struct myChar ) * ( mychar_length + 1 ) ) ;
      *wstring = ptr ;
    }
  }
  return mychar_length ;
}

/*
 * Microsoft Kanji Code を内部漢字コードに変換する関数。
 */
int microsoftKanjiCode_stringToMycharset
( unsigned char *string, struct myChar **wstring )
{
  int length, mychar_length ;
  unsigned short chara ;
  struct myChar *ptr = NULL ;

  /* wstring が NULL だったら、様子見になる。どの程度の容量が必要にな
   * るのかとか…。必要量は元のテキストの文字列長よりは長くなることは
   * ないを利用している。それで最初に適当にとってから、後からサイズ変
   * 更している。*/
  mychar_length = 0 ;
  length = strlen( string ) ;
  if( wstring != NULL ){
    ptr = *wstring = ( struct myChar * )
      malloc( sizeof( struct myChar ) * ( length + 1 ) ) ;
  }
  while( *string != '\0' ){
    if( *string & 0x80 ){
      if( ( *string >= 0x81 && *string <= 0x9F ) ||
	  ( *string >= 0xE0 && *string <= 0xFC ) ){
	chara = *string ++ ;
	/* 予期せぬ文字列の終了。*/
	if( *string == '\0' )
	  break ;
	if( ( *string >= 0x40 && *string <= 0x7E ) ||
	    ( *string >= 0x80 && *string <= 0xFC ) ){
	  if( ptr != NULL ){
	    unsigned short c1, c2 ;

	    c1 = chara ;
	    c2 = *string ;
	    
	    ptr->charset = CHARSET_JISX0208_1983 ;
	    
	    /* SJIS から JISX0208-1983 へ変換する。*/
	    if( c1 >= 0x81 && c1 <= 0x9F ){
	      c1 -= 0x70 ;
	    } else if( c1 >= 0xE0 && c1 <= 0xFC ){
	      c1 -= 0xB0 ;
	    } else {
	      goto machigatta_sjis ;
	    }
	    if( c2 >= 0x80 )
	      c2 -- ;
	    c1 = c1 << 1 ;
	    c2 -= 0x1F ;
	    if( c2 >= 0x7F ){
	      c2 -= 0x5E ;
	    } else {
	      c1 -- ;
	    }
	    ptr->chara   = ( c1 << 8 ) | c2 ;
	    ptr ++ ;
	  }
	  mychar_length ++ ;
	}
      } else if( *string >= 0xA1 && *string <= 0xDF ){
	if( ptr != NULL ){
	  ptr->charset = CHARSET_JISX0201_1976 ;
	  ptr->chara   = ( *string ) | 0x80 ;
	  ptr ++ ;
	}
	mychar_length ++ ;
      }
    machigatta_sjis:
      string ++ ;
    } else {
      if( ptr != NULL ){
	ptr->charset = CHARSET_JISX0201_1976 ;
	ptr->chara   = ( *string ) & 0x7F ;
	ptr ++ ;
      }
      mychar_length ++ ;
      string ++ ;
    }
  }
  if( ptr != NULL ){
    /* きちんと終端しましょう、と。*/
    ptr->charset = CHARSET_ASCII ;
    ptr->chara   = '\0' ;
    /* きちんと大きさを揃える…取り過ぎていた筈だから。足りなくなるこ
     * とはありえない。*/
    if( mychar_length != length ){
      ptr = ( struct myChar * )realloc
	( *wstring, sizeof( struct myChar ) * ( mychar_length + 1 ) ) ;
      *wstring = ptr ;
    }
  }
  return mychar_length ;
}

/*
 * 漢字コードの判別をする関数。
 *--------
 * ただし、EUC 3バイトコードなんてのは知りませんからね。
 */
int check_kanjiCode( unsigned char *text, int length )
{
  unsigned char *ptr ;
  int kanji_code = KANJI_CODE_UNKNOWN ;

  for( ptr = text ; length > 0 ; length --, ptr ++ ){
    if( *ptr == '\x1b' ){
      /* エスケープ文字を見付けた場合には JIS である可能性が非常に高い。*/
      if( length < 3 ){
	/* 残りの文字が少な過ぎるから嘘でしょう。*/
	continue ;
      }
      if( ( *( ptr + 1 ) == '\x24' || *( ptr + 1 ) == '\x28' ) &&
	  *( ptr + 2 ) == '\x42' )
	return KANJI_CODE_JIS ;
      continue ;
    }
    /* この場合には EUC か SJIS かのどちらかであると考えてしまう。*/
    if( ( *ptr ) & 0x80 ){
      kanji_code = KANJI_CODE_EUC_SJIS_UNKNOWN ;
      
      /* 判別方法は次の通りとする。
       *----------
       * (1) 俗称半角仮名と呼ばれるコードらしいものがあった場合。これ
       * は、0xA1 から 0xDF の範囲にあるコードが1バイト目に来たが、２
       * バイト目には、8 bit 目が立っていないコードが来た場合に相当す
       * る。 ---> Shift JIS
       *
       * (2) 8 bit 目が立ってはいたものの、0x80 もしくは、0xA0 もしく
       * は、0xFD から 0xFD が１バイト目に来た場合。
       * -----> EUC
       *
       * (3) 第１バイト目が 0x81 から 0x9F の間にあり、第２バイト目が
       * 0x80 から 0x9E もしくは 0x9F から 0xFC の間になった場合は、判
       * 別不可能である。
       * 
       * (4) 第１バイト目が 0x81 から 0x9F の間にあり、第２バイト目が
       * 0x40 から 0x7E の間にある時は SJIS である。
       */
      if( length < 2 ){
	/* 俗称半角仮名を発見したので、SJIS であると思う。*/
	if( *ptr >= 0xA1 && *ptr <= 0xDF )
	  return KANJI_CODE_SJIS ;
	/* そうじゃなきゃ、最後まで行く。*/
	continue ;
      }
      /* Shift JIS において漢字コードの第１バイトになれない文字が来た
	 場合。*/
      if( *ptr == 0x80 || *ptr == 0xA0 || *ptr >= 0xFD )
	return KANJI_CODE_EUC ;
      /* 俗称半角仮名を見付けた場合。*/
      if( *ptr >= 0xA1 && *ptr <= 0xDF && !( *( ptr + 1 ) & 0x80 ) )
	return KANJI_CODE_SJIS ;
      /* Shift JIS に可能な第１バイトだった場合には…。*/
      if( ( *ptr >= 0x81 && *ptr <= 0x9f ) ||
	  ( *ptr >= 0xE0 && *ptr <= 0xFC ) ){
	if( *( ptr + 1 ) >= 0x40 && *( ptr + 1 ) < 0x7F )
	  return KANJI_CODE_SJIS ;
	if( *( ptr + 1 ) > 0xFC )
	  return KANJI_CODE_EUC ;
      }
      /* もはや判別不可能である。*/
      ptr ++ ;
      length -- ;
      continue ;
    }
  }
  return kanji_code ;
}

int myCharStrlen( struct myChar *string )
{
  int length ;
  if( string == NULL )
    return 0 ;
  for( length = 0 ; string->chara != '\0' ; string ++, length ++ )
    ;
  return length ;
}

int myCharStrncmp
( struct myChar *string1, struct myChar *string2, int count )
{
  while( count > 0 ){
    /* chara が違ったら、絶対に同一であることはない。*/
    if( string1->chara != string2->chara )
      return True ;
    /* JISX0201-ROMAN と ASCII ぐらいは同列に扱おうと思っているけど駄
     * 目でしょうか？ */
    if( string1->charset != string2->charset &&
	( !IS_ASCII_CHARA( *string1 ) ||
	  !IS_ASCII_CHARA( *string2 ) ) )
      return True ;
    /* この位置に来たということは、chara が同じで、共に終端されている
     * ということになるから、TRUE となる。*/
    if( string1->chara == '\0' )
      return False ;
    string1 ++ ;
    string2 ++ ;
    count -- ;
  }
  return False ;
}

int myCharStrcmp
( struct myChar *string1, struct myChar *string2 )
{
  while( string1->chara != '\0' && string2->chara != '\0' ){
    /* chara が違ったら、絶対に同一であることはない。*/
    if( string1->chara != string2->chara )
      return True ;
    /* JISX0201-ROMAN と ASCII ぐらいは同列に扱おうと思っているけど駄
     * 目でしょうか？ */
    if( string1->charset != string2->charset &&
	( !IS_ASCII_CHARA( *string1 ) ||
	  !IS_ASCII_CHARA( *string2 ) ) )
      return True ;
    /* 次の文字を見る。*/
    string1 ++ ;
    string2 ++ ;
  }
  /* 両者共に '\0' であれば、True になる。*/
  if( string1->chara == string2->chara )
    return False ;
  return True ;
}

int myCharStrcpy
( struct myChar *string1, struct myChar *string2 )
{
  while( string2->chara != '\0' ){
    *string1 ++ = *string2 ++ ;
  }
  MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

int myCharKatakanaStrcpy
( struct myChar *string1, struct myChar *string2 )
{
  while( string2->chara != '\0' ){
    if( string2->charset == CHARSET_JISX0208_1983 &&
	string2->chara >= 0x2421 &&
	string2->chara <= 0x2473 ){
      string1->charset = string2->charset ;
      string1->chara   = string2->chara + 0x0100 ;
      string1 ++ ;
      string2 ++ ;
    } else {
      *string1 ++ = *string2 ++ ;
    }
  }
  MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

int myCharStrncpy
( struct myChar *string1, struct myChar *string2, int length )
{
  while( !IS_END_OF_STRING( *string2 ) && length > 0 ){
    *string1 ++ = *string2 ++ ;
    length -- ;
  }
  if( IS_END_OF_STRING( *string2 ) && length > 0 )
    MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

/*
 * 片仮名交じりの文字列を平仮名に直してコピーする関数。
 */
int myCharHiraganaStrncpy
( struct myChar *string1, struct myChar *string2, int length )
{
  while( !IS_END_OF_STRING( *string2 ) && length > 0 ){
    /* 片仮名だったら強制的に平仮名に直してコピーする。*/
    if( string2->charset == CHARSET_JISX0208_1983 &&
	string2->chara >= 0x2521 &&
	string2->chara <= 0x2573 ){
      string1->charset = string2->charset ;
      string1->chara   = string2->chara - 0x0100 ;
      string1 ++ ;
      string2 ++ ;
    } else {
      *string1 ++ = *string2 ++ ;
    }
    length -- ;
  }
  if( IS_END_OF_STRING( *string2 ) && length > 0 )
    MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

/*
 * 平仮名片仮名交じりの文字列を平仮名と片仮名を入れ替えてコピーする関数。
 */
int myCharHiraKataStrnncpy
( struct myChar *string1, int length1,
  struct myChar *string2, int length2 )
{
  int length1_backup = length1 ;
  while( !IS_END_OF_STRING( *string2 ) &&
	 length1 > 0 &&
	 length2 > 0 ){
    /* 片仮名だったら強制的に平仮名に直してコピーする。*/
    if( string2->charset == CHARSET_JISX0208_1983 ||
	string2->charset == CHARSET_JISX0208_1978 ){
      /* 片仮名だった場合。*/
      if( string2->chara >= 0x2521 &&
	  string2->chara <= 0x2573 ){
	string1->charset = string2->charset ;
	string1->chara   = string2->chara - 0x0100 ;
	string1 ++ ;
	length1 -- ;
	string2 ++ ;
	length2 -- ;
	continue ;
      }
      /* 「ヴ」だった場合。*/
      if( string2->chara == 0x2574 ){
	string1->charset = string2->charset ;
	string1->chara   = 0x2426 ; /* 「う」 */
	string1 ++ ;
	length1 -- ;
	if( length1 > 0 ){
	  string1->charset = string2->charset ;
	  string1->chara   = 0x212b ;
	  string1 ++ ;
	  length1 -- ;
	}
	string2 ++ ;
	length2 -- ;
	continue ;
      } 
      /* 平仮名だった場合。*/
      if( string2->chara >= 0x2421 &&
	  string2->chara <= 0x2473 ){
	string1->charset = string2->charset ;
	string1->chara   = string2->chara + 0x0100 ;
	string1 ++ ;
	length1 -- ;
	string2 ++ ;
	length2 -- ;
	continue ;
      }
      /* 「う゛」だった場合。*/
      if( string2->chara == 0x2474 &&
	  length2 > 1 &&
	  ( string2[ 1 ].charset == CHARSET_JISX0208_1983 ||
	    string2[ 1 ].charset == CHARSET_JISX0208_1978 ) &&
	  string2[ 1 ].chara == 0x212b ){
	string1->charset = string2->charset ;
	string1->chara   = 0x2574 ;
	string1 ++ ;
	length1 -- ;
	string2 ++ ;
	string2 ++ ;
	length2 -- ;
	length2 -- ;
	continue ;
      }
    }
    /* それ以外の文字の場合にはそのままコピーする。*/
    *string1 ++ = *string2 ++ ;
    length1 -- ;
    length2 -- ;
  }
  if( IS_END_OF_STRING( *string2 ) && length2 > 0 && length1 > 0 )
    MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return ( length1_backup - length1 ) ;
}

/*
 * この関数は ASCII STRING を内部コード文字列にコピーする関数である。
 * 従って、漢字コードが入っていた場合には無力である。漢字コードが入っ
 * ている場合には、StringToMyChar 系の関数を使って下さい。C のコードで、
 * "abcdefg" とか書いた時にそれを myChar に変換したい時に使うだけです。
 * (それで十分。外部とのインターフェースしたかったら、ToMyChar 使うこ
 * と。)
 */
int myCharCharStrcpy
( struct myChar *string1, unsigned char *string2 )
{
  while( *string2 != '\0' ){
    MYCHAR_SET_CHARA( *string1, *string2 ) ;
    string1 ++ ;
    string2 ++ ;
  }
  MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

int myCharCharStrncpy
( struct myChar *string1, unsigned char *string2, int number )
{
  while( *string2 != '\0' && number > 0 ){
    if( ( *string2 ) & 0x80 ){
      string1->charset = CHARSET_JISX0208_1983 ;
      string1->chara   =
	( ( ( string2[ 0 ] ) << 8 ) | ( string2[ 1 ] ) ) & 0x7F7F ;
      string2 ++ ; string2 ++ ;
      number -- ;  number -- ;
    } else {
      MYCHAR_SET_CHARA( *string1, *string2 ) ;
      string2 ++ ;
      number -- ;
    }
    string1 ++ ;
  }
  if( number > 0 && *string2 == '\0' )
    MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

int myCharCharStrncmp
( struct myChar *string1, unsigned char *string2, int length )
{
  while( length > 0 ){
    if( !IS_ASCII_CHARA( *string1 ) )
      return True ;
    if( string1->chara != *string2 )
      return True ;
    /* 次の文字を見る。*/
    string1 ++ ;
    string2 ++ ;
    length -- ;
  }
  return False ;
}

int myCharCharStrcmp
( struct myChar *string1, unsigned char *string2 )
{
  while( *string2 != '\0' && !IS_END_OF_STRING( *string1 ) ){
    if( !IS_ASCII_CHARA( *string1 ) )
      return True ;
    if( string1->chara != *string2 )
      return True ;
    /* 次の文字を見る。*/
    string1 ++ ;
    string2 ++ ;
  }
  if( *string2 == '\0' && IS_END_OF_STRING( *string1 ) )
    return False ;
  return True ;
}

int myCharStrcat
( struct myChar *string1, struct myChar *string2 )
{
  /* 文字列の一番最後を探す。*/
  while( !IS_END_OF_STRING( *string1 ) )
    string1 ++ ;
  /* 文字列に足して行く。*/
  while( !IS_END_OF_STRING( *string2 ) ){
    *string1 ++ = *string2 ++ ;
  }
  MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

int myCharStrncat
( struct myChar *string1, struct myChar *string2, int length )
{
  /* 文字列の一番最後を探す。*/
  while( !IS_END_OF_STRING( *string1 ) )
    string1 ++ ;
  /* 文字列に足して行く。*/
  while( length > 0 && !IS_END_OF_STRING( *string2 ) ){
    *string1 ++ = *string2 ++ ;
    length -- ;
  }
  MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

int myCharHiraganaStrncat
( struct myChar *string1, struct myChar *string2, int length )
{
  /* 文字列の一番最後を探す。*/
  while( !IS_END_OF_STRING( *string1 ) )
    string1 ++ ;
  /* 文字列に足して行く。*/
  while( length > 0 && !IS_END_OF_STRING( *string2 ) ){
    /* 片仮名だったら強制的に平仮名に直してコピーする。*/
    if( string2->charset == CHARSET_JISX0208_1983 &&
	string2->chara >= 0x2521 &&
	string2->chara <= 0x2573 ){
      string1->charset = string2->charset ;
      string1->chara   = string2->chara - 0x0100 ;
      string1 ++ ;
      string2 ++ ;
    } else {
      *string1 ++ = *string2 ++ ;
    }
    length -- ;
  }
  MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

int myCharHiraKataStrnncat
( struct myChar *string1, int length1, struct myChar *string2, int length2 )
{
  int length1_backup = length1 ;
  /* 文字列の一番最後を探す。*/
  while( !IS_END_OF_STRING( *string1 ) )
    string1 ++ ;
  /* 文字列に足して行く。*/
  while( !IS_END_OF_STRING( *string2 ) &&
	 length1 > 0 && length2 ){
    /* 片仮名だったら強制的に平仮名に直してコピーする。*/
    if( string2->charset == CHARSET_JISX0208_1983 ||
	string2->charset == CHARSET_JISX0208_1978 ){
      /* 片仮名だった場合。*/
      if( string2->chara >= 0x2521 &&
	  string2->chara <= 0x2573 ){
	string1->charset = string2->charset ;
	string1->chara   = string2->chara - 0x0100 ;
	string1 ++ ;
	length1 -- ;
	string2 ++ ;
	length2 -- ;
	continue ;
      }
      /* 「ヴ」だった場合。*/
      if( string2->chara == 0x2574 ){
	string1->charset = string2->charset ;
	string1->chara   = 0x2474 ;
	length1 -- ;
	if( length1 > 0 ){
	  string1->charset = string2->charset ;
	  string1->chara   = 0x212b ;
	  length1 -- ;
	}
	length2 -- ;
	continue ;
      } 
      /* 平仮名だった場合。*/
      if( string2->chara >= 0x2421 &&
	  string2->chara <= 0x2473 ){
	string1->charset = string2->charset ;
	string1->chara   = string2->chara + 0x0100 ;
	string1 ++ ;
	length1 -- ;
	string2 ++ ;
	length2 -- ;
	continue ;
      }
      /* 「う゛」だった場合。*/
      if( string2->chara == 0x2474 &&
	  length2 > 1 &&
	  ( string2[ 1 ].charset == CHARSET_JISX0208_1983 ||
	    string2[ 1 ].charset == CHARSET_JISX0208_1978 ) &&
	  string2[ 1 ].chara == 0x212b ){
	string1->charset = string2->charset ;
	string1->chara   = 0x2574 ;
	string1 ++ ;
	length1 -- ;
	string2 ++ ;
	string2 ++ ;
	length2 -- ;
	length2 -- ;
	continue ;
      }
    }
    /* それ以外の文字の場合にはそのままコピーする。*/
    *string1 ++ = *string2 ++ ;
    length1 -- ;
    length2 -- ;
  }
  MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return ( length1_backup - length1 ) ;
}

int myCharCharStrncat
( struct myChar *string1, unsigned char *string2, int length )
{
  /* 文字列の一番最後を探す。*/
  while( !IS_END_OF_STRING( *string1 ) )
    string1 ++ ;
  /* 文字列に足して行く。*/
  while( length > 0 && *string2 != '\0' ){
    MYCHAR_SET_CHARA( *string1, *string2 ) ;
    string1 ++ ;
    string2 ++ ;
  }
  MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

int myCharCharStrcat
( struct myChar *string1, unsigned char *string2 )
{
  /* 文字列の一番最後を探す。*/
  while( !IS_END_OF_STRING( *string1 ) )
    string1 ++ ;
  /* 文字列に足して行く。*/
  while( *string2 != '\0' ){
    MYCHAR_SET_CHARA( *string1, *string2 ) ;
    string1 ++ ;
    string2 ++ ;
  }
  MYCHAR_SET_END_OF_STRING( *string1 ) ;
  return True ;
}

int myCharItoa( struct myChar *string, int value )
{
  int i, j ;
  for( i = 0, j = value ; j != 0 ; i ++, j = j / 10 )
    ;
  if( i == 0 ){
    MYCHAR_SET_CHARA( string[ 0 ], '0' ) ;
    MYCHAR_SET_END_OF_STRING( string[ 1 ] ) ;
    return True ;
  }
  MYCHAR_SET_END_OF_STRING( string[ i ] ) ;
  i -- ;
  for( j = value ; i >= 0 ; i -- ){
    MYCHAR_SET_CHARA( string[ i ], '0' + ( j % 10 ) ) ;
    j = j / 10 ;
  }
  return True ;
}

/*
 * 今回は EUC で書き込むことを考えている。将来的には、もっと多国語を扱
 * えるようにする必要があるかもしれない。
 */
int myCharFputEUCc( struct myChar chara, FILE *fp )
{
  switch( chara.charset ){
  case CHARSET_ASCII :
    fputc( chara.chara, fp ) ;
    break ;
  case CHARSET_JISX0201_1976 :
    if( chara.chara & 0x80 ){
      /* シングルシフト SS1 を送る。*/
      fputc( 0x8e, fp ) ;
    }
    fputc( ( chara.chara & 0x00FF ), fp ) ;
    break ;
  case CHARSET_JISX0208_1978 :
  case CHARSET_JISX0208_1983 :
    fputc( ( chara.chara >> 8     ) | 0x80, fp ) ;
    fputc( ( chara.chara & 0x00FF ) | 0x80, fp ) ;
    break ;
    /* JISX0212-1990 …伝説の EUC 3 Byte Code だ！ */
  case CHARSET_JISX0212_1990 :
    /* シングルシフト SS2 を送る。*/
    fputc( 0x8f, fp ) ;
    fputc( ( chara.chara >> 8     ) | 0x80, fp ) ;
    fputc( ( chara.chara & 0x00FF ) | 0x80, fp ) ;
    break ;
  default :
    /* それ以外の charset は EUC では表現できないので、送れないっす。
     * ここが弱いところなんだけどねえ…。*/
    break ;
  }
  return True ;
}

/*
 * バッファを初期化する関数。
 */
void init_messagebuffer( struct MessageBuffer *buf )
{
  buf->buffer  = buf->internal ;
  buf->bufsize = TEXTMAXLEN ;
  buf->usage   = 0 ;
  buf->buffer[ 0 ] = '\0' ;
  return ;
}

/*
 *
 */
void add_messagebuffer
( struct MessageBuffer *buf, int chara )
{
  if( ( buf->usage + 1 ) >= buf->bufsize ){
    if( buf->buffer == buf->internal ){
      /* TEXTBUFSIZE = TEXTMAXLEN + 1 である。理由は簡単で、最後の NUL 
       * 文字を入れるスペースが必要だから。*/ 
      buf->bufsize = ( TEXTBUFSIZE + TEXTMAXLEN ) ;
      buf->buffer = malloc
	( sizeof( unsigned char ) * ( buf->bufsize + 1 ) ) ;
      memcpy
	( buf->buffer, buf->internal, 
	  sizeof( unsigned char ) * buf->usage ) ;
    } else {
      buf->bufsize += TEXTBUFSIZE ;
      buf->buffer = realloc
	( buf->buffer, sizeof( unsigned char ) * ( buf->bufsize + 1 ) ) ;
    }
  }
  buf->buffer[ buf->usage ++ ] = chara ;
  buf->buffer[ buf->usage    ] = '\0' ;
  return ;
}

/*
 */
void close_messagebuffer( struct MessageBuffer *buf )
{
  if( buf->buffer != buf->internal )
    free( buf->buffer ) ;
  init_messagebuffer( buf ) ;
  return ;
}

void myCharFputstring( FILE *fp, struct myChar *string )
{
  while( !IS_END_OF_STRING( *string ) ){
    myCharFputEUCc( *string, fp ) ;
    string ++ ;
  }
  return ;
}

void myCharFputstrning( FILE *fp, struct myChar *string, int len )
{
  while( !IS_END_OF_STRING( *string ) && len > 0 ){
    myCharFputEUCc( *string, fp ) ;
    string ++ ;
    len -- ;
  }
  return ;
}

struct myChar *mychar_readOneLine( FILE *fp, int coding_system )
{
  struct MessageBuffer kanji_buf ;
  struct myChar *ptr = NULL ;
  int chara ;

  init_messagebuffer( &kanji_buf ) ;
  while( ( chara = fgetc( fp ) ) != EOF ){
    if( chara == '\n' || chara == '\r' )
      break ;
    add_messagebuffer( &kanji_buf, chara ) ;
  }
  switch( coding_system ){
  case KANJI_CODE_EUC :
    extendedUnixCode_stringToMycharset( kanji_buf.buffer, &ptr ) ;
    break ;
  case KANJI_CODE_JIS :
    iso2022jp_stringToMycharset( kanji_buf.buffer, &ptr ) ;
    break ;
  case KANJI_CODE_SJIS :
    microsoftKanjiCode_stringToMycharset( kanji_buf.buffer, &ptr ) ;
    break ;
  default :
    break ;
  }
  close_messagebuffer( &kanji_buf ) ;
  return ptr ;
}

int myCharAtoi( struct myChar *string )
{
  int value = 0 ;
  while( !IS_END_OF_STRING( *string ) &&
	 IS_ASCII_CHARA( *string ) &&
	 string->chara >= '0' &&
	 string->chara <= '9' ){
    value = value * 10 + ( string->chara - '0' ) ;
    string ++ ;
  }
  return value ;
}

unsigned char *myCharStringToAsciiString( struct myChar *string )
{
  unsigned char *asciiString, *cptr ;
  struct myChar *wptr ;
  int length ;

  length = 0 ;
  for( wptr = string ; !IS_END_OF_STRING( *wptr ) ; wptr ++ ){
    if( IS_ASCII_CHARA( *wptr ) )
      length ++ ;
  }
  asciiString = malloc( sizeof( unsigned char ) * ( length + 1 ) ) ;
  if( asciiString == NULL ){
    fprintf( stderr, "Memory exhaust.\n" ) ;
    exit( 1 ) ;
  }
  for( wptr = string, cptr = asciiString ;
       !IS_END_OF_STRING( *wptr ) ; wptr ++ ){
    if( IS_ASCII_CHARA( *wptr ) )
      *cptr ++ = wptr->chara ;
  }
  *cptr = '\0' ;
  return asciiString ;
}

