OSDN Git Service

* change order of definitions.
authorNARUSE, Yui <naruse@users.sourceforge.jp>
Thu, 24 Jan 2008 08:24:30 +0000 (08:24 +0000)
committerNARUSE, Yui <naruse@users.sourceforge.jp>
Thu, 24 Jan 2008 08:24:30 +0000 (08:24 +0000)
nkf.c

diff --git a/nkf.c b/nkf.c
index a61258e..1cd2461 100644 (file)
--- a/nkf.c
+++ b/nkf.c
@@ -30,7 +30,7 @@
  * \e$B8=:_!"\e(Bnkf \e$B$O\e(B SorceForge \e$B$K$F%a%s%F%J%s%9$,B3$1$i$l$F$$$^$9!#\e(B
  * http://sourceforge.jp/projects/nkf/
 ***********************************************************************/
-#define NKF_IDENT "$Id: nkf.c,v 1.167 2008/01/23 09:21:39 naruse Exp $"
+#define NKF_IDENT "$Id: nkf.c,v 1.168 2008/01/23 23:24:30 naruse Exp $"
 #define NKF_VERSION "2.0.8"
 #define NKF_RELEASE_DATE "2008-01-23"
 #define COPY_RIGHT \
@@ -321,12 +321,7 @@ struct input_code{
 static char *input_codename = NULL; /* NULL: unestablished, "": BINARY */
 static nkf_encoding *input_encoding = NULL;
 static nkf_encoding *output_encoding = NULL;
-static void set_output_encoding(nkf_encoding *enc);
 
-#if !defined(PERL_XS) && !defined(WIN32DLL)
-static  nkf_char     noconvert(FILE *f);
-#endif
-static  void    module_connection(void);
 static  nkf_char     kanji_convert(FILE *f);
 static  nkf_char     h_conv(FILE *f,nkf_char c2,nkf_char c1);
 static  nkf_char     push_hold_buf(nkf_char c2);
@@ -352,14 +347,7 @@ static  int     no_cp932ext_f = FALSE;
 static  int     no_best_fit_chars_f = FALSE;
 static  int     input_endian = ENDIAN_BIG;
 static  nkf_char     unicode_subchar = '?'; /* the regular substitution character */
-static  void    nkf_each_char_to_hex(void (*f)(nkf_char c2,nkf_char c1), nkf_char c);
-static  void    encode_fallback_html(nkf_char c);
-static  void    encode_fallback_xml(nkf_char c);
-static  void    encode_fallback_java(nkf_char c);
-static  void    encode_fallback_perl(nkf_char c);
-static  void    encode_fallback_subchar(nkf_char c);
 static  void    (*encode_fallback)(nkf_char c) = NULL;
-static  nkf_char     w2e_conv(nkf_char c2,nkf_char c1,nkf_char c0,nkf_char *p2,nkf_char *p1);
 static  nkf_char       unicode_to_jis_common(nkf_char c2,nkf_char c1,nkf_char c0,nkf_char *p2,nkf_char *p1);
 static  nkf_char       w_iconv_common(nkf_char c1,nkf_char c0,const unsigned short *const *pp,nkf_char psize,nkf_char *p2,nkf_char *p1);
 static  void    w16w_conv(nkf_char val, nkf_char *p2, nkf_char *p1, nkf_char *p0);
@@ -374,17 +362,11 @@ static  nkf_char     e2w_conv(nkf_char c2,nkf_char c1);
 #endif
 static  nkf_char     e2s_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1);
 static  void    fold_conv(nkf_char c2,nkf_char c1);
-static  void    nl_conv(nkf_char c2,nkf_char c1);
+static  void    eol_conv(nkf_char c2,nkf_char c1);
 static  void    z_conv(nkf_char c2,nkf_char c1);
 static  void    rot_conv(nkf_char c2,nkf_char c1);
 static  void    hira_conv(nkf_char c2,nkf_char c1);
-static  void    base64_conv(nkf_char c2,nkf_char c1);
 static  void    iso2022jp_check_conv(nkf_char c2,nkf_char c1);
-static  void    no_connection(nkf_char c2,nkf_char c1);
-static  nkf_char     no_connection2(nkf_char c2,nkf_char c1,nkf_char c0);
-
-static  void    code_score(struct input_code *ptr);
-static  void    code_status(nkf_char c);
 
 static  void    std_putc(nkf_char c);
 static  nkf_char     std_getc(FILE *f);
@@ -393,30 +375,9 @@ static  nkf_char     std_ungetc(nkf_char c,FILE *f);
 static  nkf_char     broken_getc(FILE *f);
 static  nkf_char     broken_ungetc(nkf_char c,FILE *f);
 
-static  nkf_char     mime_begin(FILE *f);
 static  nkf_char     mime_getc(FILE *f);
-static  nkf_char     mime_ungetc(nkf_char c,FILE *f);
-
-static  void    switch_mime_getc(void);
-static  void    unswitch_mime_getc(void);
-static  nkf_char     mime_begin_strict(FILE *f);
-static  nkf_char     mime_getc_buf(FILE *f);
-static  nkf_char     mime_ungetc_buf(nkf_char c,FILE *f);
-static  nkf_char     mime_integrity(FILE *f,const unsigned char *p);
-
-static  nkf_char     base64decode(nkf_char c);
-static  void    mime_prechar(nkf_char c2, nkf_char c1);
-static  void    mime_putc(nkf_char c);
-static  void    open_mime(nkf_char c);
-static  void    close_mime(void);
-static  void    eof_mime(void);
-static  void    mimeout_addchar(nkf_char c);
-#ifndef PERL_XS
-static  void    usage(void);
-static  void    show_configuration(void);
-#endif
-static  void    options(unsigned char *c);
-static  void    reinit(void);
+
+static void mime_putc(nkf_char c);
 
 /* buffers */
 
@@ -427,17 +388,6 @@ static unsigned char   stdobuf[IOBUF_SIZE];
 static unsigned char   hold_buf[HOLD_SIZE*2];
 static int             hold_count = 0;
 
-/* MIME preprocessor fifo */
-
-#define MIME_BUF_SIZE   (1024)    /* 2^n ring buffer */
-#define MIME_BUF_MASK   (MIME_BUF_SIZE-1)
-#define Fifo(n)         mime_buf[(n)&MIME_BUF_MASK]
-static unsigned char           mime_buf[MIME_BUF_SIZE];
-static unsigned int            mime_top = 0;
-static unsigned int            mime_last = 0;  /* decoded */
-static unsigned int            mime_input = 0; /* undecoded */
-static nkf_char (*mime_iconv_back)(nkf_char c2,nkf_char c1,nkf_char c0) = NULL;
-
 /* flags */
 static int             unbuf_f = FALSE;
 static int             estab_f = FALSE;
@@ -459,22 +409,16 @@ static int             iso2022jp_f = FALSE;    /* replace non ISO-2022-JP with G
 static int nfc_f = FALSE;
 static nkf_char (*i_nfc_getc)(FILE *) = std_getc; /* input of ugetc */
 static nkf_char (*i_nfc_ungetc)(nkf_char c ,FILE *f) = std_ungetc;
-static nkf_char nfc_getc(FILE *f);
-static nkf_char nfc_ungetc(nkf_char c,FILE *f);
 #endif
 
 #ifdef INPUT_OPTION
 static int cap_f = FALSE;
 static nkf_char (*i_cgetc)(FILE *) = std_getc; /* input of cgetc */
 static nkf_char (*i_cungetc)(nkf_char c ,FILE *f) = std_ungetc;
-static nkf_char cap_getc(FILE *f);
-static nkf_char cap_ungetc(nkf_char c,FILE *f);
 
 static int url_f = FALSE;
 static nkf_char (*i_ugetc)(FILE *) = std_getc; /* input of ugetc */
 static nkf_char (*i_uungetc)(nkf_char c ,FILE *f) = std_ungetc;
-static nkf_char url_getc(FILE *f);
-static nkf_char url_ungetc(nkf_char c,FILE *f);
 #endif
 
 #define PREFIX_EUCG3   NKF_INT32_C(0x8F00)
@@ -489,8 +433,6 @@ static nkf_char url_ungetc(nkf_char c,FILE *f);
 static int numchar_f = FALSE;
 static nkf_char (*i_ngetc)(FILE *) = std_getc; /* input of ugetc */
 static nkf_char (*i_nungetc)(nkf_char c ,FILE *f) = std_ungetc;
-static nkf_char numchar_getc(FILE *f);
-static nkf_char numchar_ungetc(nkf_char c,FILE *f);
 #endif
 
 #ifdef CHECK_OPTION
@@ -523,21 +465,11 @@ static int cp932inv_f = TRUE;
 
 #ifdef X0212_ENABLE
 static int x0212_f = FALSE;
-static nkf_char x0212_shift(nkf_char c);
-static nkf_char x0212_unshift(nkf_char c);
 #endif
 static int x0213_f = FALSE;
 
 static unsigned char prefix_table[256];
 
-static void set_code_score(struct input_code *ptr, nkf_char score);
-static void clr_code_score(struct input_code *ptr, nkf_char score);
-static void status_disable(struct input_code *ptr);
-static void status_push_ch(struct input_code *ptr, nkf_char c);
-static void status_clear(struct input_code *ptr);
-static void status_reset(struct input_code *ptr);
-static void status_reinit(struct input_code *ptr);
-static void status_check(struct input_code *ptr, nkf_char c);
 static void e_status(struct input_code *, nkf_char);
 static void s_status(struct input_code *, nkf_char);
 
@@ -576,12 +508,25 @@ static unsigned char   ascii_intro = DEFAULT_R;
 static int             fold_margin  = FOLD_MARGIN;
 
 /* process default */
+
+nkf_char no_connection2(nkf_char c2, nkf_char c1, nkf_char c0)
+{
+    fprintf(stderr,"nkf internal module connection failure.\n");
+    exit(1);
+    return 0; /* LINT */
+}
+
+void no_connection(nkf_char c2, nkf_char c1)
+{
+    no_connection2(c2,c1,0);
+}
+
 static nkf_char (*iconv)(nkf_char c2,nkf_char c1,nkf_char c0) = no_connection2;
 static void (*oconv)(nkf_char c2,nkf_char c1) = no_connection;
 
 static void (*o_zconv)(nkf_char c2,nkf_char c1) = no_connection;
 static void (*o_fconv)(nkf_char c2,nkf_char c1) = no_connection;
-static void (*o_nlconv)(nkf_char c2,nkf_char c1) = no_connection;
+static void (*o_eol_conv)(nkf_char c2,nkf_char c1) = no_connection;
 static void (*o_rot_conv)(nkf_char c2,nkf_char c1) = no_connection;
 static void (*o_hira_conv)(nkf_char c2,nkf_char c1) = no_connection;
 static void (*o_base64conv)(nkf_char c2,nkf_char c1) = no_connection;
@@ -705,11 +650,10 @@ static int             overwrite_f = FALSE;
 static int             preserve_time_f = FALSE;
 static int             backup_f = FALSE;
 static char            *backup_suffix = "";
-static char *get_backup_filename(const char *suffix, const char *filename);
 #endif
 
-static int nlmode_f = 0;   /* CR, LF, CRLF */
-static int input_newline = 0; /* 0: unestablished, EOF: MIXED */
+static int eolmode_f = 0;   /* CR, LF, CRLF */
+static int input_eol = 0; /* 0: unestablished, EOF: MIXED */
 static nkf_char prev_cr = 0; /* CR or 0 */
 #ifdef EASYWIN /*Easy Win */
 static int             end_check;
@@ -818,284 +762,135 @@ static nkf_encoding* nkf_default_encoding()
 #endif
 }
 
+#ifndef PERL_XS
 #ifdef WIN32DLL
-#include "nkf32dll.c"
-#elif defined(PERL_XS)
-#else /* WIN32DLL */
-int main(int argc, char **argv)
-{
-    FILE  *fin;
-    unsigned char  *cp;
-
-    char *outfname = NULL;
-    char *origfname;
-
-#ifdef EASYWIN /*Easy Win */
-    _BufferSize.y = 400;/*Set Scroll Buffer Size*/
+#define fprintf dllprintf
 #endif
-    setlocale(LC_CTYPE, "");
 
-    for (argc--,argv++; (argc > 0) && **argv == '-'; argc--, argv++) {
-        cp = (unsigned char *)*argv;
-        options(cp);
-#ifdef EXEC_IO
-        if (exec_f){
-            int fds[2], pid;
-            if (pipe(fds) < 0 || (pid = fork()) < 0){
-                abort();
-            }
-            if (pid == 0){
-                if (exec_f > 0){
-                    close(fds[0]);
-                    dup2(fds[1], 1);
-                }else{
-                    close(fds[1]);
-                    dup2(fds[0], 0);
-                }
-                execvp(argv[1], &argv[1]);
-            }
-            if (exec_f > 0){
-                close(fds[1]);
-                dup2(fds[0], 0);
-            }else{
-                close(fds[0]);
-                dup2(fds[1], 1);
-            }
-            argc = 0;
-            break;
-        }
-#endif
-    }
+void version(void)
+{
+    fprintf(HELP_OUTPUT,"Network Kanji Filter Version " NKF_VERSION " (" NKF_RELEASE_DATE ") \n" COPY_RIGHT "\n");
+}
 
-    if (guess_f) {
-#ifdef CHECK_OPTION
-       int debug_f_back = debug_f;
+void usage(void)
+{
+    fprintf(HELP_OUTPUT,
+           "USAGE:  nkf(nkf32,wnkf,nkf2) -[flags] [in file] .. [out file for -O flag]\n"
+           "Flags:\n"
+           "b,u      Output is buffered (DEFAULT),Output is unbuffered\n"
+           "j,s,e,w  Output code is ISO-2022-JP, Shift JIS, EUC-JP, UTF-8N\n"
+#ifdef UTF8_OUTPUT_ENABLE
+           "         After 'w' you can add more options. -w[ 8 [0], 16 [[BL] [0]] ]\n"
 #endif
-#ifdef EXEC_IO
-       int exec_f_back = exec_f;
+           "J,S,E,W  Input assumption is JIS 7 bit , Shift JIS, EUC-JP, UTF-8\n"
+#ifdef UTF8_INPUT_ENABLE
+           "         After 'W' you can add more options. -W[ 8, 16 [BL] ] \n"
 #endif
-#ifdef X0212_ENABLE
-       int x0212_f_back = x0212_f;
+           "t        no conversion\n"
+           "i[@B]    Specify the Esc Seq for JIS X 0208-1978/83 (DEFAULT B)\n"
+           "o[BJH]   Specify the Esc Seq for ASCII/Roman        (DEFAULT B)\n"
+           "r        {de/en}crypt ROT13/47\n"
+           "h        1 katakana->hiragana, 2 hiragana->katakana, 3 both\n"
+           "m[BQSN0] MIME decode [B:base64,Q:quoted,S:strict,N:non-strict,0:no decode]\n"
+           "M[BQ]    MIME encode [B:base64 Q:quoted]\n"
+           "l        ISO8859-1 (Latin-1) support\n"
+           "f/F      Folding: -f60 or -f or -f60-10 (fold margin 10) F preserve nl\n"
+           "Z[0-4]   Default/0: Convert JISX0208 Alphabet to ASCII\n"
+           "         1: Kankaku to one space  2: to two spaces  3: HTML Entity\n"
+           "         4: JISX0208 Katakana to JISX0201 Katakana\n"
+           "X,x      Assume X0201 kana in MS-Kanji, -x preserves X0201\n"
+           "B[0-2]   Broken input  0: missing ESC,1: any X on ESC-[($]-X,2: ASCII on NL\n"
+#ifdef MSDOS
+           "T        Text mode output\n"
 #endif
-       int x0213_f_back = x0213_f;
-       int guess_f_back = guess_f;
-       reinit();
-       guess_f = guess_f_back;
-       mime_f = FALSE;
-#ifdef CHECK_OPTION
-       debug_f = debug_f_back;
+           "O        Output to File (DEFAULT 'nkf.out')\n"
+           "I        Convert non ISO-2022-JP charactor to GETA\n"
+           "d,c      Convert line breaks  -d: LF  -c: CRLF\n"
+           "-L[uwm]  line mode u:LF w:CRLF m:CR (DEFAULT noconversion)\n"
+           "v, V     Show this usage. V: show configuration\n"
+           "\n"
+           "Long name options\n"
+           " --ic=<input codeset>  --oc=<output codeset>\n"
+           "                   Specify the input or output codeset\n"
+           " --fj  --unix --mac  --windows\n"
+           " --jis  --euc  --sjis  --utf8  --utf16  --mime  --base64\n"
+           "                   Convert for the system or code\n"
+           " --hiragana  --katakana  --katakana-hiragana\n"
+           "                   To Hiragana/Katakana Conversion\n"
+           " --prefix=         Insert escape before troublesome characters of Shift_JIS\n"
+#ifdef INPUT_OPTION
+           " --cap-input, --url-input  Convert hex after ':' or '%%'\n"
 #endif
-#ifdef EXEC_IO
-       exec_f = exec_f_back;
+#ifdef NUMCHAR_OPTION
+           " --numchar-input   Convert Unicode Character Reference\n"
 #endif
-#ifdef X0212_ENABLE
-       x0212_f = x0212_f_back;
+#ifdef UTF8_INPUT_ENABLE
+           " --fb-{skip, html, xml, perl, java, subchar}\n"
+           "                   Specify how nkf handles unassigned characters\n"
 #endif
-       x0213_f = x0213_f_back;
-    }
+#ifdef OVERWRITE
+           " --in-place[=SUFFIX]  --overwrite[=SUFFIX]\n"
+           "                   Overwrite original listed files by filtered result\n"
+           "                   --overwrite preserves timestamp of original files\n"
+#endif
+           " -g  --guess       Guess the input code\n"
+           " --help  --version Show this help/the version\n"
+           "                   For more information, see also man nkf\n"
+           "\n");
+    version();
+}
 
-    if (binmode_f == TRUE)
-#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
-    if (freopen("","wb",stdout) == NULL)
-        return (-1);
+void show_configuration(void)
+{
+    fprintf(HELP_OUTPUT,
+           "Summary of my nkf " NKF_VERSION " (" NKF_RELEASE_DATE ") configuration:\n"
+           "  nkf identity:\n"
+           "    " NKF_IDENT "\n"
+           "  Compile-time options:\n"
+           "    Compiled at:                 " __DATE__ " " __TIME__ "\n"
+          );
+    fprintf(HELP_OUTPUT,
+           "    Default output encoding:     "
+#ifdef DEFAULT_ENCIDX
+           "%s\n", nkf_enc_name(nkf_default_encoding())
 #else
-    setbinmode(stdout);
+           "%s (%s)\n", nkf_locale_encoding() ? "LOCALE" : "DEFAULT",
+           nkf_enc_name(nkf_default_encoding())
 #endif
-
-    if (unbuf_f)
-      setbuf(stdout, (char *) NULL);
-    else
-      setvbuffer(stdout, (char *) stdobuf, IOBUF_SIZE);
-
-    if (argc == 0) {
-      if (binmode_f == TRUE)
-#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
-      if (freopen("","rb",stdin) == NULL) return (-1);
+          );
+    fprintf(HELP_OUTPUT,
+           "    Default output end of line:  "
+#if DEFAULT_NEWLINE == CR
+           "CR"
+#elif DEFAULT_NEWLINE == CRLF
+           "CRLF"
 #else
-      setbinmode(stdin);
+           "LF"
 #endif
-      setvbuffer(stdin, (char *) stdibuf, IOBUF_SIZE);
-      if (nop_f)
-          noconvert(stdin);
-      else {
-          kanji_convert(stdin);
-          if (guess_f) print_guessed_code(NULL);
-      }
-    } else {
-      int nfiles = argc;
-       int is_argument_error = FALSE;
-      while (argc--) {
-           input_codename = NULL;
-           input_newline = 0;
-#ifdef CHECK_OPTION
-           iconv_for_check = 0;
+           "\n"
+           "    Decode MIME encoded string:  "
+#if MIME_DECODE_DEFAULT
+           "ON"
+#else
+           "OFF"
 #endif
-          if ((fin = fopen((origfname = *argv++), "r")) == NULL) {
-               perror(*(argv-1));
-               is_argument_error = TRUE;
-               continue;
-          } else {
-#ifdef OVERWRITE
-              int fd = 0;
-              int fd_backup = 0;
+           "\n"
+           "    Convert JIS X 0201 Katakana: "
+#if X0201_DEFAULT
+           "ON"
+#else
+           "OFF"
+#endif
+           "\n"
+           "    --help, --version output:    "
+#if HELP_OUTPUT_HELP_OUTPUT
+           "HELP_OUTPUT"
+#else
+           "STDOUT"
 #endif
-
-/* reopen file for stdout */
-              if (file_out_f == TRUE) {
-#ifdef OVERWRITE
-                  if (overwrite_f){
-                      outfname = malloc(strlen(origfname)
-                                        + strlen(".nkftmpXXXXXX")
-                                        + 1);
-                      if (!outfname){
-                          perror(origfname);
-                          return -1;
-                      }
-                      strcpy(outfname, origfname);
-#ifdef MSDOS
-                      {
-                          int i;
-                          for (i = strlen(outfname); i; --i){
-                              if (outfname[i - 1] == '/'
-                                  || outfname[i - 1] == '\\'){
-                                  break;
-                              }
-                          }
-                          outfname[i] = '\0';
-                      }
-                      strcat(outfname, "ntXXXXXX");
-                      mktemp(outfname);
-                       fd = open(outfname, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
-                                S_IREAD | S_IWRITE);
-#else
-                      strcat(outfname, ".nkftmpXXXXXX");
-                      fd = mkstemp(outfname);
-#endif
-                      if (fd < 0
-                          || (fd_backup = dup(fileno(stdout))) < 0
-                          || dup2(fd, fileno(stdout)) < 0
-                          ){
-                          perror(origfname);
-                          return -1;
-                      }
-                  }else
-#endif
-                 if(argc == 1) {
-                     outfname = *argv++;
-                     argc--;
-                 } else {
-                     outfname = "nkf.out";
-                 }
-
-                 if(freopen(outfname, "w", stdout) == NULL) {
-                     perror (outfname);
-                     return (-1);
-                 }
-                  if (binmode_f == TRUE) {
-#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
-                      if (freopen("","wb",stdout) == NULL)
-                           return (-1);
-#else
-                      setbinmode(stdout);
-#endif
-                  }
-              }
-              if (binmode_f == TRUE)
-#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
-                 if (freopen("","rb",fin) == NULL)
-                    return (-1);
-#else
-                 setbinmode(fin);
-#endif
-              setvbuffer(fin, (char *) stdibuf, IOBUF_SIZE);
-              if (nop_f)
-                  noconvert(fin);
-              else {
-                  char *filename = NULL;
-                  kanji_convert(fin);
-                  if (nfiles > 1) filename = origfname;
-                  if (guess_f) print_guessed_code(filename);
-              }
-              fclose(fin);
-#ifdef OVERWRITE
-              if (overwrite_f) {
-                  struct stat     sb;
-#if defined(MSDOS) && !defined(__MINGW32__) && !defined(__WIN32__) && !defined(__WATCOMC__) && !defined(__EMX__) && !defined(__OS2__) && !defined(__DJGPP__)
-                  time_t tb[2];
-#else
-                  struct utimbuf  tb;
-#endif
-
-                  fflush(stdout);
-                  close(fd);
-                  if (dup2(fd_backup, fileno(stdout)) < 0){
-                      perror("dup2");
-                  }
-                  if (stat(origfname, &sb)) {
-                      fprintf(stderr, "Can't stat %s\n", origfname);
-                  }
-                  /* \e$B%Q!<%_%C%7%g%s$rI|85\e(B */
-                  if (chmod(outfname, sb.st_mode)) {
-                      fprintf(stderr, "Can't set permission %s\n", outfname);
-                  }
-
-                  /* \e$B%?%$%`%9%?%s%W$rI|85\e(B */
-                   if(preserve_time_f){
-#if defined(MSDOS) && !defined(__MINGW32__) && !defined(__WIN32__) && !defined(__WATCOMC__) && !defined(__EMX__) && !defined(__OS2__) && !defined(__DJGPP__)
-                       tb[0] = tb[1] = sb.st_mtime;
-                       if (utime(outfname, tb)) {
-                           fprintf(stderr, "Can't set timestamp %s\n", outfname);
-                       }
-#else
-                       tb.actime  = sb.st_atime;
-                       tb.modtime = sb.st_mtime;
-                       if (utime(outfname, &tb)) {
-                           fprintf(stderr, "Can't set timestamp %s\n", outfname);
-                       }
-#endif
-                   }
-                   if(backup_f){
-                       char *backup_filename = get_backup_filename(backup_suffix, origfname);
-#ifdef MSDOS
-                       unlink(backup_filename);
-#endif
-                       if (rename(origfname, backup_filename)) {
-                           perror(backup_filename);
-                           fprintf(stderr, "Can't rename %s to %s\n",
-                                   origfname, backup_filename);
-                       }
-                   }else{
-#ifdef MSDOS
-                       if (unlink(origfname)){
-                           perror(origfname);
-                       }
-#endif
-                   }
-                  if (rename(outfname, origfname)) {
-                      perror(origfname);
-                      fprintf(stderr, "Can't rename %s to %s\n",
-                              outfname, origfname);
-                  }
-                  free(outfname);
-              }
-#endif
-          }
-      }
-       if (is_argument_error)
-           return(-1);
-    }
-#ifdef EASYWIN /*Easy Win */
-    if (file_out_f == FALSE)
-        scanf("%d",&end_check);
-    else
-        fclose(stdout);
-#else /* for Other OS */
-    if (file_out_f == TRUE)
-        fclose(stdout);
-#endif /*Easy Win */
-    return (0);
-}
-#endif /* WIN32DLL */
+           "\n");
+}
+#endif /*PERL_XS*/
 
 #ifdef OVERWRITE
 char *get_backup_filename(const char *suffix, const char *filename)
@@ -1138,6 +933,95 @@ char *get_backup_filename(const char *suffix, const char *filename)
 }
 #endif
 
+#ifdef UTF8_INPUT_ENABLE
+void nkf_each_char_to_hex(void (*f)(nkf_char c2,nkf_char c1), nkf_char c)
+{
+    int shift = 20;
+    c &= VALUE_MASK;
+    while(shift >= 0){
+       if(c >= 1<<shift){
+           while(shift >= 0){
+               (*f)(0, bin2hex(c>>shift));
+               shift -= 4;
+           }
+       }else{
+           shift -= 4;
+       }
+    }
+    return;
+}
+
+void encode_fallback_html(nkf_char c)
+{
+    (*oconv)(0, '&');
+    (*oconv)(0, '#');
+    c &= VALUE_MASK;
+    if(c >= NKF_INT32_C(1000000))
+       (*oconv)(0, 0x30+(c/NKF_INT32_C(1000000))%10);
+    if(c >= NKF_INT32_C(100000))
+       (*oconv)(0, 0x30+(c/NKF_INT32_C(100000) )%10);
+    if(c >= 10000)
+       (*oconv)(0, 0x30+(c/10000  )%10);
+    if(c >= 1000)
+       (*oconv)(0, 0x30+(c/1000   )%10);
+    if(c >= 100)
+       (*oconv)(0, 0x30+(c/100    )%10);
+    if(c >= 10)
+       (*oconv)(0, 0x30+(c/10     )%10);
+    if(c >= 0)
+       (*oconv)(0, 0x30+ c         %10);
+    (*oconv)(0, ';');
+    return;
+}
+
+void encode_fallback_xml(nkf_char c)
+{
+    (*oconv)(0, '&');
+    (*oconv)(0, '#');
+    (*oconv)(0, 'x');
+    nkf_each_char_to_hex(oconv, c);
+    (*oconv)(0, ';');
+    return;
+}
+
+void encode_fallback_java(nkf_char c)
+{
+    (*oconv)(0, '\\');
+    c &= VALUE_MASK;
+    if(!is_unicode_bmp(c)){
+       (*oconv)(0, 'U');
+       (*oconv)(0, '0');
+       (*oconv)(0, '0');
+       (*oconv)(0, bin2hex(c>>20));
+       (*oconv)(0, bin2hex(c>>16));
+    }else{
+       (*oconv)(0, 'u');
+    }
+    (*oconv)(0, bin2hex(c>>12));
+    (*oconv)(0, bin2hex(c>> 8));
+    (*oconv)(0, bin2hex(c>> 4));
+    (*oconv)(0, bin2hex(c    ));
+    return;
+}
+
+void encode_fallback_perl(nkf_char c)
+{
+    (*oconv)(0, '\\');
+    (*oconv)(0, 'x');
+    (*oconv)(0, '{');
+    nkf_each_char_to_hex(oconv, c);
+    (*oconv)(0, '}');
+    return;
+}
+
+void encode_fallback_subchar(nkf_char c)
+{
+    c = unicode_subchar;
+    (*oconv)((c>>8)&0xFF, c&0xFF);
+    return;
+}
+#endif
+
 static const struct {
     const char *name;
     const char *alias;
@@ -1963,23 +1847,23 @@ void options(unsigned char *cp)
             continue;
 #endif
         case 'c':/* add cr code */
-            nlmode_f = CRLF;
+            eolmode_f = CRLF;
             continue;
         case 'd':/* delete cr code */
-            nlmode_f = LF;
+            eolmode_f = LF;
             continue;
        case 'I':   /* ISO-2022-JP output */
            iso2022jp_f = TRUE;
            continue;
         case 'L':  /* line mode */
             if (*cp=='u') {         /* unix */
-                nlmode_f = LF; cp++;
+                eolmode_f = LF; cp++;
             } else if (*cp=='m') { /* mac */
-                nlmode_f = CR; cp++;
+                eolmode_f = CR; cp++;
             } else if (*cp=='w') { /* windows */
-                nlmode_f = CRLF; cp++;
+                eolmode_f = CRLF; cp++;
             } else if (*cp=='0') { /* no conversion  */
-                nlmode_f = 0; cp++;
+                eolmode_f = 0; cp++;
             }
             continue;
 #ifndef PERL_XS
@@ -2007,113 +1891,432 @@ void options(unsigned char *cp)
     }
 }
 
-struct input_code * find_inputcode_byfunc(nkf_char (*iconv_func)(nkf_char c2,nkf_char c1,nkf_char c0))
+#ifdef UTF8_INPUT_ENABLE
+nkf_char w_iconv_common(nkf_char c1, nkf_char c0, const unsigned short *const *pp, nkf_char psize, nkf_char *p2, nkf_char *p1)
 {
-    if (iconv_func){
-        struct input_code *p = input_code_list;
-        while (p->name){
-            if (iconv_func == p->iconv_func){
-                return p;
-            }
-            p++;
-        }
-    }
-    return 0;
-}
+    nkf_char c2;
+    const unsigned short *p;
+    unsigned short val;
 
-void set_iconv(nkf_char f, nkf_char (*iconv_func)(nkf_char c2,nkf_char c1,nkf_char c0))
-{
-#ifdef INPUT_CODE_FIX
-    if (f || !input_encoding)
-#endif
-        if (estab_f != f){
-            estab_f = f;
-        }
+    if (pp == 0) return 1;
 
-    if (iconv_func
-#ifdef INPUT_CODE_FIX
-        && (f == -TRUE || !input_encoding) /* -TRUE means "FORCE" */
-#endif
-        ){
-        iconv = iconv_func;
-    }
-#ifdef CHECK_OPTION
-    if (estab_f && iconv_for_check != iconv){
-        struct input_code *p = find_inputcode_byfunc(iconv);
-        if (p){
-            set_input_codename(p->name);
-            debug(p->name);
-        }
-        iconv_for_check = iconv;
-    }
-#endif
-}
-
-#define SCORE_L2       (1)                   /* \e$BBh\e(B2\e$B?e=`4A;z\e(B */
-#define SCORE_KANA     (SCORE_L2 << 1)       /* \e$B$$$o$f$kH>3Q%+%J\e(B */
-#define SCORE_DEPEND   (SCORE_KANA << 1)     /* \e$B5!<o0MB8J8;z\e(B */
-#define SCORE_CP932    (SCORE_DEPEND << 1)   /* CP932 \e$B$K$h$kFI$_49$(\e(B (IBM extended characters) */
-#define SCORE_X0212    (SCORE_CP932 << 1)    /* JIS X 0212 */
-#define SCORE_NO_EXIST (SCORE_X0212 << 1)    /* \e$BB8:_$7$J$$J8;z\e(B */
-#define SCORE_iMIME    (SCORE_NO_EXIST << 1) /* MIME \e$B$K$h$k;XDj\e(B */
-#define SCORE_ERROR    (SCORE_iMIME << 1) /* \e$B%(%i!<\e(B */
-
-#define SCORE_INIT (SCORE_iMIME)
-
-static const char score_table_A0[] = {
-    0, 0, 0, 0,
-    0, 0, 0, 0,
-    0, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
-    SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_NO_EXIST,
-};
+    c1 -= 0x80;
+    if (c1 < 0 || psize <= c1) return 1;
+    p = pp[c1];
+    if (p == 0)  return 1;
 
-static const char score_table_F0[] = {
-    SCORE_L2, SCORE_L2, SCORE_L2, SCORE_L2,
-    SCORE_L2, SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST,
-    SCORE_DEPEND, SCORE_DEPEND, SCORE_CP932, SCORE_CP932,
-    SCORE_CP932, SCORE_NO_EXIST, SCORE_NO_EXIST, SCORE_ERROR,
-};
+    c0 -= 0x80;
+    if (c0 < 0 || sizeof_utf8_to_euc_C2 <= c0) return 1;
+    val = p[c0];
+    if (val == 0) return 1;
+    if (no_cp932ext_f && (
+       (val>>8) == 0x2D || /* NEC special characters */
+       val > NKF_INT32_C(0xF300) /* IBM extended characters */
+       )) return 1;
 
-void set_code_score(struct input_code *ptr, nkf_char score)
-{
-    if (ptr){
-        ptr->score |= score;
+    c2 = val >> 8;
+   if (val > 0x7FFF){
+        c2 &= 0x7f;
+        c2 |= PREFIX_EUCG3;
     }
+    if (c2 == SO) c2 = JIS_X_0201;
+    c1 = val & 0x7f;
+    if (p2) *p2 = c2;
+    if (p1) *p1 = c1;
+    return 0;
 }
 
-void clr_code_score(struct input_code *ptr, nkf_char score)
+nkf_char unicode_to_jis_common(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char *p1)
 {
-    if (ptr){
-        ptr->score &= ~score;
+    const unsigned short *const *pp;
+    const unsigned short *const *const *ppp;
+    static const char no_best_fit_chars_table_C2[] =
+    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 2, 1, 1, 2,
+       0, 0, 1, 1, 0, 1, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1};
+    static const char no_best_fit_chars_table_C2_ms[] =
+    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0,
+       0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0};
+    static const char no_best_fit_chars_table_932_C2[] =
+    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1,
+       0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0};
+    static const char no_best_fit_chars_table_932_C3[] =
+    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1};
+    nkf_char ret = 0;
+
+    if(c2 < 0x80){
+       *p2 = 0;
+       *p1 = c2;
+    }else if(c2 < 0xe0){
+       if(no_best_fit_chars_f){
+           if(ms_ucs_map_f == UCS_MAP_CP932){
+               switch(c2){
+               case 0xC2:
+                   if(no_best_fit_chars_table_932_C2[c1&0x3F]) return 1;
+                   break;
+               case 0xC3:
+                   if(no_best_fit_chars_table_932_C3[c1&0x3F]) return 1;
+                   break;
+               }
+           }else if(!cp932inv_f){
+               switch(c2){
+               case 0xC2:
+                   if(no_best_fit_chars_table_C2[c1&0x3F]) return 1;
+                   break;
+               case 0xC3:
+                   if(no_best_fit_chars_table_932_C3[c1&0x3F]) return 1;
+                   break;
+               }
+           }else if(ms_ucs_map_f == UCS_MAP_MS){
+               if(c2 == 0xC2 && no_best_fit_chars_table_C2_ms[c1&0x3F]) return 1;
+           }else if(ms_ucs_map_f == UCS_MAP_CP10001){
+               switch(c2){
+               case 0xC2:
+                   switch(c1){
+                   case 0xA2:
+                   case 0xA3:
+                   case 0xA5:
+                   case 0xA6:
+                   case 0xAC:
+                   case 0xAF:
+                   case 0xB8:
+                       return 1;
+                   }
+                   break;
+               }
+           }
+       }
+       pp =
+           ms_ucs_map_f == UCS_MAP_CP932 ? utf8_to_euc_2bytes_932 :
+           ms_ucs_map_f == UCS_MAP_MS ? utf8_to_euc_2bytes_ms :
+           ms_ucs_map_f == UCS_MAP_CP10001 ? utf8_to_euc_2bytes_mac :
+           utf8_to_euc_2bytes;
+       ret =  w_iconv_common(c2, c1, pp, sizeof_utf8_to_euc_2bytes, p2, p1);
+    }else if(c0 < 0xF0){
+       if(no_best_fit_chars_f){
+           if(ms_ucs_map_f == UCS_MAP_CP932){
+               if(c2 == 0xE3 && c1 == 0x82 && c0 == 0x94) return 1;
+           }else if(ms_ucs_map_f == UCS_MAP_MS){
+               switch(c2){
+               case 0xE2:
+                   switch(c1){
+                   case 0x80:
+                       if(c0 == 0x94 || c0 == 0x96 || c0 == 0xBE) return 1;
+                       break;
+                   case 0x88:
+                       if(c0 == 0x92) return 1;
+                       break;
+                   }
+                   break;
+               case 0xE3:
+                   if(c1 == 0x80 || c0 == 0x9C) return 1;
+                   break;
+               }
+           }else if(ms_ucs_map_f == UCS_MAP_CP10001){
+               switch(c2){
+               case 0xE3:
+                   switch(c1){
+                   case 0x82:
+                           if(c0 == 0x94) return 1;
+                       break;
+                   case 0x83:
+                           if(c0 == 0xBB) return 1;
+                       break;
+                   }
+                   break;
+               }
+           }else{
+               switch(c2){
+               case 0xE2:
+                   switch(c1){
+                   case 0x80:
+                       if(c0 == 0x95) return 1;
+                       break;
+                   case 0x88:
+                       if(c0 == 0xA5) return 1;
+                       break;
+                   }
+                   break;
+               case 0xEF:
+                   switch(c1){
+                   case 0xBC:
+                       if(c0 == 0x8D) return 1;
+                       break;
+                   case 0xBD:
+                       if(c0 == 0x9E && !cp932inv_f) return 1;
+                       break;
+                   case 0xBF:
+                       if(0xA0 <= c0 && c0 <= 0xA5) return 1;
+                       break;
+                   }
+                   break;
+               }
+           }
+       }
+       ppp =
+           ms_ucs_map_f == UCS_MAP_CP932 ? utf8_to_euc_3bytes_932 :
+           ms_ucs_map_f == UCS_MAP_MS ? utf8_to_euc_3bytes_ms :
+           ms_ucs_map_f == UCS_MAP_CP10001 ? utf8_to_euc_3bytes_mac :
+           utf8_to_euc_3bytes;
+       ret = w_iconv_common(c1, c0, ppp[c2 - 0xE0], sizeof_utf8_to_euc_C2, p2, p1);
+    }else return -1;
+#ifdef SHIFTJIS_CP932
+    if (!ret && !cp932inv_f && is_eucg3(*p2)) {
+       nkf_char s2, s1;
+       if (e2s_conv(*p2, *p1, &s2, &s1) == 0) {
+           s2e_conv(s2, s1, p2, p1);
+       }else{
+           ret = 1;
+       }
     }
+#endif
+    return ret;
 }
 
-void code_score(struct input_code *ptr)
+nkf_char w2e_conv(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char *p1)
 {
-    nkf_char c2 = ptr->buf[0];
-#ifdef UTF8_OUTPUT_ENABLE
-    nkf_char c1 = ptr->buf[1];
-#endif
-    if (c2 < 0){
-        set_code_score(ptr, SCORE_ERROR);
-    }else if (c2 == SSO){
-        set_code_score(ptr, SCORE_KANA);
-    }else if (c2 == 0x8f){
-        set_code_score(ptr, SCORE_X0212);
-#ifdef UTF8_OUTPUT_ENABLE
-    }else if (!e2w_conv(c2, c1)){
-        set_code_score(ptr, SCORE_NO_EXIST);
+    nkf_char ret = 0;
+
+    if (!c1){
+        *p2 = 0;
+        *p1 = c2;
+    }else if (0xc0 <= c2 && c2 <= 0xef) {
+       ret =  unicode_to_jis_common(c2, c1, c0, p2, p1);
+#ifdef NUMCHAR_OPTION
+        if (ret > 0){
+            if (p2) *p2 = 0;
+            if (p1) *p1 = CLASS_UNICODE | ww16_conv(c2, c1, c0);
+            ret = 0;
+        }
 #endif
-    }else if ((c2 & 0x70) == 0x20){
-        set_code_score(ptr, score_table_A0[c2 & 0x0f]);
-    }else if ((c2 & 0x70) == 0x70){
-        set_code_score(ptr, score_table_F0[c2 & 0x0f]);
-    }else if ((c2 & 0x70) >= 0x50){
-        set_code_score(ptr, SCORE_L2);
     }
+    return ret;
 }
 
-void status_disable(struct input_code *ptr)
+nkf_char w_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
+{
+    nkf_char ret = 0;
+    static const char w_iconv_utf8_1st_byte[] =
+    { /* 0xC0 - 0xFF */
+       20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+       21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+       30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 33,
+       40, 41, 41, 41, 42, 43, 43, 43, 50, 50, 50, 50, 60, 60, 70, 70};
+
+    if (c2 < 0 || 0xff < c2) {
+    }else if (c2 == 0) { /* 0 : 1 byte*/
+       c0 = 0;
+    } else if ((c2 & 0xc0) == 0x80) { /* 0x80-0xbf : trail byte */
+       return 0;
+    } else{
+       switch (w_iconv_utf8_1st_byte[c2 - 0xC0]) {
+       case 21:
+           if (c1 < 0x80 || 0xBF < c1) return 0;
+           break;
+       case 30:
+           if (c0 == 0) return -1;
+           if (c1 < 0xA0 || 0xBF < c1 || (c0 & 0xc0) != 0x80)
+               return 0;
+           break;
+       case 31:
+       case 33:
+           if (c0 == 0) return -1;
+           if ((c1 & 0xc0) != 0x80 || (c0 & 0xc0) != 0x80)
+               return 0;
+           break;
+       case 32:
+           if (c0 == 0) return -1;
+           if (c1 < 0x80 || 0x9F < c1 || (c0 & 0xc0) != 0x80)
+               return 0;
+           break;
+       case 40:
+           if (c0 == 0) return -2;
+           if (c1 < 0x90 || 0xBF < c1 || (c0 & 0xc0c0) != 0x8080)
+               return 0;
+           break;
+       case 41:
+           if (c0 == 0) return -2;
+           if (c1 < 0x80 || 0xBF < c1 || (c0 & 0xc0c0) != 0x8080)
+               return 0;
+           break;
+       case 42:
+           if (c0 == 0) return -2;
+           if (c1 < 0x80 || 0x8F < c1 || (c0 & 0xc0c0) != 0x8080)
+               return 0;
+           break;
+       default:
+           return 0;
+           break;
+       }
+    }
+    if (c2 == 0 || c2 == EOF){
+    } else if ((c2 & 0xf8) == 0xf0) { /* 4 bytes */
+       c1 = CLASS_UNICODE | ww16_conv(c2, c1, c0);
+       c2 = 0;
+    } else {
+       ret = w2e_conv(c2, c1, c0, &c2, &c1);
+    }
+    if (ret == 0){
+        (*oconv)(c2, c1);
+    }
+    return ret;
+}
+
+nkf_char w_iconv16(nkf_char c2, nkf_char c1, nkf_char c0)
+{
+    nkf_char ret = 0;
+    if ((c2==0 && c1 < 0x80) || c2==EOF) {
+       (*oconv)(c2, c1);
+       return 0;
+    }else if (0xD8 <= c2 && c2 <= 0xDB) {
+       if (c0 < NKF_INT32_C(0xDC00) || NKF_INT32_C(0xDFFF) < c0)
+           return -2;
+       c1 =  CLASS_UNICODE | ((c2 << 18) + (c1 << 10) + c0 - NKF_INT32_C(0x35FDC00));
+       c2 = 0;
+    }else if ((c2>>3) == 27) { /* unpaired surrogate */
+       /*
+          return 2;
+       */
+       return 1;
+    }else ret = w16e_conv(((c2 & 0xff)<<8) + c1, &c2, &c1);
+    if (ret) return ret;
+    (*oconv)(c2, c1);
+    return 0;
+}
+
+nkf_char w_iconv32(nkf_char c2, nkf_char c1, nkf_char c0)
+{
+    int ret = 0;
+
+    if ((c2 == 0 && c1 < 0x80) || c2==EOF) {
+    } else if (is_unicode_bmp(c1)) {
+       ret = w16e_conv(c1, &c2, &c1);
+    } else {
+       c2 = 0;
+       c1 =  CLASS_UNICODE | c1;
+    }
+    if (ret) return ret;
+    (*oconv)(c2, c1);
+    return 0;
+}
+
+#endif
+
+struct input_code * find_inputcode_byfunc(nkf_char (*iconv_func)(nkf_char c2,nkf_char c1,nkf_char c0))
+{
+    if (iconv_func){
+        struct input_code *p = input_code_list;
+        while (p->name){
+            if (iconv_func == p->iconv_func){
+                return p;
+            }
+            p++;
+        }
+    }
+    return 0;
+}
+
+void set_iconv(nkf_char f, nkf_char (*iconv_func)(nkf_char c2,nkf_char c1,nkf_char c0))
+{
+#ifdef INPUT_CODE_FIX
+    if (f || !input_encoding)
+#endif
+        if (estab_f != f){
+            estab_f = f;
+        }
+
+    if (iconv_func
+#ifdef INPUT_CODE_FIX
+        && (f == -TRUE || !input_encoding) /* -TRUE means "FORCE" */
+#endif
+        ){
+        iconv = iconv_func;
+    }
+#ifdef CHECK_OPTION
+    if (estab_f && iconv_for_check != iconv){
+        struct input_code *p = find_inputcode_byfunc(iconv);
+        if (p){
+            set_input_codename(p->name);
+            debug(p->name);
+        }
+        iconv_for_check = iconv;
+    }
+#endif
+}
+
+#define SCORE_L2       (1)                   /* \e$BBh\e(B2\e$B?e=`4A;z\e(B */
+#define SCORE_KANA     (SCORE_L2 << 1)       /* \e$B$$$o$f$kH>3Q%+%J\e(B */
+#define SCORE_DEPEND   (SCORE_KANA << 1)     /* \e$B5!<o0MB8J8;z\e(B */
+#define SCORE_CP932    (SCORE_DEPEND << 1)   /* CP932 \e$B$K$h$kFI$_49$(\e(B (IBM extended characters) */
+#define SCORE_X0212    (SCORE_CP932 << 1)    /* JIS X 0212 */
+#define SCORE_NO_EXIST (SCORE_X0212 << 1)    /* \e$BB8:_$7$J$$J8;z\e(B */
+#define SCORE_iMIME    (SCORE_NO_EXIST << 1) /* MIME \e$B$K$h$k;XDj\e(B */
+#define SCORE_ERROR    (SCORE_iMIME << 1) /* \e$B%(%i!<\e(B */
+
+#define SCORE_INIT (SCORE_iMIME)
+
+static const char score_table_A0[] = {
+    0, 0, 0, 0,
+    0, 0, 0, 0,
+    0, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
+    SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_NO_EXIST,
+};
+
+static const char score_table_F0[] = {
+    SCORE_L2, SCORE_L2, SCORE_L2, SCORE_L2,
+    SCORE_L2, SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST,
+    SCORE_DEPEND, SCORE_DEPEND, SCORE_CP932, SCORE_CP932,
+    SCORE_CP932, SCORE_NO_EXIST, SCORE_NO_EXIST, SCORE_ERROR,
+};
+
+void set_code_score(struct input_code *ptr, nkf_char score)
+{
+    if (ptr){
+        ptr->score |= score;
+    }
+}
+
+void clr_code_score(struct input_code *ptr, nkf_char score)
+{
+    if (ptr){
+        ptr->score &= ~score;
+    }
+}
+
+void code_score(struct input_code *ptr)
+{
+    nkf_char c2 = ptr->buf[0];
+#ifdef UTF8_OUTPUT_ENABLE
+    nkf_char c1 = ptr->buf[1];
+#endif
+    if (c2 < 0){
+        set_code_score(ptr, SCORE_ERROR);
+    }else if (c2 == SSO){
+        set_code_score(ptr, SCORE_KANA);
+    }else if (c2 == 0x8f){
+        set_code_score(ptr, SCORE_X0212);
+#ifdef UTF8_OUTPUT_ENABLE
+    }else if (!e2w_conv(c2, c1)){
+        set_code_score(ptr, SCORE_NO_EXIST);
+#endif
+    }else if ((c2 & 0x70) == 0x20){
+        set_code_score(ptr, score_table_A0[c2 & 0x0f]);
+    }else if ((c2 & 0x70) == 0x70){
+        set_code_score(ptr, score_table_F0[c2 & 0x0f]);
+    }else if ((c2 & 0x70) >= 0x50){
+        set_code_score(ptr, SCORE_L2);
+    }
+}
+
+void status_disable(struct input_code *ptr)
 {
     ptr->stat = -1;
     ptr->buf[0] = -1;
@@ -2396,112 +2599,121 @@ void std_putc(nkf_char c)
 }
 #endif /*WIN32DLL*/
 
-#if !defined(PERL_XS) && !defined(WIN32DLL)
-nkf_char noconvert(FILE *f)
+nkf_char
+h_conv(FILE *f, nkf_char c2, nkf_char c1)
 {
-    nkf_char    c;
+    nkf_char ret, c3, c0;
+    int hold_index;
 
-    if (nop_f == 2)
-       module_connection();
-    while ((c = (*i_getc)(f)) != EOF)
-      (*o_putc)(c);
-    (*o_putc)(EOF);
-    return 1;
-}
-#endif
 
-void module_connection(void)
-{
-    if (input_encoding) set_input_encoding(input_encoding);
-    if (!output_encoding) {
-       output_encoding = nkf_default_encoding();
-    }
-    set_output_encoding(output_encoding);
-    oconv = nkf_enc_to_oconv(output_encoding);
-    o_putc = std_putc;
+    /** it must NOT be in the kanji shifte sequence      */
+    /** it must NOT be written in JIS7                   */
+    /** and it must be after 2 byte 8bit code            */
 
-    /* replace continucation module, from output side */
+    hold_count = 0;
+    push_hold_buf(c2);
+    push_hold_buf(c1);
 
-    /* output redicrection */
-#ifdef CHECK_OPTION
-    if (noout_f || guess_f){
-        o_putc = no_putc;
-    }
-#endif
-    if (mimeout_f) {
-       o_mputc = o_putc;
-       o_putc = mime_putc;
-       if (mimeout_f == TRUE) {
-           o_base64conv = oconv; oconv = base64_conv;
-       }
-       /* base64_count = 0; */
+    while ((c1 = (*i_getc)(f)) != EOF) {
+        if (c1 == ESC){
+           (*i_ungetc)(c1,f);
+            break;
+        }
+        code_status(c1);
+        if (push_hold_buf(c1) == EOF || estab_f){
+            break;
+        }
     }
 
-    if (nlmode_f || guess_f) {
-       o_nlconv = oconv; oconv = nl_conv;
-    }
-    if (rot_f) {
-       o_rot_conv = oconv; oconv = rot_conv;
-    }
-    if (iso2022jp_f) {
-       o_iso2022jp_check_conv = oconv; oconv = iso2022jp_check_conv;
-    }
-    if (hira_f) {
-       o_hira_conv = oconv; oconv = hira_conv;
-    }
-    if (fold_f) {
-       o_fconv = oconv; oconv = fold_conv;
-       f_line = 0;
-    }
-    if (alpha_f || x0201_f) {
-       o_zconv = oconv; oconv = z_conv;
+    if (!estab_f){
+        struct input_code *p = input_code_list;
+        struct input_code *result = p;
+        if (c1 == EOF){
+            code_status(c1);
+        }
+        while (p->name){
+            if (p->status_func && p->score < result->score){
+                result = p;
+            }
+            ++p;
+        }
+        set_iconv(TRUE, result->iconv_func);
     }
 
-    i_getc = std_getc;
-    i_ungetc = std_ungetc;
-    /* input redicrection */
-#ifdef INPUT_OPTION
-    if (cap_f){
-        i_cgetc = i_getc; i_getc = cap_getc;
-        i_cungetc = i_ungetc; i_ungetc= cap_ungetc;
-    }
-    if (url_f){
-        i_ugetc = i_getc; i_getc = url_getc;
-        i_uungetc = i_ungetc; i_ungetc= url_ungetc;
-    }
-#endif
+
+    /** now,
+     ** 1) EOF is detected, or
+     ** 2) Code is established, or
+     ** 3) Buffer is FULL (but last word is pushed)
+     **
+     ** in 1) and 3) cases, we continue to use
+     ** Kanji codes by oconv and leave estab_f unchanged.
+     **/
+
+    ret = c1;
+    hold_index = 0;
+    while (hold_index < hold_count){
+        c2 = hold_buf[hold_index++];
+        if (c2 <= DEL
 #ifdef NUMCHAR_OPTION
-    if (numchar_f){
-        i_ngetc = i_getc; i_getc = numchar_getc;
-        i_nungetc = i_ungetc; i_ungetc= numchar_ungetc;
-    }
-#endif
-#ifdef UNICODE_NORMALIZATION
-    if (nfc_f){
-        i_nfc_getc = i_getc; i_getc = nfc_getc;
-        i_nfc_ungetc = i_ungetc; i_ungetc= nfc_ungetc;
-    }
+            || is_unicode_capsule(c2)
 #endif
-    if (mime_f && mimebuf_f==FIXED_MIME) {
-       i_mgetc = i_getc; i_getc = mime_getc;
-       i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
-    }
-    if (broken_f & 1) {
-       i_bgetc = i_getc; i_getc = broken_getc;
-       i_bungetc = i_ungetc; i_ungetc = broken_ungetc;
-    }
-    if (input_encoding) {
-        set_iconv(-TRUE, nkf_enc_to_iconv(input_encoding));
-    } else {
-        set_iconv(FALSE, e_iconv);
-    }
-
-    {
-        struct input_code *p = input_code_list;
-        while (p->name){
-            status_reinit(p++);
+            ){
+            (*iconv)(0, c2, 0);
+            continue;
+        }else if (iconv == s_iconv && 0xa1 <= c2 && c2 <= 0xdf){
+            (*iconv)(JIS_X_0201, c2, 0);
+            continue;
+        }
+        if (hold_index < hold_count){
+            c1 = hold_buf[hold_index++];
+        }else{
+            c1 = (*i_getc)(f);
+            if (c1 == EOF){
+                c3 = EOF;
+                break;
+            }
+            code_status(c1);
         }
+        c0 = 0;
+        switch ((*iconv)(c2, c1, 0)) {  /* can be EUC/SJIS/UTF-8 */
+       case -2:
+           /* 4 bytes UTF-8 */
+            if (hold_index < hold_count){
+                c0 = hold_buf[hold_index++];
+            } else if ((c0 = (*i_getc)(f)) == EOF) {
+               ret = EOF;
+               break;
+           } else {
+                code_status(c0);
+               c0 <<= 8;
+               if (hold_index < hold_count){
+                   c3 = hold_buf[hold_index++];
+               } else if ((c3 = (*i_getc)(f)) == EOF) {
+                   c0 = ret = EOF;
+                   break;
+               } else {
+                   code_status(c3);
+                   (*iconv)(c2, c1, c0|c3);
+               }
+            }
+           break;
+       case -1:
+           /* 3 bytes EUC or UTF-8 */
+            if (hold_index < hold_count){
+                c0 = hold_buf[hold_index++];
+            } else if ((c0 = (*i_getc)(f)) == EOF) {
+               ret = EOF;
+               break;
+           } else {
+                code_status(c0);
+            }
+            (*iconv)(c2, c1, c0);
+            break;
+       }
+       if (c0 == EOF) break;
     }
+    return ret;
 }
 
 /*
@@ -2615,621 +2827,48 @@ void check_bom(FILE *f)
     }
 }
 
-/*
-   Conversion main loop. Code detection only.
- */
-
-nkf_char kanji_convert(FILE *f)
+nkf_char push_hold_buf(nkf_char c2)
 {
-    nkf_char    c3, c2=0, c1, c0=0;
-    int is_8bit = FALSE;
+    if (hold_count >= HOLD_SIZE*2)
+        return (EOF);
+    hold_buf[hold_count++] = (unsigned char)c2;
+    return ((hold_count >= HOLD_SIZE*2) ? EOF : hold_count);
+}
 
-    if (input_encoding && !nkf_enc_asciicompat(input_encoding)) {
-       is_8bit = TRUE;
+#ifdef X0212_ENABLE
+nkf_char x0212_shift(nkf_char c)
+{
+    nkf_char ret = c;
+    c &= 0x7f;
+    if (is_eucg3(ret)){
+        if (0x75 <= c && c <= 0x7f){
+            ret = c + (0x109 - 0x75);
+        }
+    }else{
+        if (0x75 <= c && c <= 0x7f){
+            ret = c + (0x113 - 0x75);
+        }
     }
+    return ret;
+}
 
-    input_mode = ASCII;
-    output_mode = ASCII;
-    shift_mode = FALSE;
-
-#define NEXT continue      /* no output, get next */
-#define SEND ;             /* output c1 and c2, get next */
-#define LAST break         /* end of loop, go closing  */
 
-    module_connection();
-    check_bom(f);
+nkf_char x0212_unshift(nkf_char c)
+{
+    nkf_char ret = c;
+    if (0x7f <= c && c <= 0x88){
+        ret = c + (0x75 - 0x7f);
+    }else if (0x89 <= c && c <= 0x92){
+        ret = PREFIX_EUCG3 | 0x80 | (c + (0x75 - 0x89));
+    }
+    return ret;
+}
+#endif /* X0212_ENABLE */
 
-    while ((c1 = (*i_getc)(f)) != EOF) {
-#ifdef INPUT_CODE_FIX
-       if (!input_encoding)
-#endif
-           code_status(c1);
-        if (c2) {
-            /* second byte */
-            if (c2 > ((input_encoding && nkf_enc_cp5022x_p(input_encoding)) ? 0x92 : DEL)) {
-                /* in case of 8th bit is on */
-                if (!estab_f&&!mime_decode_mode) {
-                    /* in case of not established yet */
-                    /* It is still ambiguious */
-                    if (h_conv(f, c2, c1)==EOF)
-                        LAST;
-                    else
-                        c2 = 0;
-                    NEXT;
-                } else {
-                   /* in case of already established */
-                   if (c1 < AT) {
-                       /* ignore bogus code and not CP5022x UCD */
-                       c2 = 0;
-                       NEXT;
-                   } else {
-                       SEND;
-                   }
-               }
-            } else
-                /* second byte, 7 bit code */
-                /* it might be kanji shitfted */
-                if ((c1 == DEL) || (c1 <= SP)) {
-                    /* ignore bogus first code */
-                    c2 = 0;
-                    NEXT;
-                } else
-                    SEND;
-        } else {
-            /* first byte */
-#ifdef UTF8_INPUT_ENABLE
-           if (iconv == w_iconv16) {
-               if (input_endian == ENDIAN_BIG) {
-                   c2 = c1;
-                   if ((c1 = (*i_getc)(f)) != EOF) {
-                       if (0xD8 <= c2 && c2 <= 0xDB) {
-                           if ((c0 = (*i_getc)(f)) != EOF) {
-                               c0 <<= 8;
-                               if ((c3 = (*i_getc)(f)) != EOF) {
-                                   c0 |= c3;
-                               } else c2 = EOF;
-                           } else c2 = EOF;
-                       }
-                   } else c2 = EOF;
-               } else {
-                   if ((c2 = (*i_getc)(f)) != EOF) {
-                       if (0xD8 <= c2 && c2 <= 0xDB) {
-                           if ((c3 = (*i_getc)(f)) != EOF) {
-                               if ((c0 = (*i_getc)(f)) != EOF) {
-                                   c0 <<= 8;
-                                   c0 |= c3;
-                               } else c2 = EOF;
-                           } else c2 = EOF;
-                       }
-                   } else c2 = EOF;
-               }
-               SEND;
-            } else if(iconv == w_iconv32){
-               int c3 = c1;
-               if((c2 = (*i_getc)(f)) != EOF &&
-                  (c1 = (*i_getc)(f)) != EOF &&
-                  (c0 = (*i_getc)(f)) != EOF){
-                   switch(input_endian){
-                   case ENDIAN_BIG:
-                       c1 = (c2&0xFF)<<16 | (c1&0xFF)<<8 | (c0&0xFF);
-                       break;
-                   case ENDIAN_LITTLE:
-                       c1 = (c3&0xFF) | (c2&0xFF)<<8 | (c1&0xFF)<<16;
-                       break;
-                   case ENDIAN_2143:
-                       c1 = (c3&0xFF)<<16 | (c1&0xFF) | (c0&0xFF)<<8;
-                       break;
-                   case ENDIAN_3412:
-                       c1 = (c3&0xFF)<<8 | (c2&0xFF) | (c0&0xFF)<<16;
-                       break;
-                   }
-                   c2 = 0;
-               }else{
-                   c2 = EOF;
-               }
-               SEND;
-            } else
-#endif
-#ifdef NUMCHAR_OPTION
-            if (is_unicode_capsule(c1)){
-                SEND;
-           } else
-#endif
-           if (c1 > ((input_encoding && nkf_enc_cp5022x_p(input_encoding)) ? 0x92 : DEL)) {
-                /* 8 bit code */
-                if (!estab_f && !iso8859_f) {
-                    /* not established yet */
-                    c2 = c1;
-                    NEXT;
-                } else { /* estab_f==TRUE */
-                    if (iso8859_f) {
-                        c2 = ISO_8859_1;
-                        c1 &= 0x7f;
-                        SEND;
-                    } else if (SSP<=c1 && c1<0xe0 && iconv == s_iconv) {
-                        /* SJIS X0201 Case... */
-                        if (iso2022jp_f && !x0201_f) {
-                            (*oconv)(GETA1, GETA2);
-                            NEXT;
-                        } else {
-                           c2 = JIS_X_0201;
-                           c1 &= 0x7f;
-                           SEND;
-                       }
-                    } else if (c1==SSO && iconv != s_iconv) {
-                        /* EUC X0201 Case */
-                        c1 = (*i_getc)(f);  /* skip SSO */
-                        code_status(c1);
-                        if (SSP<=c1 && c1<0xe0) {
-                           if (iso2022jp_f && !x0201_f) {
-                               (*oconv)(GETA1, GETA2);
-                               NEXT;
-                           } else {
-                               c2 = JIS_X_0201;
-                               c1 &= 0x7f;
-                               SEND;
-                           }
-                        } else  { /* bogus code, skip SSO and one byte */
-                            NEXT;
-                        }
-                   } else if (ms_ucs_map_f == UCS_MAP_CP10001 &&
-                              (c1 == 0xFD || c1 == 0xFE)) {
-                       /* CP10001 */
-                       c2 = JIS_X_0201;
-                       c1 &= 0x7f;
-                       SEND;
-                    } else {
-                       /* already established */
-                       c2 = c1;
-                       NEXT;
-                    }
-                }
-            } else if ((c1 > SP) && (c1 != DEL)) {
-                /* in case of Roman characters */
-                if (shift_mode) {
-                    /* output 1 shifted byte */
-                    if (iso8859_f) {
-                        c2 = ISO_8859_1;
-                        SEND;
-                    } else if (SP <= c1 && c1 < (0xe0&0x7f)){
-                      /* output 1 shifted byte */
-                       if (iso2022jp_f && !x0201_f) {
-                           (*oconv)(GETA1, GETA2);
-                           NEXT;
-                       } else {
-                           c2 = JIS_X_0201;
-                           SEND;
-                       }
-                    } else {
-                        /* look like bogus code */
-                        NEXT;
-                    }
-                } else if (input_mode == JIS_X_0208 || input_mode == JIS_X_0212 ||
-                          input_mode == JIS_X_0213_1 || input_mode == JIS_X_0213_2) {
-                    /* in case of Kanji shifted */
-                    c2 = c1;
-                    NEXT;
-                } else if (c1 == '=' && mime_f && !mime_decode_mode) {
-                    /* Check MIME code */
-                    if ((c1 = (*i_getc)(f)) == EOF) {
-                        (*oconv)(0, '=');
-                        LAST;
-                    } else if (c1 == '?') {
-                        /* =? is mime conversion start sequence */
-                       if(mime_f == STRICT_MIME) {
-                           /* check in real detail */
-                           if (mime_begin_strict(f) == EOF)
-                               LAST;
-                           else
-                               NEXT;
-                       } else if (mime_begin(f) == EOF)
-                            LAST;
-                        else
-                            NEXT;
-                    } else {
-                        (*oconv)(0, '=');
-                        (*i_ungetc)(c1,f);
-                        NEXT;
-                    }
-                } else {
-                    /* normal ASCII code */
-                    SEND;
-                }
-            } else if (c1 == SI && (!is_8bit || mime_decode_mode)) {
-                shift_mode = FALSE;
-                NEXT;
-            } else if (c1 == SO && (!is_8bit || mime_decode_mode)) {
-                shift_mode = TRUE;
-                NEXT;
-            } else if (c1 == ESC && (!is_8bit || mime_decode_mode)) {
-                if ((c1 = (*i_getc)(f)) == EOF) {
-                    /*  (*oconv)(0, ESC); don't send bogus code */
-                    LAST;
-                } else if (c1 == '$') {
-                    if ((c1 = (*i_getc)(f)) == EOF) {
-                        /*
-                        (*oconv)(0, ESC); don't send bogus code
-                        (*oconv)(0, '$'); */
-                        LAST;
-                    } else if (c1 == '@'|| c1 == 'B') {
-                        /* This is kanji introduction */
-                        input_mode = JIS_X_0208;
-                        shift_mode = FALSE;
-                        set_input_codename("ISO-2022-JP");
-#ifdef CHECK_OPTION
-                        debug("ISO-2022-JP");
-#endif
-                        NEXT;
-                    } else if (c1 == '(') {
-                        if ((c1 = (*i_getc)(f)) == EOF) {
-                            /* don't send bogus code
-                            (*oconv)(0, ESC);
-                            (*oconv)(0, '$');
-                            (*oconv)(0, '(');
-                                */
-                            LAST;
-                        } else if (c1 == '@'|| c1 == 'B') {
-                            /* This is kanji introduction */
-                            input_mode = JIS_X_0208;
-                            shift_mode = FALSE;
-                            NEXT;
-#ifdef X0212_ENABLE
-                        } else if (c1 == 'D'){
-                            input_mode = JIS_X_0212;
-                            shift_mode = FALSE;
-                            NEXT;
-#endif /* X0212_ENABLE */
-                        } else if (c1 == 0x4F){
-                            input_mode = JIS_X_0213_1;
-                            shift_mode = FALSE;
-                            NEXT;
-                        } else if (c1 == 0x50){
-                            input_mode = JIS_X_0213_2;
-                            shift_mode = FALSE;
-                            NEXT;
-                        } else {
-                            /* could be some special code */
-                            (*oconv)(0, ESC);
-                            (*oconv)(0, '$');
-                            (*oconv)(0, '(');
-                            (*oconv)(0, c1);
-                            NEXT;
-                        }
-                    } else if (broken_f&0x2) {
-                        /* accept any ESC-(-x as broken code ... */
-                        input_mode = JIS_X_0208;
-                        shift_mode = FALSE;
-                        NEXT;
-                    } else {
-                        (*oconv)(0, ESC);
-                        (*oconv)(0, '$');
-                        (*oconv)(0, c1);
-                        NEXT;
-                    }
-                } else if (c1 == '(') {
-                    if ((c1 = (*i_getc)(f)) == EOF) {
-                        /* don't send bogus code
-                        (*oconv)(0, ESC);
-                        (*oconv)(0, '('); */
-                        LAST;
-                    } else {
-                        if (c1 == 'I') {
-                            /* This is X0201 kana introduction */
-                            input_mode = JIS_X_0201; shift_mode = JIS_X_0201;
-                            NEXT;
-                        } else if (c1 == 'B' || c1 == 'J' || c1 == 'H') {
-                            /* This is X0208 kanji introduction */
-                            input_mode = ASCII; shift_mode = FALSE;
-                            NEXT;
-                        } else if (broken_f&0x2) {
-                            input_mode = ASCII; shift_mode = FALSE;
-                            NEXT;
-                        } else {
-                            (*oconv)(0, ESC);
-                            (*oconv)(0, '(');
-                            /* maintain various input_mode here */
-                            SEND;
-                        }
-                    }
-               } else if ( c1 == 'N' || c1 == 'n'){
-                   /* SS2 */
-                   c3 = (*i_getc)(f);  /* skip SS2 */
-                   if ( (SP<=c3 && c3 < 0x60) || (0xa0<=c3 && c3 < 0xe0)){
-                       c1 = c3;
-                       c2 = JIS_X_0201;
-                       SEND;
-                   }else{
-                       (*i_ungetc)(c3, f);
-                       /* lonely ESC  */
-                       (*oconv)(0, ESC);
-                       SEND;
-                   }
-                } else {
-                    /* lonely ESC  */
-                    (*oconv)(0, ESC);
-                    SEND;
-                }
-           } else if (c1 == ESC && iconv == s_iconv) {
-               /* ESC in Shift_JIS */
-               if ((c1 = (*i_getc)(f)) == EOF) {
-                   /*  (*oconv)(0, ESC); don't send bogus code */
-                   LAST;
-               } else if (c1 == '$') {
-                   /* J-PHONE emoji */
-                   if ((c1 = (*i_getc)(f)) == EOF) {
-                       /*
-                          (*oconv)(0, ESC); don't send bogus code
-                          (*oconv)(0, '$'); */
-                       LAST;
-                   } else {
-                       if (('E' <= c1 && c1 <= 'G') ||
-                           ('O' <= c1 && c1 <= 'Q')) {
-                           /*
-                              NUM : 0 1 2 3 4 5
-                              BYTE: G E F O P Q
-                              C%7 : 1 6 0 2 3 4
-                              C%7 : 0 1 2 3 4 5 6
-                              NUM : 2 0 3 4 5 X 1
-                            */
-                           static const char jphone_emoji_first_table[7] = {2, 0, 3, 4, 5, 0, 1};
-                           c0 = (jphone_emoji_first_table[c1 % 7] << 8) - SP + 0xE000 + CLASS_UNICODE;
-                           while ((c1 = (*i_getc)(f)) != EOF) {
-                               if (SP <= c1 && c1 <= 'z') {
-                                   (*oconv)(0, c1 + c0);
-                               } else break; /* c1 == SO */
-                           }
-                       }
-                   }
-                   if (c1 == EOF) LAST;
-                   NEXT;
-               } else {
-                   /* lonely ESC  */
-                   (*oconv)(0, ESC);
-                   SEND;
-               }
-           } else if (c1 == LF || c1 == CR) {
-               if (broken_f&4) {
-                   input_mode = ASCII; set_iconv(FALSE, 0);
-                   SEND;
-               } else if (mime_decode_f && !mime_decode_mode){
-                   if (c1 == LF) {
-                       if ((c1=(*i_getc)(f))!=EOF && c1 == SP) {
-                           i_ungetc(SP,f);
-                           continue;
-                       } else {
-                           i_ungetc(c1,f);
-                       }
-                       c1 = LF;
-                       SEND;
-                   } else  { /* if (c1 == CR)*/
-                       if ((c1=(*i_getc)(f))!=EOF) {
-                           if (c1==SP) {
-                               i_ungetc(SP,f);
-                               continue;
-                           } else if (c1 == LF && (c1=(*i_getc)(f))!=EOF && c1 == SP) {
-                               i_ungetc(SP,f);
-                               continue;
-                           } else {
-                               i_ungetc(c1,f);
-                           }
-                           i_ungetc(LF,f);
-                       } else {
-                           i_ungetc(c1,f);
-                       }
-                       c1 = CR;
-                       SEND;
-                   }
-               }
-           } else if (c1 == DEL && input_mode == JIS_X_0208) {
-               /* CP5022x */
-               c2 = c1;
-               NEXT;
-           } else
-                SEND;
-        }
-        /* send: */
-       switch(input_mode){
-       case ASCII:
-           switch ((*iconv)(c2, c1, c0)) {  /* can be EUC / SJIS / UTF-8 / UTF-16 */
-           case -2:
-               /* 4 bytes UTF-8 */
-               if ((c0 = (*i_getc)(f)) != EOF) {
-                   code_status(c0);
-                   c0 <<= 8;
-                   if ((c3 = (*i_getc)(f)) != EOF) {
-                       code_status(c3);
-                       (*iconv)(c2, c1, c0|c3);
-                   }
-               }
-               break;
-           case -1:
-               /* 3 bytes EUC or UTF-8 */
-               if ((c0 = (*i_getc)(f)) != EOF) {
-                   code_status(c0);
-                   (*iconv)(c2, c1, c0);
-               }
-               break;
-           }
-           break;
-       case JIS_X_0208:
-       case JIS_X_0213_1:
-           if (ms_ucs_map_f &&
-               0x7F <= c2 && c2 <= 0x92 &&
-               0x21 <= c1 && c1 <= 0x7E) {
-               /* CP932 UDC */
-               if(c1 == 0x7F) return 0;
-               c1 = (c2 - 0x7F) * 94 + c1 - 0x21 + 0xE000 + CLASS_UNICODE;
-               c2 = 0;
-           }
-           (*oconv)(c2, c1); /* this is JIS, not SJIS/EUC case */
-           break;
-#ifdef X0212_ENABLE
-       case JIS_X_0212:
-           (*oconv)(PREFIX_EUCG3 | c2, c1);
-           break;
-#endif /* X0212_ENABLE */
-       case JIS_X_0213_2:
-           (*oconv)(PREFIX_EUCG3 | c2, c1);
-           break;
-       default:
-           (*oconv)(input_mode, c1);  /* other special case */
-       }
-
-        c2 = 0;
-        c0 = 0;
-        continue;
-        /* goto next_word */
-    }
-
-    /* epilogue */
-    (*iconv)(EOF, 0, 0);
-    if (!input_codename)
-    {
-       if (is_8bit) {
-           struct input_code *p = input_code_list;
-           struct input_code *result = p;
-           while (p->name){
-               if (p->score < result->score) result = p;
-               ++p;
-           }
-           set_input_codename(result->name);
-#ifdef CHECK_OPTION
-           debug(result->name);
-#endif
-       }
-    }
-    return 1;
-}
-
-nkf_char
-h_conv(FILE *f, nkf_char c2, nkf_char c1)
-{
-    nkf_char ret, c3, c0;
-    int hold_index;
-
-
-    /** it must NOT be in the kanji shifte sequence      */
-    /** it must NOT be written in JIS7                   */
-    /** and it must be after 2 byte 8bit code            */
-
-    hold_count = 0;
-    push_hold_buf(c2);
-    push_hold_buf(c1);
-
-    while ((c1 = (*i_getc)(f)) != EOF) {
-        if (c1 == ESC){
-           (*i_ungetc)(c1,f);
-            break;
-        }
-        code_status(c1);
-        if (push_hold_buf(c1) == EOF || estab_f){
-            break;
-        }
-    }
-
-    if (!estab_f){
-        struct input_code *p = input_code_list;
-        struct input_code *result = p;
-        if (c1 == EOF){
-            code_status(c1);
-        }
-        while (p->name){
-            if (p->status_func && p->score < result->score){
-                result = p;
-            }
-            ++p;
-        }
-        set_iconv(TRUE, result->iconv_func);
-    }
-
-
-    /** now,
-     ** 1) EOF is detected, or
-     ** 2) Code is established, or
-     ** 3) Buffer is FULL (but last word is pushed)
-     **
-     ** in 1) and 3) cases, we continue to use
-     ** Kanji codes by oconv and leave estab_f unchanged.
-     **/
-
-    ret = c1;
-    hold_index = 0;
-    while (hold_index < hold_count){
-        c2 = hold_buf[hold_index++];
-        if (c2 <= DEL
-#ifdef NUMCHAR_OPTION
-            || is_unicode_capsule(c2)
-#endif
-            ){
-            (*iconv)(0, c2, 0);
-            continue;
-        }else if (iconv == s_iconv && 0xa1 <= c2 && c2 <= 0xdf){
-            (*iconv)(JIS_X_0201, c2, 0);
-            continue;
-        }
-        if (hold_index < hold_count){
-            c1 = hold_buf[hold_index++];
-        }else{
-            c1 = (*i_getc)(f);
-            if (c1 == EOF){
-                c3 = EOF;
-                break;
-            }
-            code_status(c1);
-        }
-        c0 = 0;
-        switch ((*iconv)(c2, c1, 0)) {  /* can be EUC/SJIS/UTF-8 */
-       case -2:
-           /* 4 bytes UTF-8 */
-            if (hold_index < hold_count){
-                c0 = hold_buf[hold_index++];
-            } else if ((c0 = (*i_getc)(f)) == EOF) {
-               ret = EOF;
-               break;
-           } else {
-                code_status(c0);
-               c0 <<= 8;
-               if (hold_index < hold_count){
-                   c3 = hold_buf[hold_index++];
-               } else if ((c3 = (*i_getc)(f)) == EOF) {
-                   c0 = ret = EOF;
-                   break;
-               } else {
-                   code_status(c3);
-                   (*iconv)(c2, c1, c0|c3);
-               }
-            }
-           break;
-       case -1:
-           /* 3 bytes EUC or UTF-8 */
-            if (hold_index < hold_count){
-                c0 = hold_buf[hold_index++];
-            } else if ((c0 = (*i_getc)(f)) == EOF) {
-               ret = EOF;
-               break;
-           } else {
-                code_status(c0);
-            }
-            (*iconv)(c2, c1, c0);
-            break;
-       }
-       if (c0 == EOF) break;
-    }
-    return ret;
-}
-
-nkf_char push_hold_buf(nkf_char c2)
-{
-    if (hold_count >= HOLD_SIZE*2)
-        return (EOF);
-    hold_buf[hold_count++] = (unsigned char)c2;
-    return ((hold_count >= HOLD_SIZE*2) ? EOF : hold_count);
-}
-
-nkf_char s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
-{
-#if defined(SHIFTJIS_CP932) || defined(X0212_ENABLE)
-    nkf_char val;
+nkf_char s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
+{
+#if defined(SHIFTJIS_CP932) || defined(X0212_ENABLE)
+    nkf_char val;
 #endif
     static const char shift_jisx0213_s1a3_table[5][2] ={ { 1, 8}, { 3, 4}, { 5,12}, {13,14}, {15, 0} };
 #ifdef SHIFTJIS_CP932
@@ -3282,579 +2921,172 @@ nkf_char s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
        }
        if (c1 < 0x9F)
            c1 = c1 - ((c1 > DEL) ? SP : 0x1F);
-       else {
-           c1 = c1 - 0x7E;
-       }
-    }
-
-#ifdef X0212_ENABLE
-    c2 = x0212_unshift(c2);
-#endif
-    if (p2) *p2 = c2;
-    if (p1) *p1 = c1;
-    return 0;
-}
-
-nkf_char s_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
-{
-    if (c2 == JIS_X_0201) {
-       c1 &= 0x7f;
-    } else if ((c2 == EOF) || (c2 == 0) || c2 < SP) {
-        /* NOP */
-    } else if (!x0213_f && 0xF0 <= c2 && c2 <= 0xF9 && 0x40 <= c1 && c1 <= 0xFC) {
-       /* CP932 UDC */
-       if(c1 == 0x7F) return 0;
-       c1 = (c2 - 0xF0) * 188 + (c1 - 0x40 - (0x7E < c1)) + 0xE000 + CLASS_UNICODE;
-       c2 = 0;
-    } else {
-        nkf_char ret = s2e_conv(c2, c1, &c2, &c1);
-        if (ret) return ret;
-    }
-    (*oconv)(c2, c1);
-    return 0;
-}
-
-nkf_char e_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
-{
-    if (c2 == JIS_X_0201) {
-       c1 &= 0x7f;
-#ifdef X0212_ENABLE
-    }else if (c2 == 0x8f){
-        if (c0 == 0){
-            return -1;
-        }
-       if (!cp51932_f && !x0213_f && 0xF5 <= c1 && c1 <= 0xFE && 0xA1 <= c0 && c0 <= 0xFE) {
-           /* encoding is eucJP-ms, so invert to Unicode Private User Area */
-           c1 = (c1 - 0xF5) * 94 + c0 - 0xA1 + 0xE3AC + CLASS_UNICODE;
-           c2 = 0;
-       } else {
-           c2 = (c2 << 8) | (c1 & 0x7f);
-           c1 = c0 & 0x7f;
-#ifdef SHIFTJIS_CP932
-           if (cp51932_f){
-               nkf_char s2, s1;
-               if (e2s_conv(c2, c1, &s2, &s1) == 0){
-                   s2e_conv(s2, s1, &c2, &c1);
-                   if (c2 < 0x100){
-                       c1 &= 0x7f;
-                       c2 &= 0x7f;
-                   }
-               }
-           }
-#endif /* SHIFTJIS_CP932 */
-        }
-#endif /* X0212_ENABLE */
-    } else if (c2 == SSO){
-        c2 = JIS_X_0201;
-        c1 &= 0x7f;
-    } else if ((c2 == EOF) || (c2 == 0) || c2 < SP) {
-        /* NOP */
-    } else {
-       if (!cp51932_f && ms_ucs_map_f && 0xF5 <= c2 && c2 <= 0xFE && 0xA1 <= c1 && c1 <= 0xFE) {
-           /* encoding is eucJP-ms, so invert to Unicode Private User Area */
-           c1 = (c2 - 0xF5) * 94 + c1 - 0xA1 + 0xE000 + CLASS_UNICODE;
-           c2 = 0;
-       } else {
-           c1 &= 0x7f;
-           c2 &= 0x7f;
-#ifdef SHIFTJIS_CP932
-           if (cp51932_f && 0x79 <= c2 && c2 <= 0x7c){
-               nkf_char s2, s1;
-               if (e2s_conv(c2, c1, &s2, &s1) == 0){
-                   s2e_conv(s2, s1, &c2, &c1);
-                   if (c2 < 0x100){
-                       c1 &= 0x7f;
-                       c2 &= 0x7f;
-                   }
-               }
-           }
-#endif /* SHIFTJIS_CP932 */
-        }
-    }
-    (*oconv)(c2, c1);
-    return 0;
-}
-
-#ifdef UTF8_INPUT_ENABLE
-nkf_char w2e_conv(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char *p1)
-{
-    nkf_char ret = 0;
-
-    if (!c1){
-        *p2 = 0;
-        *p1 = c2;
-    }else if (0xc0 <= c2 && c2 <= 0xef) {
-       ret =  unicode_to_jis_common(c2, c1, c0, p2, p1);
-#ifdef NUMCHAR_OPTION
-        if (ret > 0){
-            if (p2) *p2 = 0;
-            if (p1) *p1 = CLASS_UNICODE | ww16_conv(c2, c1, c0);
-            ret = 0;
-        }
-#endif
-    }
-    return ret;
-}
-
-nkf_char w_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
-{
-    nkf_char ret = 0;
-    static const char w_iconv_utf8_1st_byte[] =
-    { /* 0xC0 - 0xFF */
-       20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-       21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-       30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 33,
-       40, 41, 41, 41, 42, 43, 43, 43, 50, 50, 50, 50, 60, 60, 70, 70};
-
-    if (c2 < 0 || 0xff < c2) {
-    }else if (c2 == 0) { /* 0 : 1 byte*/
-       c0 = 0;
-    } else if ((c2 & 0xc0) == 0x80) { /* 0x80-0xbf : trail byte */
-       return 0;
-    } else{
-       switch (w_iconv_utf8_1st_byte[c2 - 0xC0]) {
-       case 21:
-           if (c1 < 0x80 || 0xBF < c1) return 0;
-           break;
-       case 30:
-           if (c0 == 0) return -1;
-           if (c1 < 0xA0 || 0xBF < c1 || (c0 & 0xc0) != 0x80)
-               return 0;
-           break;
-       case 31:
-       case 33:
-           if (c0 == 0) return -1;
-           if ((c1 & 0xc0) != 0x80 || (c0 & 0xc0) != 0x80)
-               return 0;
-           break;
-       case 32:
-           if (c0 == 0) return -1;
-           if (c1 < 0x80 || 0x9F < c1 || (c0 & 0xc0) != 0x80)
-               return 0;
-           break;
-       case 40:
-           if (c0 == 0) return -2;
-           if (c1 < 0x90 || 0xBF < c1 || (c0 & 0xc0c0) != 0x8080)
-               return 0;
-           break;
-       case 41:
-           if (c0 == 0) return -2;
-           if (c1 < 0x80 || 0xBF < c1 || (c0 & 0xc0c0) != 0x8080)
-               return 0;
-           break;
-       case 42:
-           if (c0 == 0) return -2;
-           if (c1 < 0x80 || 0x8F < c1 || (c0 & 0xc0c0) != 0x8080)
-               return 0;
-           break;
-       default:
-           return 0;
-           break;
-       }
-    }
-    if (c2 == 0 || c2 == EOF){
-    } else if ((c2 & 0xf8) == 0xf0) { /* 4 bytes */
-       c1 = CLASS_UNICODE | ww16_conv(c2, c1, c0);
-       c2 = 0;
-    } else {
-       ret = w2e_conv(c2, c1, c0, &c2, &c1);
-    }
-    if (ret == 0){
-        (*oconv)(c2, c1);
-    }
-    return ret;
-}
-#endif
-
-#if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
-void w16w_conv(nkf_char val, nkf_char *p2, nkf_char *p1, nkf_char *p0)
-{
-    val &= VALUE_MASK;
-    if (val < 0x80){
-        *p2 = val;
-        *p1 = 0;
-        *p0 = 0;
-    }else if (val < 0x800){
-       *p2 = 0xc0 | (val >> 6);
-       *p1 = 0x80 | (val & 0x3f);
-        *p0 = 0;
-    } else if (val <= NKF_INT32_C(0xFFFF)) {
-        *p2 = 0xe0 | (val >> 12);
-        *p1 = 0x80 | ((val >> 6) & 0x3f);
-        *p0 = 0x80 | (val        & 0x3f);
-    } else if (val <= NKF_INT32_C(0x10FFFF)) {
-        *p2 = 0xe0 |  (val >> 16);
-        *p1 = 0x80 | ((val >> 12) & 0x3f);
-        *p0 = 0x8080 | ((val << 2) & 0x3f00)| (val & 0x3f);
-    } else {
-        *p2 = 0;
-        *p1 = 0;
-        *p0 = 0;
-    }
-}
-#endif
-
-#ifdef UTF8_INPUT_ENABLE
-nkf_char ww16_conv(nkf_char c2, nkf_char c1, nkf_char c0)
-{
-    nkf_char val;
-    if (c2 >= 0xf8) {
-       val = -1;
-    } else if (c2 >= 0xf0){
-       /* c2: 1st, c1: 2nd, c0: 3rd/4th */
-       val = (c2 & 0x0f) << 18;
-        val |= (c1 & 0x3f) << 12;
-        val |= (c0 & 0x3f00) >> 2;
-        val |= (c0 & 0x3f);
-    }else if (c2 >= 0xe0){
-        val = (c2 & 0x0f) << 12;
-        val |= (c1 & 0x3f) << 6;
-        val |= (c0 & 0x3f);
-    }else if (c2 >= 0xc0){
-        val = (c2 & 0x1f) << 6;
-        val |= (c1 & 0x3f);
-    }else{
-        val = c2;
-    }
-    return val;
-}
-
-nkf_char w16e_conv(nkf_char val, nkf_char *p2, nkf_char *p1)
-{
-    nkf_char c2, c1, c0;
-    nkf_char ret = 0;
-    val &= VALUE_MASK;
-    if (val < 0x80){
-        *p2 = 0;
-        *p1 = val;
-    }else{
-       w16w_conv(val, &c2, &c1, &c0);
-       ret =  unicode_to_jis_common(c2, c1, c0, p2, p1);
-#ifdef NUMCHAR_OPTION
-       if (ret > 0){
-           *p2 = 0;
-           *p1 = CLASS_UNICODE | val;
-           ret = 0;
+       else {
+           c1 = c1 - 0x7E;
        }
-#endif
     }
-    return ret;
-}
-#endif
 
-#ifdef UTF8_INPUT_ENABLE
-nkf_char w_iconv16(nkf_char c2, nkf_char c1, nkf_char c0)
-{
-    nkf_char ret = 0;
-    if ((c2==0 && c1 < 0x80) || c2==EOF) {
-       (*oconv)(c2, c1);
-       return 0;
-    }else if (0xD8 <= c2 && c2 <= 0xDB) {
-       if (c0 < NKF_INT32_C(0xDC00) || NKF_INT32_C(0xDFFF) < c0)
-           return -2;
-       c1 =  CLASS_UNICODE | ((c2 << 18) + (c1 << 10) + c0 - NKF_INT32_C(0x35FDC00));
-       c2 = 0;
-    }else if ((c2>>3) == 27) { /* unpaired surrogate */
-       /*
-          return 2;
-       */
-       return 1;
-    }else ret = w16e_conv(((c2 & 0xff)<<8) + c1, &c2, &c1);
-    if (ret) return ret;
-    (*oconv)(c2, c1);
+#ifdef X0212_ENABLE
+    c2 = x0212_unshift(c2);
+#endif
+    if (p2) *p2 = c2;
+    if (p1) *p1 = c1;
     return 0;
 }
 
-nkf_char w_iconv32(nkf_char c2, nkf_char c1, nkf_char c0)
+nkf_char s_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
 {
-    int ret = 0;
-
-    if ((c2 == 0 && c1 < 0x80) || c2==EOF) {
-    } else if (is_unicode_bmp(c1)) {
-       ret = w16e_conv(c1, &c2, &c1);
-    } else {
+    if (c2 == JIS_X_0201) {
+       c1 &= 0x7f;
+    } else if ((c2 == EOF) || (c2 == 0) || c2 < SP) {
+        /* NOP */
+    } else if (!x0213_f && 0xF0 <= c2 && c2 <= 0xF9 && 0x40 <= c1 && c1 <= 0xFC) {
+       /* CP932 UDC */
+       if(c1 == 0x7F) return 0;
+       c1 = (c2 - 0xF0) * 188 + (c1 - 0x40 - (0x7E < c1)) + 0xE000 + CLASS_UNICODE;
        c2 = 0;
-       c1 =  CLASS_UNICODE | c1;
+    } else {
+        nkf_char ret = s2e_conv(c2, c1, &c2, &c1);
+        if (ret) return ret;
     }
-    if (ret) return ret;
     (*oconv)(c2, c1);
     return 0;
 }
 
-nkf_char unicode_to_jis_common(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char *p1)
+nkf_char e_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
 {
-    const unsigned short *const *pp;
-    const unsigned short *const *const *ppp;
-    static const char no_best_fit_chars_table_C2[] =
-    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 2, 1, 1, 2,
-       0, 0, 1, 1, 0, 1, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1};
-    static const char no_best_fit_chars_table_C2_ms[] =
-    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0,
-       0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0};
-    static const char no_best_fit_chars_table_932_C2[] =
-    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1,
-       0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0};
-    static const char no_best_fit_chars_table_932_C3[] =
-    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1};
-    nkf_char ret = 0;
-
-    if(c2 < 0x80){
-       *p2 = 0;
-       *p1 = c2;
-    }else if(c2 < 0xe0){
-       if(no_best_fit_chars_f){
-           if(ms_ucs_map_f == UCS_MAP_CP932){
-               switch(c2){
-               case 0xC2:
-                   if(no_best_fit_chars_table_932_C2[c1&0x3F]) return 1;
-                   break;
-               case 0xC3:
-                   if(no_best_fit_chars_table_932_C3[c1&0x3F]) return 1;
-                   break;
-               }
-           }else if(!cp932inv_f){
-               switch(c2){
-               case 0xC2:
-                   if(no_best_fit_chars_table_C2[c1&0x3F]) return 1;
-                   break;
-               case 0xC3:
-                   if(no_best_fit_chars_table_932_C3[c1&0x3F]) return 1;
-                   break;
-               }
-           }else if(ms_ucs_map_f == UCS_MAP_MS){
-               if(c2 == 0xC2 && no_best_fit_chars_table_C2_ms[c1&0x3F]) return 1;
-           }else if(ms_ucs_map_f == UCS_MAP_CP10001){
-               switch(c2){
-               case 0xC2:
-                   switch(c1){
-                   case 0xA2:
-                   case 0xA3:
-                   case 0xA5:
-                   case 0xA6:
-                   case 0xAC:
-                   case 0xAF:
-                   case 0xB8:
-                       return 1;
-                   }
-                   break;
-               }
-           }
-       }
-       pp =
-           ms_ucs_map_f == UCS_MAP_CP932 ? utf8_to_euc_2bytes_932 :
-           ms_ucs_map_f == UCS_MAP_MS ? utf8_to_euc_2bytes_ms :
-           ms_ucs_map_f == UCS_MAP_CP10001 ? utf8_to_euc_2bytes_mac :
-           utf8_to_euc_2bytes;
-       ret =  w_iconv_common(c2, c1, pp, sizeof_utf8_to_euc_2bytes, p2, p1);
-    }else if(c0 < 0xF0){
-       if(no_best_fit_chars_f){
-           if(ms_ucs_map_f == UCS_MAP_CP932){
-               if(c2 == 0xE3 && c1 == 0x82 && c0 == 0x94) return 1;
-           }else if(ms_ucs_map_f == UCS_MAP_MS){
-               switch(c2){
-               case 0xE2:
-                   switch(c1){
-                   case 0x80:
-                       if(c0 == 0x94 || c0 == 0x96 || c0 == 0xBE) return 1;
-                       break;
-                   case 0x88:
-                       if(c0 == 0x92) return 1;
-                       break;
-                   }
-                   break;
-               case 0xE3:
-                   if(c1 == 0x80 || c0 == 0x9C) return 1;
-                   break;
-               }
-           }else if(ms_ucs_map_f == UCS_MAP_CP10001){
-               switch(c2){
-               case 0xE3:
-                   switch(c1){
-                   case 0x82:
-                           if(c0 == 0x94) return 1;
-                       break;
-                   case 0x83:
-                           if(c0 == 0xBB) return 1;
-                       break;
-                   }
-                   break;
-               }
-           }else{
-               switch(c2){
-               case 0xE2:
-                   switch(c1){
-                   case 0x80:
-                       if(c0 == 0x95) return 1;
-                       break;
-                   case 0x88:
-                       if(c0 == 0xA5) return 1;
-                       break;
-                   }
-                   break;
-               case 0xEF:
-                   switch(c1){
-                   case 0xBC:
-                       if(c0 == 0x8D) return 1;
-                       break;
-                   case 0xBD:
-                       if(c0 == 0x9E && !cp932inv_f) return 1;
-                       break;
-                   case 0xBF:
-                       if(0xA0 <= c0 && c0 <= 0xA5) return 1;
-                       break;
+    if (c2 == JIS_X_0201) {
+       c1 &= 0x7f;
+#ifdef X0212_ENABLE
+    }else if (c2 == 0x8f){
+        if (c0 == 0){
+            return -1;
+        }
+       if (!cp51932_f && !x0213_f && 0xF5 <= c1 && c1 <= 0xFE && 0xA1 <= c0 && c0 <= 0xFE) {
+           /* encoding is eucJP-ms, so invert to Unicode Private User Area */
+           c1 = (c1 - 0xF5) * 94 + c0 - 0xA1 + 0xE3AC + CLASS_UNICODE;
+           c2 = 0;
+       } else {
+           c2 = (c2 << 8) | (c1 & 0x7f);
+           c1 = c0 & 0x7f;
+#ifdef SHIFTJIS_CP932
+           if (cp51932_f){
+               nkf_char s2, s1;
+               if (e2s_conv(c2, c1, &s2, &s1) == 0){
+                   s2e_conv(s2, s1, &c2, &c1);
+                   if (c2 < 0x100){
+                       c1 &= 0x7f;
+                       c2 &= 0x7f;
                    }
-                   break;
                }
            }
-       }
-       ppp =
-           ms_ucs_map_f == UCS_MAP_CP932 ? utf8_to_euc_3bytes_932 :
-           ms_ucs_map_f == UCS_MAP_MS ? utf8_to_euc_3bytes_ms :
-           ms_ucs_map_f == UCS_MAP_CP10001 ? utf8_to_euc_3bytes_mac :
-           utf8_to_euc_3bytes;
-       ret = w_iconv_common(c1, c0, ppp[c2 - 0xE0], sizeof_utf8_to_euc_C2, p2, p1);
-    }else return -1;
-#ifdef SHIFTJIS_CP932
-    if (!ret && !cp932inv_f && is_eucg3(*p2)) {
-       nkf_char s2, s1;
-       if (e2s_conv(*p2, *p1, &s2, &s1) == 0) {
-           s2e_conv(s2, s1, p2, p1);
-       }else{
-           ret = 1;
-       }
-    }
-#endif
-    return ret;
-}
-
-nkf_char w_iconv_common(nkf_char c1, nkf_char c0, const unsigned short *const *pp, nkf_char psize, nkf_char *p2, nkf_char *p1)
-{
-    nkf_char c2;
-    const unsigned short *p;
-    unsigned short val;
-
-    if (pp == 0) return 1;
-
-    c1 -= 0x80;
-    if (c1 < 0 || psize <= c1) return 1;
-    p = pp[c1];
-    if (p == 0)  return 1;
-
-    c0 -= 0x80;
-    if (c0 < 0 || sizeof_utf8_to_euc_C2 <= c0) return 1;
-    val = p[c0];
-    if (val == 0) return 1;
-    if (no_cp932ext_f && (
-       (val>>8) == 0x2D || /* NEC special characters */
-       val > NKF_INT32_C(0xF300) /* IBM extended characters */
-       )) return 1;
-
-    c2 = val >> 8;
-   if (val > 0x7FFF){
-        c2 &= 0x7f;
-        c2 |= PREFIX_EUCG3;
+#endif /* SHIFTJIS_CP932 */
+        }
+#endif /* X0212_ENABLE */
+    } else if (c2 == SSO){
+        c2 = JIS_X_0201;
+        c1 &= 0x7f;
+    } else if ((c2 == EOF) || (c2 == 0) || c2 < SP) {
+        /* NOP */
+    } else {
+       if (!cp51932_f && ms_ucs_map_f && 0xF5 <= c2 && c2 <= 0xFE && 0xA1 <= c1 && c1 <= 0xFE) {
+           /* encoding is eucJP-ms, so invert to Unicode Private User Area */
+           c1 = (c2 - 0xF5) * 94 + c1 - 0xA1 + 0xE000 + CLASS_UNICODE;
+           c2 = 0;
+       } else {
+           c1 &= 0x7f;
+           c2 &= 0x7f;
+#ifdef SHIFTJIS_CP932
+           if (cp51932_f && 0x79 <= c2 && c2 <= 0x7c){
+               nkf_char s2, s1;
+               if (e2s_conv(c2, c1, &s2, &s1) == 0){
+                   s2e_conv(s2, s1, &c2, &c1);
+                   if (c2 < 0x100){
+                       c1 &= 0x7f;
+                       c2 &= 0x7f;
+                   }
+               }
+           }
+#endif /* SHIFTJIS_CP932 */
+        }
     }
-    if (c2 == SO) c2 = JIS_X_0201;
-    c1 = val & 0x7f;
-    if (p2) *p2 = c2;
-    if (p1) *p1 = c1;
+    (*oconv)(c2, c1);
     return 0;
 }
 
-void nkf_each_char_to_hex(void (*f)(nkf_char c2,nkf_char c1), nkf_char c)
+#if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
+void w16w_conv(nkf_char val, nkf_char *p2, nkf_char *p1, nkf_char *p0)
 {
-    int shift = 20;
-    c &= VALUE_MASK;
-    while(shift >= 0){
-       if(c >= 1<<shift){
-           while(shift >= 0){
-               (*f)(0, bin2hex(c>>shift));
-               shift -= 4;
-           }
-       }else{
-           shift -= 4;
-       }
+    val &= VALUE_MASK;
+    if (val < 0x80){
+        *p2 = val;
+        *p1 = 0;
+        *p0 = 0;
+    }else if (val < 0x800){
+       *p2 = 0xc0 | (val >> 6);
+       *p1 = 0x80 | (val & 0x3f);
+        *p0 = 0;
+    } else if (val <= NKF_INT32_C(0xFFFF)) {
+        *p2 = 0xe0 | (val >> 12);
+        *p1 = 0x80 | ((val >> 6) & 0x3f);
+        *p0 = 0x80 | (val        & 0x3f);
+    } else if (val <= NKF_INT32_C(0x10FFFF)) {
+        *p2 = 0xe0 |  (val >> 16);
+        *p1 = 0x80 | ((val >> 12) & 0x3f);
+        *p0 = 0x8080 | ((val << 2) & 0x3f00)| (val & 0x3f);
+    } else {
+        *p2 = 0;
+        *p1 = 0;
+        *p0 = 0;
     }
-    return;
-}
-
-void encode_fallback_html(nkf_char c)
-{
-    (*oconv)(0, '&');
-    (*oconv)(0, '#');
-    c &= VALUE_MASK;
-    if(c >= NKF_INT32_C(1000000))
-       (*oconv)(0, 0x30+(c/NKF_INT32_C(1000000))%10);
-    if(c >= NKF_INT32_C(100000))
-       (*oconv)(0, 0x30+(c/NKF_INT32_C(100000) )%10);
-    if(c >= 10000)
-       (*oconv)(0, 0x30+(c/10000  )%10);
-    if(c >= 1000)
-       (*oconv)(0, 0x30+(c/1000   )%10);
-    if(c >= 100)
-       (*oconv)(0, 0x30+(c/100    )%10);
-    if(c >= 10)
-       (*oconv)(0, 0x30+(c/10     )%10);
-    if(c >= 0)
-       (*oconv)(0, 0x30+ c         %10);
-    (*oconv)(0, ';');
-    return;
-}
-
-void encode_fallback_xml(nkf_char c)
-{
-    (*oconv)(0, '&');
-    (*oconv)(0, '#');
-    (*oconv)(0, 'x');
-    nkf_each_char_to_hex(oconv, c);
-    (*oconv)(0, ';');
-    return;
 }
+#endif
 
-void encode_fallback_java(nkf_char c)
+#ifdef UTF8_INPUT_ENABLE
+nkf_char ww16_conv(nkf_char c2, nkf_char c1, nkf_char c0)
 {
-    (*oconv)(0, '\\');
-    c &= VALUE_MASK;
-    if(!is_unicode_bmp(c)){
-       (*oconv)(0, 'U');
-       (*oconv)(0, '0');
-       (*oconv)(0, '0');
-       (*oconv)(0, bin2hex(c>>20));
-       (*oconv)(0, bin2hex(c>>16));
+    nkf_char val;
+    if (c2 >= 0xf8) {
+       val = -1;
+    } else if (c2 >= 0xf0){
+       /* c2: 1st, c1: 2nd, c0: 3rd/4th */
+       val = (c2 & 0x0f) << 18;
+        val |= (c1 & 0x3f) << 12;
+        val |= (c0 & 0x3f00) >> 2;
+        val |= (c0 & 0x3f);
+    }else if (c2 >= 0xe0){
+        val = (c2 & 0x0f) << 12;
+        val |= (c1 & 0x3f) << 6;
+        val |= (c0 & 0x3f);
+    }else if (c2 >= 0xc0){
+        val = (c2 & 0x1f) << 6;
+        val |= (c1 & 0x3f);
     }else{
-       (*oconv)(0, 'u');
+        val = c2;
     }
-    (*oconv)(0, bin2hex(c>>12));
-    (*oconv)(0, bin2hex(c>> 8));
-    (*oconv)(0, bin2hex(c>> 4));
-    (*oconv)(0, bin2hex(c    ));
-    return;
-}
-
-void encode_fallback_perl(nkf_char c)
-{
-    (*oconv)(0, '\\');
-    (*oconv)(0, 'x');
-    (*oconv)(0, '{');
-    nkf_each_char_to_hex(oconv, c);
-    (*oconv)(0, '}');
-    return;
+    return val;
 }
 
-void encode_fallback_subchar(nkf_char c)
+nkf_char w16e_conv(nkf_char val, nkf_char *p2, nkf_char *p1)
 {
-    c = unicode_subchar;
-    (*oconv)((c>>8)&0xFF, c&0xFF);
-    return;
+    nkf_char c2, c1, c0;
+    nkf_char ret = 0;
+    val &= VALUE_MASK;
+    if (val < 0x80){
+        *p2 = 0;
+        *p1 = val;
+    }else{
+       w16w_conv(val, &c2, &c1, &c0);
+       ret =  unicode_to_jis_common(c2, c1, c0, p2, p1);
+#ifdef NUMCHAR_OPTION
+       if (ret > 0){
+           *p2 = 0;
+           *p1 = CLASS_UNICODE | val;
+           ret = 0;
+       }
+#endif
+    }
+    return ret;
 }
 #endif
 
@@ -4145,36 +3377,6 @@ void e_oconv(nkf_char c2, nkf_char c1)
     }
 }
 
-#ifdef X0212_ENABLE
-nkf_char x0212_shift(nkf_char c)
-{
-    nkf_char ret = c;
-    c &= 0x7f;
-    if (is_eucg3(ret)){
-        if (0x75 <= c && c <= 0x7f){
-            ret = c + (0x109 - 0x75);
-        }
-    }else{
-        if (0x75 <= c && c <= 0x7f){
-            ret = c + (0x113 - 0x75);
-        }
-    }
-    return ret;
-}
-
-
-nkf_char x0212_unshift(nkf_char c)
-{
-    nkf_char ret = c;
-    if (0x7f <= c && c <= 0x88){
-        ret = c + (0x75 - 0x7f);
-    }else if (0x89 <= c && c <= 0x92){
-        ret = PREFIX_EUCG3 | 0x80 | (c + (0x75 - 0x89));
-    }
-    return ret;
-}
-#endif /* X0212_ENABLE */
-
 nkf_char e2s_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
 {
     nkf_char ndx;
@@ -4381,79 +3583,90 @@ void j_oconv(nkf_char c2, nkf_char c1)
     }
 }
 
-void base64_conv(nkf_char c2, nkf_char c1)
+static struct {
+    int count;
+    nkf_char status;
+    nkf_char buf[3];
+} broken_state;
+
+static void init_broken_state(void)
 {
-    mime_prechar(c2, c1);
-    (*o_base64conv)(c2,c1);
+    memset(&broken_state, 0, sizeof(broken_state));
+}
+
+static void push_broken_buf(c)
+{
+    broken_state.buf[broken_state.count++] = c;
 }
 
+static nkf_char pop_broken_buf(void)
+{
+    return broken_state.buf[--broken_state.count];
+}
 
-static nkf_char broken_buf[3];
-static int broken_counter = 0;
-static int broken_last = 0;
 nkf_char broken_getc(FILE *f)
 {
-    nkf_char c,c1;
+    nkf_char c, c1;
 
-    if (broken_counter>0) {
-       return broken_buf[--broken_counter];
+    if (broken_state.count > 0) {
+       return pop_broken_buf();
     }
-    c= (*i_bgetc)(f);
-    if (c=='$' && broken_last != ESC
+    c = (*i_bgetc)(f);
+    if (c=='$' && broken_state.status != ESC
             && (input_mode==ASCII || input_mode==JIS_X_0201)) {
        c1= (*i_bgetc)(f);
-       broken_last = 0;
+       broken_state.status = 0;
        if (c1=='@'|| c1=='B') {
-           broken_buf[0]=c1; broken_buf[1]=c;
-           broken_counter=2;
+           push_broken_buf(c1);
+           push_broken_buf(c);
            return ESC;
        } else {
            (*i_bungetc)(c1,f);
            return c;
        }
-    } else if (c=='(' && broken_last != ESC
+    } else if (c=='(' && broken_state.status != ESC
             && (input_mode==JIS_X_0208 || input_mode==JIS_X_0201)) { /* ) */
        c1= (*i_bgetc)(f);
-       broken_last = 0;
+       broken_state.status = 0;
        if (c1=='J'|| c1=='B') {
-           broken_buf[0]=c1; broken_buf[1]=c;
-           broken_counter=2;
+           push_broken_buf(c1);
+           push_broken_buf(c);
            return ESC;
        } else {
            (*i_bungetc)(c1,f);
            return c;
        }
     } else {
-       broken_last = c;
+       broken_state.status = c;
        return c;
     }
 }
 
 nkf_char broken_ungetc(nkf_char c, FILE *f)
 {
-    if (broken_counter<2)
-       broken_buf[broken_counter++]=c;
+    if (broken_state.count < 2)
+       push_broken_buf(c);
     return c;
 }
 
-void nl_conv(nkf_char c2, nkf_char c1)
+void eol_conv(nkf_char c2, nkf_char c1)
 {
-    if (guess_f && input_newline != EOF) {
+    if (guess_f && input_eol != EOF) {
        if (c2 == 0 && c1 == LF) {
-           if (!input_newline) input_newline = prev_cr ? CRLF : LF;
-           else if (input_newline != (prev_cr ? CRLF : LF)) input_newline = EOF;
-       } else if (c2 == 0 && c1 == CR && input_newline == LF) input_newline = EOF;
+           if (!input_eol) input_eol = prev_cr ? CRLF : LF;
+           else if (input_eol != (prev_cr ? CRLF : LF)) input_eol = EOF;
+       } else if (c2 == 0 && c1 == CR && input_eol == LF) input_eol = EOF;
        else if (!prev_cr);
-       else if (!input_newline) input_newline = CR;
-       else if (input_newline != CR) input_newline = EOF;
+       else if (!input_eol) input_eol = CR;
+       else if (input_eol != CR) input_eol = EOF;
     }
     if (prev_cr || (c2 == 0 && c1 == LF)) {
        prev_cr = 0;
-       if (nlmode_f != LF) (*o_nlconv)(0, CR);
-       if (nlmode_f != CR) (*o_nlconv)(0, LF);
+       if (eolmode_f != LF) (*o_eol_conv)(0, CR);
+       if (eolmode_f != CR) (*o_eol_conv)(0, LF);
     }
     if (c2 == 0 && c1 == CR) prev_cr = CR;
-    else if (c2 != 0 || c1 != LF) (*o_nlconv)(c2, c1);
+    else if (c2 != 0 || c1 != LF) (*o_eol_conv)(c2, c1);
 }
 
 /*
@@ -4955,8 +4168,49 @@ static const nkf_char mime_encode_method[] = {
 };
 
 
+/* MIME preprocessor fifo */
+
+#define MIME_BUF_SIZE   (1024)    /* 2^n ring buffer */
+#define MIME_BUF_MASK   (MIME_BUF_SIZE-1)
+#define mime_input_buf(n)        mime_input_state.buf[(n)&MIME_BUF_MASK]
+static struct {
+    unsigned char buf[MIME_BUF_SIZE];
+    unsigned int  top;
+    unsigned int  last;  /* decoded */
+    unsigned int  input; /* undecoded */
+} mime_input_state;
+static nkf_char (*mime_iconv_back)(nkf_char c2,nkf_char c1,nkf_char c0) = NULL;
+
 #define MAXRECOVER 20
 
+static void mime_input_buf_unshift(nkf_char c)
+{
+    mime_input_buf(--mime_input_state.top) = (unsigned char)c;
+}
+
+nkf_char mime_ungetc(nkf_char c, FILE *f)
+{
+    mime_input_buf_unshift(c);
+    return c;
+}
+
+nkf_char mime_ungetc_buf(nkf_char c, FILE *f)
+{
+    if (mimebuf_f)
+       (*i_mungetc_buf)(c,f);
+    else
+       mime_input_buf(--mime_input_state.input) = (unsigned char)c;
+    return c;
+}
+
+nkf_char mime_getc_buf(FILE *f)
+{
+    /* we don't keep eof of mime_input_buf, becase it contains ?= as
+       a terminator. It was checked in mime_integrity. */
+    return ((mimebuf_f)?
+        (*i_mgetc_buf)(f):mime_input_buf(mime_input_state.input++));
+}
+
 void switch_mime_getc(void)
 {
     if (i_getc!=mime_getc) {
@@ -4981,6 +4235,44 @@ void unswitch_mime_getc(void)
     mime_iconv_back = NULL;
 }
 
+nkf_char mime_integrity(FILE *f, const unsigned char *p)
+{
+    nkf_char c,d;
+    unsigned int q;
+    /* In buffered mode, read until =? or NL or buffer full
+     */
+    mime_input_state.input = mime_input_state.top;
+    mime_input_state.last = mime_input_state.top;
+
+    while(*p) mime_input_buf(mime_input_state.input++) = *p++;
+    d = 0;
+    q = mime_input_state.input;
+    while((c=(*i_getc)(f))!=EOF) {
+        if (((mime_input_state.input-mime_input_state.top)&MIME_BUF_MASK)==0) {
+           break;   /* buffer full */
+       }
+        if (c=='=' && d=='?') {
+            /* checked. skip header, start decode */
+            mime_input_buf(mime_input_state.input++) = (unsigned char)c;
+            /* mime_last_input = mime_input_state.input; */
+            mime_input_state.input = q;
+           switch_mime_getc();
+            return 1;
+        }
+        if (!( (c=='+'||c=='/'|| c=='=' || c=='?' || is_alnum(c))))
+            break;
+        /* Should we check length mod 4? */
+        mime_input_buf(mime_input_state.input++) = (unsigned char)c;
+        d=c;
+    }
+    /* In case of Incomplete MIME, no MIME decode  */
+    mime_input_buf(mime_input_state.input++) = (unsigned char)c;
+    mime_input_state.last = mime_input_state.input;     /* point undecoded buffer */
+    mime_decode_mode = 1;              /* no decode on mime_input_buf last in mime_getc */
+    switch_mime_getc();         /* anyway we need buffered getc */
+    return 1;
+}
+
 nkf_char mime_begin_strict(FILE *f)
 {
     nkf_char c1 = 0;
@@ -5032,23 +4324,6 @@ nkf_char mime_begin_strict(FILE *f)
     return c1;
 }
 
-nkf_char mime_getc_buf(FILE *f)
-{
-    /* we don't keep eof of Fifo, becase it contains ?= as
-       a terminator. It was checked in mime_integrity. */
-    return ((mimebuf_f)?
-        (*i_mgetc_buf)(f):Fifo(mime_input++));
-}
-
-nkf_char mime_ungetc_buf(nkf_char c, FILE *f)
-{
-    if (mimebuf_f)
-       (*i_mungetc_buf)(c,f);
-    else
-       Fifo(--mime_input) = (unsigned char)c;
-    return c;
-}
-
 nkf_char mime_begin(FILE *f)
 {
     nkf_char c1;
@@ -5058,23 +4333,23 @@ nkf_char mime_begin(FILE *f)
     /* re-read and convert again from mime_buffer.  */
 
     /* =? has been checked */
-    k = mime_last;
-    Fifo(mime_last++)='='; Fifo(mime_last++)='?';
+    k = mime_input_state.last;
+    mime_input_buf(mime_input_state.last++)='='; mime_input_buf(mime_input_state.last++)='?';
     for(i=2;i<MAXRECOVER;i++) {                   /* start at =? */
         /* We accept any character type even if it is breaked by new lines */
-        c1 = (*i_getc)(f); Fifo(mime_last++) = (unsigned char)c1;
+        c1 = (*i_getc)(f); mime_input_buf(mime_input_state.last++) = (unsigned char)c1;
         if (c1==LF||c1==SP||c1==CR||
                 c1=='-'||c1=='_'||is_alnum(c1)) continue;
         if (c1=='=') {
             /* Failed. But this could be another MIME preemble */
             (*i_ungetc)(c1,f);
-            mime_last--;
+            mime_input_state.last--;
             break;
         }
         if (c1!='?') break;
         else {
             /* c1=='?' */
-            c1 = (*i_getc)(f); Fifo(mime_last++) = (unsigned char)c1;
+            c1 = (*i_getc)(f); mime_input_buf(mime_input_state.last++) = (unsigned char)c1;
             if (!(++i<MAXRECOVER) || c1==EOF) break;
             if (c1=='b'||c1=='B') {
                 mime_decode_mode = 'B';
@@ -5083,7 +4358,7 @@ nkf_char mime_begin(FILE *f)
             } else {
                 break;
             }
-            c1 = (*i_getc)(f); Fifo(mime_last++) = (unsigned char)c1;
+            c1 = (*i_getc)(f); mime_input_buf(mime_input_state.last++) = (unsigned char)c1;
             if (!(++i<MAXRECOVER) || c1==EOF) break;
             if (c1!='?') {
                 mime_decode_mode = FALSE;
@@ -5099,1312 +4374,2006 @@ nkf_char mime_begin(FILE *f)
         /* we never go into mime_begin again for a while.           */
         return c1;
     }
-    /* discard mime preemble, and goto MIME mode */
-    mime_last = k;
-    /* do no MIME integrity check */
-    return c1;   /* used only for checking EOF */
+    /* discard mime preemble, and goto MIME mode */
+    mime_input_state.last = k;
+    /* do no MIME integrity check */
+    return c1;   /* used only for checking EOF */
+}
+
+#ifdef CHECK_OPTION
+void no_putc(nkf_char c)
+{
+    ;
+}
+
+void debug(const char *str)
+{
+    if (debug_f){
+        fprintf(stderr, "%s\n", str ? str : "NULL");
+    }
+}
+#endif
+
+void set_input_codename(char *codename)
+{
+    if (!input_codename) {
+       input_codename = codename;
+    } else if (strcmp(codename, input_codename) != 0) {
+       input_codename = "";
+    }
+}
+
+static char* get_guessed_code(void)
+{
+    if (input_codename && !*input_codename) {
+       input_codename = "BINARY";
+    } else {
+       struct input_code *p = find_inputcode_byfunc(iconv);
+       if (!input_codename) {
+           input_codename = "ASCII";
+       } else if (strcmp(input_codename, "Shift_JIS") == 0) {
+           if (p->score & (SCORE_DEPEND|SCORE_CP932))
+               input_codename = "CP932";
+       } else if (strcmp(input_codename, "EUC-JP") == 0) {
+           if (p->score & (SCORE_X0212))
+               input_codename = "EUCJP-MS";
+           else if (p->score & (SCORE_DEPEND|SCORE_CP932))
+               input_codename = "CP51932";
+       } else if (strcmp(input_codename, "ISO-2022-JP") == 0) {
+           if (p->score & (SCORE_KANA))
+               input_codename = "CP50221";
+           else if (p->score & (SCORE_DEPEND|SCORE_CP932))
+               input_codename = "CP50220";
+       }
+    }
+    return input_codename;
+}
+
+#if !defined(PERL_XS) && !defined(WIN32DLL)
+void print_guessed_code(char *filename)
+{
+    if (filename != NULL) printf("%s: ", filename);
+    if (input_codename && !*input_codename) {
+       printf("BINARY\n");
+    } else {
+       input_codename = get_guessed_code();
+       if (guess_f == 1) {
+           printf("%s\n", input_codename);
+       } else {
+           printf("%s%s\n",
+                  input_codename,
+                  input_eol == CR   ? " (CR)" :
+                  input_eol == LF   ? " (LF)" :
+                  input_eol == CRLF ? " (CRLF)" :
+                  input_eol == EOF  ? " (MIXED NL)" :
+                  "");
+       }
+    }
+}
+#endif /*WIN32DLL*/
+
+#ifdef INPUT_OPTION
+
+nkf_char hex_getc(nkf_char ch, FILE *f, nkf_char (*g)(FILE *f), nkf_char (*u)(nkf_char c, FILE *f))
+{
+    nkf_char c1, c2, c3;
+    c1 = (*g)(f);
+    if (c1 != ch){
+        return c1;
+    }
+    c2 = (*g)(f);
+    if (!nkf_isxdigit(c2)){
+        (*u)(c2, f);
+        return c1;
+    }
+    c3 = (*g)(f);
+    if (!nkf_isxdigit(c3)){
+        (*u)(c2, f);
+        (*u)(c3, f);
+        return c1;
+    }
+    return (hex2bin(c2) << 4) | hex2bin(c3);
+}
+
+nkf_char cap_getc(FILE *f)
+{
+    return hex_getc(':', f, i_cgetc, i_cungetc);
+}
+
+nkf_char cap_ungetc(nkf_char c, FILE *f)
+{
+    return (*i_cungetc)(c, f);
+}
+
+nkf_char url_getc(FILE *f)
+{
+    return hex_getc('%', f, i_ugetc, i_uungetc);
+}
+
+nkf_char url_ungetc(nkf_char c, FILE *f)
+{
+    return (*i_uungetc)(c, f);
+}
+#endif
+
+#ifdef NUMCHAR_OPTION
+nkf_char numchar_getc(FILE *f)
+{
+    nkf_char (*g)(FILE *) = i_ngetc;
+    nkf_char (*u)(nkf_char c ,FILE *f) = i_nungetc;
+    int i = 0, j;
+    nkf_char buf[8];
+    long c = -1;
+
+    buf[i] = (*g)(f);
+    if (buf[i] == '&'){
+        buf[++i] = (*g)(f);
+        if (buf[i] == '#'){
+            c = 0;
+            buf[++i] = (*g)(f);
+            if (buf[i] == 'x' || buf[i] == 'X'){
+                for (j = 0; j < 7; j++){
+                    buf[++i] = (*g)(f);
+                    if (!nkf_isxdigit(buf[i])){
+                        if (buf[i] != ';'){
+                            c = -1;
+                        }
+                        break;
+                    }
+                    c <<= 4;
+                    c |= hex2bin(buf[i]);
+                }
+            }else{
+                for (j = 0; j < 8; j++){
+                    if (j){
+                        buf[++i] = (*g)(f);
+                    }
+                    if (!nkf_isdigit(buf[i])){
+                        if (buf[i] != ';'){
+                            c = -1;
+                        }
+                        break;
+                    }
+                    c *= 10;
+                    c += hex2bin(buf[i]);
+                }
+            }
+        }
+    }
+    if (c != -1){
+        return CLASS_UNICODE | c;
+    }
+    while (i > 0){
+        (*u)(buf[i], f);
+        --i;
+    }
+    return buf[0];
+}
+
+nkf_char numchar_ungetc(nkf_char c, FILE *f)
+{
+    return (*i_nungetc)(c, f);
+}
+#endif
+
+#ifdef UNICODE_NORMALIZATION
+
+/* Normalization Form C */
+nkf_char nfc_getc(FILE *f)
+{
+    nkf_char (*g)(FILE *f) = i_nfc_getc;
+    nkf_char (*u)(nkf_char c ,FILE *f) = i_nfc_ungetc;
+    int i=0, j, k=1, lower, upper;
+    nkf_char buf[9];
+    const unsigned char *array;
+
+    buf[i] = (*g)(f);
+    while (k > 0 && ((buf[i] & 0xc0) != 0x80)){
+       lower=0, upper=NORMALIZATION_TABLE_LENGTH-1;
+       while (upper >= lower) {
+           j = (lower+upper) / 2;
+           array = normalization_table[j].nfd;
+           for (k=0; k < NORMALIZATION_TABLE_NFD_LENGTH && array[k]; k++){
+               if (array[k] != buf[k]){
+                   array[k] < buf[k] ? (lower = j + 1) : (upper = j - 1);
+                   k = 0;
+                   break;
+               } else if (k >= i)
+                   buf[++i] = (*g)(f);
+           }
+           if (k > 0){
+               array = normalization_table[j].nfc;
+               for (i=0; i < NORMALIZATION_TABLE_NFC_LENGTH && array[i]; i++)
+                   buf[i] = (nkf_char)(array[i]);
+               i--;
+               break;
+           }
+       }
+       while (i > 0)
+           (*u)(buf[i--], f);
+    }
+    return buf[0];
+}
+
+nkf_char nfc_ungetc(nkf_char c, FILE *f)
+{
+    return (*i_nfc_ungetc)(c, f);
+}
+#endif /* UNICODE_NORMALIZATION */
+
+
+static nkf_char base64decode(nkf_char c)
+{
+    int             i;
+    if (c > '@') {
+        if (c < '[') {
+            i = c - 'A';                        /* A..Z 0-25 */
+       } else if (c == '_') {
+           i = '?'         /* 63 */ ;          /* _  63 */
+        } else {
+            i = c - 'G'     /* - 'a' + 26 */ ;  /* a..z 26-51 */
+       }
+    } else if (c > '/') {
+        i = c - '0' + '4'   /* - '0' + 52 */ ;  /* 0..9 52-61 */
+    } else if (c == '+' || c == '-') {
+        i = '>'             /* 62 */ ;          /* + and -  62 */
+    } else {
+        i = '?'             /* 63 */ ;          /* / 63 */
+    }
+    return (i);
 }
 
-#ifdef CHECK_OPTION
-void no_putc(nkf_char c)
+nkf_char
+mime_getc(FILE *f)
 {
-    ;
-}
+    nkf_char c1, c2, c3, c4, cc;
+    nkf_char t1, t2, t3, t4, mode, exit_mode;
+    nkf_char lwsp_count;
+    char *lwsp_buf;
+    char *lwsp_buf_new;
+    nkf_char lwsp_size = 128;
 
-void debug(const char *str)
-{
-    if (debug_f){
-        fprintf(stderr, "%s\n", str ? str : "NULL");
+    if (mime_input_state.top != mime_input_state.last) {  /* Something is in FIFO */
+        return  mime_input_buf(mime_input_state.top++);
     }
-}
-#endif
-
-void set_input_codename(char *codename)
-{
-    if (!input_codename) {
-       input_codename = codename;
-    } else if (strcmp(codename, input_codename) != 0) {
-       input_codename = "";
+    if (mime_decode_mode==1 ||mime_decode_mode==FALSE) {
+       mime_decode_mode=FALSE;
+       unswitch_mime_getc();
+       return (*i_getc)(f);
     }
-}
 
-static char* get_guessed_code(void)
-{
-    if (input_codename && !*input_codename) {
-       input_codename = "BINARY";
-    } else {
-       struct input_code *p = find_inputcode_byfunc(iconv);
-       if (!input_codename) {
-           input_codename = "ASCII";
-       } else if (strcmp(input_codename, "Shift_JIS") == 0) {
-           if (p->score & (SCORE_DEPEND|SCORE_CP932))
-               input_codename = "CP932";
-       } else if (strcmp(input_codename, "EUC-JP") == 0) {
-           if (p->score & (SCORE_X0212))
-               input_codename = "EUCJP-MS";
-           else if (p->score & (SCORE_DEPEND|SCORE_CP932))
-               input_codename = "CP51932";
-       } else if (strcmp(input_codename, "ISO-2022-JP") == 0) {
-           if (p->score & (SCORE_KANA))
-               input_codename = "CP50221";
-           else if (p->score & (SCORE_DEPEND|SCORE_CP932))
-               input_codename = "CP50220";
+    if (mimebuf_f == FIXED_MIME)
+        exit_mode = mime_decode_mode;
+    else
+        exit_mode = FALSE;
+    if (mime_decode_mode == 'Q') {
+        if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
+restart_mime_q:
+        if (c1=='_' && mimebuf_f != FIXED_MIME) return SP;
+       if (c1<=SP || DEL<=c1) {
+           mime_decode_mode = exit_mode; /* prepare for quit */
+           return c1;
+       }
+        if (c1!='=' && (c1!='?' || mimebuf_f == FIXED_MIME)) {
+           return c1;
+       }
+
+        mime_decode_mode = exit_mode; /* prepare for quit */
+        if ((c2 = (*i_mgetc)(f)) == EOF) return (EOF);
+        if (c1=='?'&&c2=='=' && mimebuf_f != FIXED_MIME) {
+            /* end Q encoding */
+            input_mode = exit_mode;
+           lwsp_count = 0;
+           lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
+           if (lwsp_buf==NULL) {
+               perror("can't malloc");
+               return -1;
+           }
+           while ((c1=(*i_getc)(f))!=EOF) {
+               switch (c1) {
+               case LF:
+               case CR:
+                   if (c1==LF) {
+                       if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
+                           i_ungetc(SP,f);
+                           continue;
+                       } else {
+                           i_ungetc(c1,f);
+                       }
+                       c1 = LF;
+                   } else {
+                       if ((c1=(*i_getc)(f))!=EOF && c1 == LF) {
+                           if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
+                               i_ungetc(SP,f);
+                               continue;
+                           } else {
+                               i_ungetc(c1,f);
+                           }
+                           i_ungetc(LF,f);
+                       } else {
+                           i_ungetc(c1,f);
+                       }
+                       c1 = CR;
+                   }
+                   break;
+               case SP:
+               case TAB:
+                   lwsp_buf[lwsp_count] = (unsigned char)c1;
+                   if (lwsp_count++>lwsp_size){
+                       lwsp_size <<= 1;
+                       lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
+                       if (lwsp_buf_new==NULL) {
+                           free(lwsp_buf);
+                           perror("can't realloc");
+                           return -1;
+                       }
+                       lwsp_buf = lwsp_buf_new;
+                   }
+                   continue;
+               }
+               break;
+           }
+           if (lwsp_count > 0 && (c1 != '=' || (lwsp_buf[lwsp_count-1] != SP && lwsp_buf[lwsp_count-1] != TAB))) {
+               i_ungetc(c1,f);
+               for(lwsp_count--;lwsp_count>0;lwsp_count--)
+                   i_ungetc(lwsp_buf[lwsp_count],f);
+               c1 = lwsp_buf[0];
+           }
+           free(lwsp_buf);
+            return c1;
+        }
+        if (c1=='='&&c2<SP) { /* this is soft wrap */
+            while((c1 =  (*i_mgetc)(f)) <=SP) {
+               if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
+           }
+            mime_decode_mode = 'Q'; /* still in MIME */
+           goto restart_mime_q;
        }
+        if (c1=='?') {
+            mime_decode_mode = 'Q'; /* still in MIME */
+            (*i_mungetc)(c2,f);
+            return c1;
+        }
+        if ((c3 = (*i_mgetc)(f)) == EOF) return (EOF);
+        if (c2<=SP) return c2;
+        mime_decode_mode = 'Q'; /* still in MIME */
+        return ((hex2bin(c2)<<4) + hex2bin(c3));
     }
-    return input_codename;
-}
 
-#if !defined(PERL_XS) && !defined(WIN32DLL)
-void print_guessed_code(char *filename)
-{
-    if (filename != NULL) printf("%s: ", filename);
-    if (input_codename && !*input_codename) {
-       printf("BINARY\n");
-    } else {
-       input_codename = get_guessed_code();
-       if (guess_f == 1) {
-           printf("%s\n", input_codename);
-       } else {
-           printf("%s%s\n",
-                  input_codename,
-                  input_newline == CR   ? " (CR)" :
-                  input_newline == LF   ? " (LF)" :
-                  input_newline == CRLF ? " (CRLF)" :
-                  input_newline == EOF  ? " (MIXED NL)" :
-                  "");
+    if (mime_decode_mode != 'B') {
+        mime_decode_mode = FALSE;
+        return (*i_mgetc)(f);
+    }
+
+
+    /* Base64 encoding */
+    /*
+        MIME allows line break in the middle of
+        Base64, but we are very pessimistic in decoding
+        in unbuf mode because MIME encoded code may broken by
+        less or editor's control sequence (such as ESC-[-K in unbuffered
+        mode. ignore incomplete MIME.
+    */
+    mode = mime_decode_mode;
+    mime_decode_mode = exit_mode;  /* prepare for quit */
+
+    while ((c1 = (*i_mgetc)(f))<=SP) {
+        if (c1==EOF)
+            return (EOF);
+    }
+mime_c2_retry:
+    if ((c2 = (*i_mgetc)(f))<=SP) {
+        if (c2==EOF)
+            return (EOF);
+       if (mime_f != STRICT_MIME) goto mime_c2_retry;
+        if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;
+        return c2;
+    }
+    if ((c1 == '?') && (c2 == '=')) {
+        input_mode = ASCII;
+       lwsp_count = 0;
+       lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
+       if (lwsp_buf==NULL) {
+           perror("can't malloc");
+           return -1;
+       }
+       while ((c1=(*i_getc)(f))!=EOF) {
+           switch (c1) {
+           case LF:
+           case CR:
+               if (c1==LF) {
+                   if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
+                       i_ungetc(SP,f);
+                       continue;
+                   } else {
+                       i_ungetc(c1,f);
+                   }
+                   c1 = LF;
+               } else {
+                   if ((c1=(*i_getc)(f))!=EOF) {
+                       if (c1==SP) {
+                           i_ungetc(SP,f);
+                           continue;
+                       } else if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
+                           i_ungetc(SP,f);
+                           continue;
+                       } else {
+                           i_ungetc(c1,f);
+                       }
+                       i_ungetc(LF,f);
+                   } else {
+                       i_ungetc(c1,f);
+                   }
+                   c1 = CR;
+               }
+               break;
+           case SP:
+           case TAB:
+               lwsp_buf[lwsp_count] = (unsigned char)c1;
+               if (lwsp_count++>lwsp_size){
+                   lwsp_size <<= 1;
+                   lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
+                   if (lwsp_buf_new==NULL) {
+                       free(lwsp_buf);
+                       perror("can't realloc");
+                       return -1;
+                   }
+                   lwsp_buf = lwsp_buf_new;
+               }
+               continue;
+           }
+           break;
+       }
+       if (lwsp_count > 0 && (c1 != '=' || (lwsp_buf[lwsp_count-1] != SP && lwsp_buf[lwsp_count-1] != TAB))) {
+           i_ungetc(c1,f);
+           for(lwsp_count--;lwsp_count>0;lwsp_count--)
+               i_ungetc(lwsp_buf[lwsp_count],f);
+           c1 = lwsp_buf[0];
        }
-    }
-}
-#endif /*WIN32DLL*/
-
-#ifdef INPUT_OPTION
-
-nkf_char hex_getc(nkf_char ch, FILE *f, nkf_char (*g)(FILE *f), nkf_char (*u)(nkf_char c, FILE *f))
-{
-    nkf_char c1, c2, c3;
-    c1 = (*g)(f);
-    if (c1 != ch){
+       free(lwsp_buf);
         return c1;
     }
-    c2 = (*g)(f);
-    if (!nkf_isxdigit(c2)){
-        (*u)(c2, f);
-        return c1;
+mime_c3_retry:
+    if ((c3 = (*i_mgetc)(f))<=SP) {
+        if (c3==EOF)
+            return (EOF);
+       if (mime_f != STRICT_MIME) goto mime_c3_retry;
+        if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;
+        return c3;
     }
-    c3 = (*g)(f);
-    if (!nkf_isxdigit(c3)){
-        (*u)(c2, f);
-        (*u)(c3, f);
+mime_c4_retry:
+    if ((c4 = (*i_mgetc)(f))<=SP) {
+        if (c4==EOF)
+            return (EOF);
+       if (mime_f != STRICT_MIME) goto mime_c4_retry;
+        if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;
+        return c4;
+    }
+
+    mime_decode_mode = mode; /* still in MIME sigh... */
+
+    /* BASE 64 decoding */
+
+    t1 = 0x3f & base64decode(c1);
+    t2 = 0x3f & base64decode(c2);
+    t3 = 0x3f & base64decode(c3);
+    t4 = 0x3f & base64decode(c4);
+    cc = ((t1 << 2) & 0x0fc) | ((t2 >> 4) & 0x03);
+    if (c2 != '=') {
+        mime_input_buf(mime_input_state.last++) = (unsigned char)cc;
+        cc = ((t2 << 4) & 0x0f0) | ((t3 >> 2) & 0x0f);
+        if (c3 != '=') {
+            mime_input_buf(mime_input_state.last++) = (unsigned char)cc;
+            cc = ((t3 << 6) & 0x0c0) | (t4 & 0x3f);
+            if (c4 != '=')
+                mime_input_buf(mime_input_state.last++) = (unsigned char)cc;
+        }
+    } else {
         return c1;
     }
-    return (hex2bin(c2) << 4) | hex2bin(c3);
+    return  mime_input_buf(mime_input_state.top++);
 }
 
-nkf_char cap_getc(FILE *f)
-{
-    return hex_getc(':', f, i_cgetc, i_cungetc);
-}
+static const char basis_64[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
-nkf_char cap_ungetc(nkf_char c, FILE *f)
-{
-    return (*i_cungetc)(c, f);
-}
+#define MIMEOUT_BUF_LENGTH (60)
+static struct {
+    char buf[MIMEOUT_BUF_LENGTH+1];
+    int count;
+    nkf_char state;
+} mimeout_state;
 
-nkf_char url_getc(FILE *f)
-{
-    return hex_getc('%', f, i_ugetc, i_uungetc);
-}
+/*nkf_char mime_lastchar2, mime_lastchar1;*/
 
-nkf_char url_ungetc(nkf_char c, FILE *f)
+static void open_mime(nkf_char mode)
 {
-    return (*i_uungetc)(c, f);
+    const unsigned char *p;
+    int i;
+    int j;
+    p  = mime_pattern[0];
+    for(i=0;mime_pattern[i];i++) {
+       if (mode == mime_encode[i]) {
+           p = mime_pattern[i];
+           break;
+       }
+    }
+    mimeout_mode = mime_encode_method[i];
+    i = 0;
+    if (base64_count>45) {
+       if (mimeout_state.count>0 && nkf_isblank(mimeout_state.buf[i])){
+            (*o_mputc)(mimeout_state.buf[i]);
+           i++;
+       }
+       PUT_NEWLINE((*o_mputc));
+       (*o_mputc)(SP);
+       base64_count = 1;
+       if (mimeout_state.count>0
+           && (mimeout_state.buf[i]==SP || mimeout_state.buf[i]==TAB
+               || mimeout_state.buf[i]==CR || mimeout_state.buf[i]==LF)) {
+           i++;
+       }
+    }
+    for (;i<mimeout_state.count;i++) {
+       if (mimeout_state.buf[i]==SP || mimeout_state.buf[i]==TAB
+           || mimeout_state.buf[i]==CR || mimeout_state.buf[i]==LF) {
+           (*o_mputc)(mimeout_state.buf[i]);
+           base64_count ++;
+       } else {
+           break;
+       }
+    }
+    while(*p) {
+        (*o_mputc)(*p++);
+        base64_count ++;
+    }
+    j = mimeout_state.count;
+    mimeout_state.count = 0;
+    for (;i<j;i++) {
+       mime_putc(mimeout_state.buf[i]);
+    }
 }
-#endif
 
-#ifdef NUMCHAR_OPTION
-nkf_char numchar_getc(FILE *f)
+static void mime_prechar(nkf_char c2, nkf_char c1)
 {
-    nkf_char (*g)(FILE *) = i_ngetc;
-    nkf_char (*u)(nkf_char c ,FILE *f) = i_nungetc;
-    int i = 0, j;
-    nkf_char buf[8];
-    long c = -1;
-
-    buf[i] = (*g)(f);
-    if (buf[i] == '&'){
-        buf[++i] = (*g)(f);
-        if (buf[i] == '#'){
-            c = 0;
-            buf[++i] = (*g)(f);
-            if (buf[i] == 'x' || buf[i] == 'X'){
-                for (j = 0; j < 7; j++){
-                    buf[++i] = (*g)(f);
-                    if (!nkf_isxdigit(buf[i])){
-                        if (buf[i] != ';'){
-                            c = -1;
-                        }
-                        break;
-                    }
-                    c <<= 4;
-                    c |= hex2bin(buf[i]);
-                }
-            }else{
-                for (j = 0; j < 8; j++){
-                    if (j){
-                        buf[++i] = (*g)(f);
-                    }
-                    if (!nkf_isdigit(buf[i])){
-                        if (buf[i] != ';'){
-                            c = -1;
-                        }
-                        break;
-                    }
-                    c *= 10;
-                    c += hex2bin(buf[i]);
-                }
+    if (mimeout_mode > 0){
+        if (c2 == EOF){
+            if (base64_count + mimeout_state.count/3*4> 73){
+                (*o_base64conv)(EOF,0);
+                OCONV_NEWLINE((*o_base64conv));
+                (*o_base64conv)(0,SP);
+                base64_count = 1;
+            }
+        } else {
+            if (base64_count + mimeout_state.count/3*4> 66) {
+                (*o_base64conv)(EOF,0);
+                OCONV_NEWLINE((*o_base64conv));
+                (*o_base64conv)(0,SP);
+                base64_count = 1;
+                mimeout_mode = -1;
             }
         }
+    } else if (c2) {
+       if (c2 != EOF && base64_count + mimeout_state.count/3*4> 60) {
+           mimeout_mode =  (output_mode==ASCII ||output_mode == ISO_8859_1) ? 'Q' : 'B';
+           open_mime(output_mode);
+           (*o_base64conv)(EOF,0);
+           OCONV_NEWLINE((*o_base64conv));
+           (*o_base64conv)(0,SP);
+           base64_count = 1;
+           mimeout_mode = -1;
+       }
     }
-    if (c != -1){
-        return CLASS_UNICODE | c;
-    }
-    while (i > 0){
-        (*u)(buf[i], f);
-        --i;
-    }
-    return buf[0];
 }
 
-nkf_char numchar_ungetc(nkf_char c, FILE *f)
+static void close_mime(void)
 {
-    return (*i_nungetc)(c, f);
+    (*o_mputc)('?');
+    (*o_mputc)('=');
+    base64_count += 2;
+    mimeout_mode = 0;
 }
-#endif
 
-#ifdef UNICODE_NORMALIZATION
-
-/* Normalization Form C */
-nkf_char nfc_getc(FILE *f)
+static void eof_mime(void)
 {
-    nkf_char (*g)(FILE *f) = i_nfc_getc;
-    nkf_char (*u)(nkf_char c ,FILE *f) = i_nfc_ungetc;
-    int i=0, j, k=1, lower, upper;
-    nkf_char buf[9];
-    const unsigned char *array;
+    switch(mimeout_mode) {
+    case 'Q':
+    case 'B':
+       break;
+    case 2:
+       (*o_mputc)(basis_64[((mimeout_state.state & 0x3)<< 4)]);
+       (*o_mputc)('=');
+       (*o_mputc)('=');
+       base64_count += 3;
+       break;
+    case 1:
+       (*o_mputc)(basis_64[((mimeout_state.state & 0xF) << 2)]);
+       (*o_mputc)('=');
+       base64_count += 2;
+       break;
+    }
+    if (mimeout_mode > 0) {
+       if (mimeout_f!=FIXED_MIME) {
+           close_mime();
+       } else if (mimeout_mode != 'Q')
+           mimeout_mode = 'B';
+    }
+}
 
-    buf[i] = (*g)(f);
-    while (k > 0 && ((buf[i] & 0xc0) != 0x80)){
-       lower=0, upper=NORMALIZATION_TABLE_LENGTH-1;
-       while (upper >= lower) {
-           j = (lower+upper) / 2;
-           array = normalization_table[j].nfd;
-           for (k=0; k < NORMALIZATION_TABLE_NFD_LENGTH && array[k]; k++){
-               if (array[k] != buf[k]){
-                   array[k] < buf[k] ? (lower = j + 1) : (upper = j - 1);
-                   k = 0;
-                   break;
-               } else if (k >= i)
-                   buf[++i] = (*g)(f);
-           }
-           if (k > 0){
-               array = normalization_table[j].nfc;
-               for (i=0; i < NORMALIZATION_TABLE_NFC_LENGTH && array[i]; i++)
-                   buf[i] = (nkf_char)(array[i]);
-               i--;
-               break;
-           }
+static void mimeout_addchar(nkf_char c)
+{
+    switch(mimeout_mode) {
+    case 'Q':
+       if (c==CR||c==LF) {
+           (*o_mputc)(c);
+           base64_count = 0;
+       } else if(!nkf_isalnum(c)) {
+           (*o_mputc)('=');
+           (*o_mputc)(bin2hex(((c>>4)&0xf)));
+           (*o_mputc)(bin2hex((c&0xf)));
+           base64_count += 3;
+       } else {
+           (*o_mputc)(c);
+           base64_count++;
        }
-       while (i > 0)
-           (*u)(buf[i--], f);
+        break;
+    case 'B':
+        mimeout_state.state=c;
+        (*o_mputc)(basis_64[c>>2]);
+        mimeout_mode=2;
+        base64_count ++;
+        break;
+    case 2:
+        (*o_mputc)(basis_64[((mimeout_state.state & 0x3)<< 4) | ((c & 0xF0) >> 4)]);
+        mimeout_state.state=c;
+        mimeout_mode=1;
+        base64_count ++;
+        break;
+    case 1:
+        (*o_mputc)(basis_64[((mimeout_state.state & 0xF) << 2) | ((c & 0xC0) >>6)]);
+        (*o_mputc)(basis_64[c & 0x3F]);
+        mimeout_mode='B';
+        base64_count += 2;
+        break;
+    default:
+       (*o_mputc)(c);
+       base64_count++;
+        break;
     }
-    return buf[0];
 }
 
-nkf_char nfc_ungetc(nkf_char c, FILE *f)
+static void mime_putc(nkf_char c)
 {
-    return (*i_nfc_ungetc)(c, f);
-}
-#endif /* UNICODE_NORMALIZATION */
+    int i, j;
+    nkf_char lastchar;
 
+    if (mimeout_f == FIXED_MIME){
+        if (mimeout_mode == 'Q'){
+            if (base64_count > 71){
+                if (c!=CR && c!=LF) {
+                    (*o_mputc)('=');
+                    PUT_NEWLINE((*o_mputc));
+                }
+                base64_count = 0;
+            }
+        }else{
+            if (base64_count > 71){
+                eof_mime();
+                PUT_NEWLINE((*o_mputc));
+                base64_count = 0;
+            }
+            if (c == EOF) { /* c==EOF */
+                eof_mime();
+            }
+        }
+        if (c != EOF) { /* c==EOF */
+            mimeout_addchar(c);
+        }
+        return;
+    }
 
-nkf_char
-mime_getc(FILE *f)
-{
-    nkf_char c1, c2, c3, c4, cc;
-    nkf_char t1, t2, t3, t4, mode, exit_mode;
-    nkf_char lwsp_count;
-    char *lwsp_buf;
-    char *lwsp_buf_new;
-    nkf_char lwsp_size = 128;
+    /* mimeout_f != FIXED_MIME */
 
-    if (mime_top != mime_last) {  /* Something is in FIFO */
-        return  Fifo(mime_top++);
-    }
-    if (mime_decode_mode==1 ||mime_decode_mode==FALSE) {
-       mime_decode_mode=FALSE;
-       unswitch_mime_getc();
-       return (*i_getc)(f);
+    if (c == EOF) { /* c==EOF */
+       if (mimeout_mode == -1 && mimeout_state.count > 1) open_mime(output_mode);
+       j = mimeout_state.count;
+       mimeout_state.count = 0;
+       i = 0;
+       if (mimeout_mode > 0) {
+           if (!nkf_isblank(mimeout_state.buf[j-1])) {
+               for (;i<j;i++) {
+                   if (nkf_isspace(mimeout_state.buf[i]) && base64_count < 71){
+                       break;
+                   }
+                   mimeout_addchar(mimeout_state.buf[i]);
+               }
+               eof_mime();
+               for (;i<j;i++) {
+                   mimeout_addchar(mimeout_state.buf[i]);
+               }
+           } else {
+               for (;i<j;i++) {
+                   mimeout_addchar(mimeout_state.buf[i]);
+               }
+               eof_mime();
+           }
+       } else {
+           for (;i<j;i++) {
+               mimeout_addchar(mimeout_state.buf[i]);
+           }
+       }
+        return;
     }
 
-    if (mimebuf_f == FIXED_MIME)
-        exit_mode = mime_decode_mode;
-    else
-        exit_mode = FALSE;
-    if (mime_decode_mode == 'Q') {
-        if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
-restart_mime_q:
-        if (c1=='_' && mimebuf_f != FIXED_MIME) return SP;
-       if (c1<=SP || DEL<=c1) {
-           mime_decode_mode = exit_mode; /* prepare for quit */
-           return c1;
-       }
-        if (c1!='=' && (c1!='?' || mimebuf_f == FIXED_MIME)) {
-           return c1;
-       }
+    if (mimeout_state.count > 0){
+        lastchar = mimeout_state.buf[mimeout_state.count - 1];
+    }else{
+        lastchar = -1;
+    }
 
-        mime_decode_mode = exit_mode; /* prepare for quit */
-        if ((c2 = (*i_mgetc)(f)) == EOF) return (EOF);
-        if (c1=='?'&&c2=='=' && mimebuf_f != FIXED_MIME) {
-            /* end Q encoding */
-            input_mode = exit_mode;
-           lwsp_count = 0;
-           lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
-           if (lwsp_buf==NULL) {
-               perror("can't malloc");
-               return -1;
+    if (mimeout_mode=='Q') {
+        if (c <= DEL && (output_mode==ASCII ||output_mode == ISO_8859_1)) {
+           if (c == CR || c == LF) {
+               close_mime();
+               (*o_mputc)(c);
+               base64_count = 0;
+               return;
+            } else if (c <= SP) {
+                close_mime();
+               if (base64_count > 70) {
+                   PUT_NEWLINE((*o_mputc));
+                   base64_count = 0;
+               }
+               if (!nkf_isblank(c)) {
+                   (*o_mputc)(SP);
+                   base64_count++;
+               }
+            } else {
+               if (base64_count > 70) {
+                   close_mime();
+                   PUT_NEWLINE((*o_mputc));
+                   (*o_mputc)(SP);
+                   base64_count = 1;
+                   open_mime(output_mode);
+               }
+               if (!nkf_noescape_mime(c)) {
+                   mimeout_addchar(c);
+                   return;
+               }
            }
-           while ((c1=(*i_getc)(f))!=EOF) {
-               switch (c1) {
-               case LF:
-               case CR:
-                   if (c1==LF) {
-                       if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
-                           i_ungetc(SP,f);
-                           continue;
-                       } else {
-                           i_ungetc(c1,f);
-                       }
-                       c1 = LF;
+           (*o_mputc)(c);
+           base64_count++;
+        }
+        return;
+    }
+
+    if (mimeout_mode <= 0) {
+        if (c <= DEL && (output_mode==ASCII ||output_mode == ISO_8859_1)) {
+            if (nkf_isspace(c)) {
+               int flag = 0;
+               if (mimeout_mode == -1) {
+                   flag = 1;
+               }
+                if (c==CR || c==LF) {
+                   if (flag) {
+                       open_mime(output_mode);
+                       output_mode = 0;
                    } else {
-                       if ((c1=(*i_getc)(f))!=EOF && c1 == LF) {
-                           if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
-                               i_ungetc(SP,f);
-                               continue;
-                           } else {
-                               i_ungetc(c1,f);
-                           }
-                           i_ungetc(LF,f);
-                       } else {
-                           i_ungetc(c1,f);
-                       }
-                       c1 = CR;
-                   }
-                   break;
-               case SP:
-               case TAB:
-                   lwsp_buf[lwsp_count] = (unsigned char)c1;
-                   if (lwsp_count++>lwsp_size){
-                       lwsp_size <<= 1;
-                       lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
-                       if (lwsp_buf_new==NULL) {
-                           free(lwsp_buf);
-                           perror("can't realloc");
-                           return -1;
-                       }
-                       lwsp_buf = lwsp_buf_new;
+                       base64_count = 0;
                    }
-                   continue;
-               }
-               break;
-           }
-           if (lwsp_count > 0 && (c1 != '=' || (lwsp_buf[lwsp_count-1] != SP && lwsp_buf[lwsp_count-1] != TAB))) {
-               i_ungetc(c1,f);
-               for(lwsp_count--;lwsp_count>0;lwsp_count--)
-                   i_ungetc(lwsp_buf[lwsp_count],f);
-               c1 = lwsp_buf[0];
+                }
+                for (i=0;i<mimeout_state.count;i++) {
+                    (*o_mputc)(mimeout_state.buf[i]);
+                    if (mimeout_state.buf[i] == CR || mimeout_state.buf[i] == LF){
+                        base64_count = 0;
+                    }else{
+                        base64_count++;
+                    }
+                }
+               if (flag) {
+                   eof_mime();
+                   base64_count = 0;
+                   mimeout_mode = 0;
+                }
+               mimeout_state.buf[0] = (char)c;
+               mimeout_state.count = 1;
+            }else{
+                if (base64_count > 1
+                    && base64_count + mimeout_state.count > 76
+                   && mimeout_state.buf[0] != CR && mimeout_state.buf[0] != LF){
+                    PUT_NEWLINE((*o_mputc));
+                    base64_count = 0;
+                    if (!nkf_isspace(mimeout_state.buf[0])){
+                        (*o_mputc)(SP);
+                        base64_count++;
+                    }
+                }
+                mimeout_state.buf[mimeout_state.count++] = (char)c;
+                if (mimeout_state.count>MIMEOUT_BUF_LENGTH) {
+                    open_mime(output_mode);
+                }
+            }
+            return;
+        }else{
+            if (lastchar==CR || lastchar == LF){
+                for (i=0;i<mimeout_state.count;i++) {
+                    (*o_mputc)(mimeout_state.buf[i]);
+                }
+                base64_count = 0;
+                mimeout_state.count = 0;
+            }
+            if (lastchar==SP) {
+                for (i=0;i<mimeout_state.count-1;i++) {
+                    (*o_mputc)(mimeout_state.buf[i]);
+                    base64_count++;
+                }
+                mimeout_state.buf[0] = SP;
+                mimeout_state.count = 1;
+            }
+            open_mime(output_mode);
+        }
+    }else{
+        /* mimeout_mode == 'B', 1, 2 */
+        if ( c<=DEL && (output_mode==ASCII ||output_mode == ISO_8859_1)) {
+            if (lastchar == CR || lastchar == LF){
+                if (nkf_isblank(c)) {
+                    for (i=0;i<mimeout_state.count;i++) {
+                        mimeout_addchar(mimeout_state.buf[i]);
+                    }
+                    mimeout_state.count = 0;
+                } else if (SP<c && c<DEL) {
+                    eof_mime();
+                    for (i=0;i<mimeout_state.count;i++) {
+                        (*o_mputc)(mimeout_state.buf[i]);
+                    }
+                    base64_count = 0;
+                    mimeout_state.count = 0;
+                }
+                mimeout_state.buf[mimeout_state.count++] = (char)c;
+               return;
+            }
+            if (c==SP || c==TAB || c==CR || c==LF) {
+                for (i=0;i<mimeout_state.count;i++) {
+                    if (SP<mimeout_state.buf[i] && mimeout_state.buf[i]<DEL) {
+                        eof_mime();
+                        for (i=0;i<mimeout_state.count;i++) {
+                            (*o_mputc)(mimeout_state.buf[i]);
+                            base64_count++;
+                        }
+                        mimeout_state.count = 0;
+                    }
+                }
+                mimeout_state.buf[mimeout_state.count++] = (char)c;
+                if (mimeout_state.count>MIMEOUT_BUF_LENGTH) {
+                    eof_mime();
+                    for (i=0;i<mimeout_state.count;i++) {
+                        (*o_mputc)(mimeout_state.buf[i]);
+                        base64_count++;
+                    }
+                    mimeout_state.count = 0;
+                }
+                return;
            }
-           free(lwsp_buf);
-            return c1;
+            if (mimeout_state.count>0 && SP<c && c!='=') {
+                mimeout_state.buf[mimeout_state.count++] = (char)c;
+                if (mimeout_state.count>MIMEOUT_BUF_LENGTH) {
+                    j = mimeout_state.count;
+                    mimeout_state.count = 0;
+                    for (i=0;i<j;i++) {
+                        mimeout_addchar(mimeout_state.buf[i]);
+                    }
+                }
+                return;
+            }
         }
-        if (c1=='='&&c2<SP) { /* this is soft wrap */
-            while((c1 =  (*i_mgetc)(f)) <=SP) {
-               if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
+    }
+    if (mimeout_state.count>0) {
+       j = mimeout_state.count;
+       mimeout_state.count = 0;
+       for (i=0;i<j;i++) {
+           if (mimeout_state.buf[i]==CR || mimeout_state.buf[i]==LF)
+               break;
+           mimeout_addchar(mimeout_state.buf[i]);
+       }
+       if (i<j) {
+           eof_mime();
+           base64_count=0;
+           for (;i<j;i++) {
+               (*o_mputc)(mimeout_state.buf[i]);
            }
-            mime_decode_mode = 'Q'; /* still in MIME */
-           goto restart_mime_q;
+           open_mime(output_mode);
        }
-        if (c1=='?') {
-            mime_decode_mode = 'Q'; /* still in MIME */
-            (*i_mungetc)(c2,f);
-            return c1;
-        }
-        if ((c3 = (*i_mgetc)(f)) == EOF) return (EOF);
-        if (c2<=SP) return c2;
-        mime_decode_mode = 'Q'; /* still in MIME */
-        return ((hex2bin(c2)<<4) + hex2bin(c3));
     }
+    mimeout_addchar(c);
+}
 
-    if (mime_decode_mode != 'B') {
-        mime_decode_mode = FALSE;
-        return (*i_mgetc)(f);
-    }
+void base64_conv(nkf_char c2, nkf_char c1)
+{
+    mime_prechar(c2, c1);
+    (*o_base64conv)(c2,c1);
+}
 
+#ifdef HAVE_ICONV_H
+typedef struct nkf_iconv_t {
+    iconv_t cd;
+    char *input_buffer;
+    size_t input_buffer_size;
+    char *output_buffer;
+    size_t output_buffer_size;
+}
 
-    /* Base64 encoding */
-    /*
-        MIME allows line break in the middle of
-        Base64, but we are very pessimistic in decoding
-        in unbuf mode because MIME encoded code may broken by
-        less or editor's control sequence (such as ESC-[-K in unbuffered
-        mode. ignore incomplete MIME.
-    */
-    mode = mime_decode_mode;
-    mime_decode_mode = exit_mode;  /* prepare for quit */
+nkf_iconv_t nkf_iconv_new(char *tocode, char *fromcode)
+{
+    nkf_iconv_t converter;
 
-    while ((c1 = (*i_mgetc)(f))<=SP) {
-        if (c1==EOF)
-            return (EOF);
-    }
-mime_c2_retry:
-    if ((c2 = (*i_mgetc)(f))<=SP) {
-        if (c2==EOF)
-            return (EOF);
-       if (mime_f != STRICT_MIME) goto mime_c2_retry;
-        if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;
-        return c2;
-    }
-    if ((c1 == '?') && (c2 == '=')) {
-        input_mode = ASCII;
-       lwsp_count = 0;
-       lwsp_buf = malloc((lwsp_size+5)*sizeof(char));
-       if (lwsp_buf==NULL) {
-           perror("can't malloc");
-           return -1;
-       }
-       while ((c1=(*i_getc)(f))!=EOF) {
-           switch (c1) {
-           case LF:
-           case CR:
-               if (c1==LF) {
-                   if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
-                       i_ungetc(SP,f);
-                       continue;
-                   } else {
-                       i_ungetc(c1,f);
-                   }
-                   c1 = LF;
-               } else {
-                   if ((c1=(*i_getc)(f))!=EOF) {
-                       if (c1==SP) {
-                           i_ungetc(SP,f);
-                           continue;
-                       } else if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
-                           i_ungetc(SP,f);
-                           continue;
-                       } else {
-                           i_ungetc(c1,f);
-                       }
-                       i_ungetc(LF,f);
-                   } else {
-                       i_ungetc(c1,f);
-                   }
-                   c1 = CR;
-               }
-               break;
-           case SP:
-           case TAB:
-               lwsp_buf[lwsp_count] = (unsigned char)c1;
-               if (lwsp_count++>lwsp_size){
-                   lwsp_size <<= 1;
-                   lwsp_buf_new = realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
-                   if (lwsp_buf_new==NULL) {
-                       free(lwsp_buf);
-                       perror("can't realloc");
-                       return -1;
-                   }
-                   lwsp_buf = lwsp_buf_new;
-               }
-               continue;
-           }
-           break;
-       }
-       if (lwsp_count > 0 && (c1 != '=' || (lwsp_buf[lwsp_count-1] != SP && lwsp_buf[lwsp_count-1] != TAB))) {
-           i_ungetc(c1,f);
-           for(lwsp_count--;lwsp_count>0;lwsp_count--)
-               i_ungetc(lwsp_buf[lwsp_count],f);
-           c1 = lwsp_buf[0];
-       }
-       free(lwsp_buf);
-        return c1;
-    }
-mime_c3_retry:
-    if ((c3 = (*i_mgetc)(f))<=SP) {
-        if (c3==EOF)
-            return (EOF);
-       if (mime_f != STRICT_MIME) goto mime_c3_retry;
-        if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;
-        return c3;
-    }
-mime_c4_retry:
-    if ((c4 = (*i_mgetc)(f))<=SP) {
-        if (c4==EOF)
-            return (EOF);
-       if (mime_f != STRICT_MIME) goto mime_c4_retry;
-        if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;
-        return c4;
+    converter->input_buffer_size = IOBUF_SIZE;
+    converter->input_buffer = malloc(converter->input_buffer_size);
+    if (converter->input_buffer == NULL)
+        perror("can't malloc");
+
+    converter->output_buffer_size = IOBUF_SIZE * 2;
+    converter->output_buffer = malloc(converter->output_buffer_size);
+    if (converter->output_buffer == NULL)
+        perror("can't malloc");
+
+    converter->cd = iconv_open(tocode, fromcode);
+    if (converter->cd == (iconv_t)-1)
+    {
+        switch (errno) {
+        case EINVAL:
+            perror(fprintf("iconv doesn't support %s to %s conversion.", fromcode, tocode));
+            return -1;
+        default:
+            perror("can't iconv_open");
+        }
     }
+}
 
-    mime_decode_mode = mode; /* still in MIME sigh... */
+size_t nkf_iconv_convert(nkf_iconv_t *converter, FILE *input)
+{
+    size_t invalid = (size_t)0;
+    char *input_buffer = converter->input_buffer;
+    size_t input_length = (size_t)0;
+    char *output_buffer = converter->output_buffer;
+    size_t output_length = converter->output_buffer_size;
+    int c;
 
-    /* BASE 64 decoding */
+    do {
+        if (c != EOF) {
+            while ((c = (*i_getc)(f)) != EOF) {
+                input_buffer[input_length++] = c;
+                if (input_length < converter->input_buffer_size) break;
+            }
+        }
 
-    t1 = 0x3f & base64decode(c1);
-    t2 = 0x3f & base64decode(c2);
-    t3 = 0x3f & base64decode(c3);
-    t4 = 0x3f & base64decode(c4);
-    cc = ((t1 << 2) & 0x0fc) | ((t2 >> 4) & 0x03);
-    if (c2 != '=') {
-        Fifo(mime_last++) = (unsigned char)cc;
-        cc = ((t2 << 4) & 0x0f0) | ((t3 >> 2) & 0x0f);
-        if (c3 != '=') {
-            Fifo(mime_last++) = (unsigned char)cc;
-            cc = ((t3 << 6) & 0x0c0) | (t4 & 0x3f);
-            if (c4 != '=')
-                Fifo(mime_last++) = (unsigned char)cc;
+        size_t ret = iconv(converter->cd, &input_buffer, &input_length, &output_buffer, &output_length);
+        while (output_length-- > 0) {
+            (*o_putc)(output_buffer[converter->output_buffer_size-output_length]);
+        }
+        if (ret == (size_t) - 1) {
+            switch (errno) {
+            case EINVAL:
+                if (input_buffer != converter->input_buffer)
+                    memmove(converter->input_buffer, input_buffer, input_length);
+                break;
+            case E2BIG:
+                converter->output_buffer_size *= 2;
+                output_buffer = realloc(converter->outbuf, converter->output_buffer_size);
+                if (output_buffer == NULL) {
+                    perror("can't realloc");
+                    return -1;
+                }
+                converter->output_buffer = output_buffer;
+                break;
+            default:
+                perror("can't iconv");
+                return -1;
+            }
+        } else {
+            invalid += ret;
+        }
+    } while (1);
+
+    return invalid;
+}
+
+
+void nkf_iconv_close(nkf_iconv_t *convert)
+{
+        free(converter->inbuf);
+        free(converter->outbuf);
+        iconv_close(converter->cd);
+}
+#endif
+
+
+void reinit(void)
+{
+    {
+        struct input_code *p = input_code_list;
+        while (p->name){
+            status_reinit(p++);
+        }
+    }
+    unbuf_f = FALSE;
+    estab_f = FALSE;
+    nop_f = FALSE;
+    binmode_f = TRUE;
+    rot_f = FALSE;
+    hira_f = FALSE;
+    alpha_f = FALSE;
+    mime_f = MIME_DECODE_DEFAULT;
+    mime_decode_f = FALSE;
+    mimebuf_f = FALSE;
+    broken_f = FALSE;
+    iso8859_f = FALSE;
+    mimeout_f = FALSE;
+    x0201_f = X0201_DEFAULT;
+    iso2022jp_f = FALSE;
+#if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
+    ms_ucs_map_f = UCS_MAP_ASCII;
+#endif
+#ifdef UTF8_INPUT_ENABLE
+    no_cp932ext_f = FALSE;
+    no_best_fit_chars_f = FALSE;
+    encode_fallback = NULL;
+    unicode_subchar  = '?';
+    input_endian = ENDIAN_BIG;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+    output_bom_f = FALSE;
+    output_endian = ENDIAN_BIG;
+#endif
+#ifdef UNICODE_NORMALIZATION
+    nfc_f = FALSE;
+#endif
+#ifdef INPUT_OPTION
+    cap_f = FALSE;
+    url_f = FALSE;
+    numchar_f = FALSE;
+#endif
+#ifdef CHECK_OPTION
+    noout_f = FALSE;
+    debug_f = FALSE;
+#endif
+    guess_f = 0;
+#ifdef EXEC_IO
+    exec_f = 0;
+#endif
+#ifdef SHIFTJIS_CP932
+    cp51932_f = TRUE;
+    cp932inv_f = TRUE;
+#endif
+#ifdef X0212_ENABLE
+    x0212_f = FALSE;
+    x0213_f = FALSE;
+#endif
+    {
+        int i;
+        for (i = 0; i < 256; i++){
+            prefix_table[i] = 0;
         }
-    } else {
-        return c1;
     }
-    return  Fifo(mime_top++);
+    hold_count = 0;
+    mimeout_state.count = 0;
+    mimeout_mode = 0;
+    base64_count = 0;
+    f_line = 0;
+    f_prev = 0;
+    fold_preserve_f = FALSE;
+    fold_f = FALSE;
+    fold_len = 0;
+    kanji_intro = DEFAULT_J;
+    ascii_intro = DEFAULT_R;
+    fold_margin  = FOLD_MARGIN;
+    o_zconv = no_connection;
+    o_fconv = no_connection;
+    o_eol_conv = no_connection;
+    o_rot_conv = no_connection;
+    o_hira_conv = no_connection;
+    o_base64conv = no_connection;
+    o_iso2022jp_check_conv = no_connection;
+    o_putc = std_putc;
+    i_getc = std_getc;
+    i_ungetc = std_ungetc;
+    i_bgetc = std_getc;
+    i_bungetc = std_ungetc;
+    o_mputc = std_putc;
+    i_mgetc = std_getc;
+    i_mungetc  = std_ungetc;
+    i_mgetc_buf = std_getc;
+    i_mungetc_buf = std_ungetc;
+    output_mode = ASCII;
+    input_mode =  ASCII;
+    shift_mode =  FALSE;
+    mime_decode_mode = FALSE;
+    file_out_f = FALSE;
+    eolmode_f = 0;
+    input_eol = 0;
+    prev_cr = 0;
+    option_mode = 0;
+    init_broken_state();
+    z_prev2=0,z_prev1=0;
+#ifdef CHECK_OPTION
+    iconv_for_check = 0;
+#endif
+    input_codename = NULL;
+    input_encoding = NULL;
+    output_encoding = NULL;
+#ifdef WIN32DLL
+    reinitdll();
+#endif /*WIN32DLL*/
 }
 
-nkf_char mime_ungetc(nkf_char c, FILE *f)
+void module_connection(void)
 {
-    Fifo(--mime_top) = (unsigned char)c;
-    return c;
-}
+    if (input_encoding) set_input_encoding(input_encoding);
+    if (!output_encoding) {
+       output_encoding = nkf_default_encoding();
+    }
+    set_output_encoding(output_encoding);
+    oconv = nkf_enc_to_oconv(output_encoding);
+    o_putc = std_putc;
 
-nkf_char mime_integrity(FILE *f, const unsigned char *p)
-{
-    nkf_char c,d;
-    unsigned int q;
-    /* In buffered mode, read until =? or NL or buffer full
-     */
-    mime_input = mime_top;
-    mime_last = mime_top;
+    /* replace continucation module, from output side */
 
-    while(*p) Fifo(mime_input++) = *p++;
-    d = 0;
-    q = mime_input;
-    while((c=(*i_getc)(f))!=EOF) {
-        if (((mime_input-mime_top)&MIME_BUF_MASK)==0) {
-           break;   /* buffer full */
-       }
-        if (c=='=' && d=='?') {
-            /* checked. skip header, start decode */
-            Fifo(mime_input++) = (unsigned char)c;
-            /* mime_last_input = mime_input; */
-            mime_input = q;
-           switch_mime_getc();
-            return 1;
-        }
-        if (!( (c=='+'||c=='/'|| c=='=' || c=='?' || is_alnum(c))))
-            break;
-        /* Should we check length mod 4? */
-        Fifo(mime_input++) = (unsigned char)c;
-        d=c;
+    /* output redicrection */
+#ifdef CHECK_OPTION
+    if (noout_f || guess_f){
+        o_putc = no_putc;
     }
-    /* In case of Incomplete MIME, no MIME decode  */
-    Fifo(mime_input++) = (unsigned char)c;
-    mime_last = mime_input;     /* point undecoded buffer */
-    mime_decode_mode = 1;              /* no decode on Fifo last in mime_getc */
-    switch_mime_getc();         /* anyway we need buffered getc */
-    return 1;
-}
-
-nkf_char base64decode(nkf_char c)
-{
-    int             i;
-    if (c > '@') {
-        if (c < '[') {
-            i = c - 'A';                        /* A..Z 0-25 */
-       } else if (c == '_') {
-           i = '?'         /* 63 */ ;          /* _  63 */
-        } else {
-            i = c - 'G'     /* - 'a' + 26 */ ;  /* a..z 26-51 */
+#endif
+    if (mimeout_f) {
+       o_mputc = o_putc;
+       o_putc = mime_putc;
+       if (mimeout_f == TRUE) {
+           o_base64conv = oconv; oconv = base64_conv;
        }
-    } else if (c > '/') {
-        i = c - '0' + '4'   /* - '0' + 52 */ ;  /* 0..9 52-61 */
-    } else if (c == '+' || c == '-') {
-        i = '>'             /* 62 */ ;          /* + and -  62 */
-    } else {
-        i = '?'             /* 63 */ ;          /* / 63 */
+       /* base64_count = 0; */
     }
-    return (i);
-}
-
-static const char basis_64[] =
-   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
-static nkf_char b64c;
-#define MIMEOUT_BUF_LENGTH (60)
-char mimeout_buf[MIMEOUT_BUF_LENGTH+1];
-int mimeout_buf_count = 0;
-
-void open_mime(nkf_char mode)
-{
-    const unsigned char *p;
-    int i;
-    int j;
-    p  = mime_pattern[0];
-    for(i=0;mime_pattern[i];i++) {
-       if (mode == mime_encode[i]) {
-           p = mime_pattern[i];
-           break;
-       }
+    if (eolmode_f || guess_f) {
+       o_eol_conv = oconv; oconv = eol_conv;
     }
-    mimeout_mode = mime_encode_method[i];
-    i = 0;
-    if (base64_count>45) {
-       if (mimeout_buf_count>0 && nkf_isblank(mimeout_buf[i])){
-            (*o_mputc)(mimeout_buf[i]);
-           i++;
-       }
-       PUT_NEWLINE((*o_mputc));
-       (*o_mputc)(SP);
-       base64_count = 1;
-       if (mimeout_buf_count>0
-           && (mimeout_buf[i]==SP || mimeout_buf[i]==TAB
-               || mimeout_buf[i]==CR || mimeout_buf[i]==LF)) {
-           i++;
-       }
+    if (rot_f) {
+       o_rot_conv = oconv; oconv = rot_conv;
     }
-    for (;i<mimeout_buf_count;i++) {
-       if (mimeout_buf[i]==SP || mimeout_buf[i]==TAB
-           || mimeout_buf[i]==CR || mimeout_buf[i]==LF) {
-           (*o_mputc)(mimeout_buf[i]);
-           base64_count ++;
-       } else {
-           break;
-       }
+    if (iso2022jp_f) {
+       o_iso2022jp_check_conv = oconv; oconv = iso2022jp_check_conv;
     }
-    while(*p) {
-        (*o_mputc)(*p++);
-        base64_count ++;
+    if (hira_f) {
+       o_hira_conv = oconv; oconv = hira_conv;
     }
-    j = mimeout_buf_count;
-    mimeout_buf_count = 0;
-    for (;i<j;i++) {
-       mime_putc(mimeout_buf[i]);
+    if (fold_f) {
+       o_fconv = oconv; oconv = fold_conv;
+       f_line = 0;
+    }
+    if (alpha_f || x0201_f) {
+       o_zconv = oconv; oconv = z_conv;
     }
-}
-
-void close_mime(void)
-{
-    (*o_mputc)('?');
-    (*o_mputc)('=');
-    base64_count += 2;
-    mimeout_mode = 0;
-}
 
-void eof_mime(void)
-{
-    switch(mimeout_mode) {
-    case 'Q':
-    case 'B':
-       break;
-    case 2:
-       (*o_mputc)(basis_64[((b64c & 0x3)<< 4)]);
-       (*o_mputc)('=');
-       (*o_mputc)('=');
-       base64_count += 3;
-       break;
-    case 1:
-       (*o_mputc)(basis_64[((b64c & 0xF) << 2)]);
-       (*o_mputc)('=');
-       base64_count += 2;
-       break;
+    i_getc = std_getc;
+    i_ungetc = std_ungetc;
+    /* input redicrection */
+#ifdef INPUT_OPTION
+    if (cap_f){
+        i_cgetc = i_getc; i_getc = cap_getc;
+        i_cungetc = i_ungetc; i_ungetc= cap_ungetc;
+    }
+    if (url_f){
+        i_ugetc = i_getc; i_getc = url_getc;
+        i_uungetc = i_ungetc; i_ungetc= url_ungetc;
+    }
+#endif
+#ifdef NUMCHAR_OPTION
+    if (numchar_f){
+        i_ngetc = i_getc; i_getc = numchar_getc;
+        i_nungetc = i_ungetc; i_ungetc= numchar_ungetc;
+    }
+#endif
+#ifdef UNICODE_NORMALIZATION
+    if (nfc_f){
+        i_nfc_getc = i_getc; i_getc = nfc_getc;
+        i_nfc_ungetc = i_ungetc; i_ungetc= nfc_ungetc;
+    }
+#endif
+    if (mime_f && mimebuf_f==FIXED_MIME) {
+       i_mgetc = i_getc; i_getc = mime_getc;
+       i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
     }
-    if (mimeout_mode > 0) {
-       if (mimeout_f!=FIXED_MIME) {
-           close_mime();
-       } else if (mimeout_mode != 'Q')
-           mimeout_mode = 'B';
+    if (broken_f & 1) {
+       i_bgetc = i_getc; i_getc = broken_getc;
+       i_bungetc = i_ungetc; i_ungetc = broken_ungetc;
+    }
+    if (input_encoding) {
+        set_iconv(-TRUE, nkf_enc_to_iconv(input_encoding));
+    } else {
+        set_iconv(FALSE, e_iconv);
     }
-}
 
-void mimeout_addchar(nkf_char c)
-{
-    switch(mimeout_mode) {
-    case 'Q':
-       if (c==CR||c==LF) {
-           (*o_mputc)(c);
-           base64_count = 0;
-       } else if(!nkf_isalnum(c)) {
-           (*o_mputc)('=');
-           (*o_mputc)(bin2hex(((c>>4)&0xf)));
-           (*o_mputc)(bin2hex((c&0xf)));
-           base64_count += 3;
-       } else {
-           (*o_mputc)(c);
-           base64_count++;
-       }
-        break;
-    case 'B':
-        b64c=c;
-        (*o_mputc)(basis_64[c>>2]);
-        mimeout_mode=2;
-        base64_count ++;
-        break;
-    case 2:
-        (*o_mputc)(basis_64[((b64c & 0x3)<< 4) | ((c & 0xF0) >> 4)]);
-        b64c=c;
-        mimeout_mode=1;
-        base64_count ++;
-        break;
-    case 1:
-        (*o_mputc)(basis_64[((b64c & 0xF) << 2) | ((c & 0xC0) >>6)]);
-        (*o_mputc)(basis_64[c & 0x3F]);
-        mimeout_mode='B';
-        base64_count += 2;
-        break;
-    default:
-       (*o_mputc)(c);
-       base64_count++;
-        break;
+    {
+        struct input_code *p = input_code_list;
+        while (p->name){
+            status_reinit(p++);
+        }
     }
 }
 
-/*nkf_char mime_lastchar2, mime_lastchar1;*/
+/*
+   Conversion main loop. Code detection only.
+ */
 
-void mime_prechar(nkf_char c2, nkf_char c1)
+#if !defined(PERL_XS) && !defined(WIN32DLL)
+nkf_char noconvert(FILE *f)
 {
-    if (mimeout_mode > 0){
-        if (c2 == EOF){
-            if (base64_count + mimeout_buf_count/3*4> 73){
-                (*o_base64conv)(EOF,0);
-                OCONV_NEWLINE((*o_base64conv));
-                (*o_base64conv)(0,SP);
-                base64_count = 1;
-            }
-        } else {
-            if (base64_count + mimeout_buf_count/3*4> 66) {
-                (*o_base64conv)(EOF,0);
-                OCONV_NEWLINE((*o_base64conv));
-                (*o_base64conv)(0,SP);
-                base64_count = 1;
-                mimeout_mode = -1;
-            }
-        }
-    } else if (c2) {
-       if (c2 != EOF && base64_count + mimeout_buf_count/3*4> 60) {
-           mimeout_mode =  (output_mode==ASCII ||output_mode == ISO_8859_1) ? 'Q' : 'B';
-           open_mime(output_mode);
-           (*o_base64conv)(EOF,0);
-           OCONV_NEWLINE((*o_base64conv));
-           (*o_base64conv)(0,SP);
-           base64_count = 1;
-           mimeout_mode = -1;
-       }
-    }
+    nkf_char    c;
+
+    if (nop_f == 2)
+       module_connection();
+    while ((c = (*i_getc)(f)) != EOF)
+      (*o_putc)(c);
+    (*o_putc)(EOF);
+    return 1;
 }
+#endif
 
-void mime_putc(nkf_char c)
+nkf_char kanji_convert(FILE *f)
 {
-    int i, j;
-    nkf_char lastchar;
+    nkf_char    c3, c2=0, c1, c0=0;
+    int is_8bit = FALSE;
 
-    if (mimeout_f == FIXED_MIME){
-        if (mimeout_mode == 'Q'){
-            if (base64_count > 71){
-                if (c!=CR && c!=LF) {
-                    (*o_mputc)('=');
-                    PUT_NEWLINE((*o_mputc));
-                }
-                base64_count = 0;
-            }
-        }else{
-            if (base64_count > 71){
-                eof_mime();
-                PUT_NEWLINE((*o_mputc));
-                base64_count = 0;
-            }
-            if (c == EOF) { /* c==EOF */
-                eof_mime();
-            }
-        }
-        if (c != EOF) { /* c==EOF */
-            mimeout_addchar(c);
-        }
-        return;
+    if (input_encoding && !nkf_enc_asciicompat(input_encoding)) {
+       is_8bit = TRUE;
     }
 
-    /* mimeout_f != FIXED_MIME */
+    input_mode = ASCII;
+    output_mode = ASCII;
+    shift_mode = FALSE;
 
-    if (c == EOF) { /* c==EOF */
-       if (mimeout_mode == -1 && mimeout_buf_count > 1) open_mime(output_mode);
-       j = mimeout_buf_count;
-       mimeout_buf_count = 0;
-       i = 0;
-       if (mimeout_mode > 0) {
-           if (!nkf_isblank(mimeout_buf[j-1])) {
-               for (;i<j;i++) {
-                   if (nkf_isspace(mimeout_buf[i]) && base64_count < 71){
-                       break;
-                   }
-                   mimeout_addchar(mimeout_buf[i]);
-               }
-               eof_mime();
-               for (;i<j;i++) {
-                   mimeout_addchar(mimeout_buf[i]);
-               }
-           } else {
-               for (;i<j;i++) {
-                   mimeout_addchar(mimeout_buf[i]);
-               }
-               eof_mime();
-           }
-       } else {
-           for (;i<j;i++) {
-               mimeout_addchar(mimeout_buf[i]);
-           }
-       }
-        return;
-    }
+#define NEXT continue      /* no output, get next */
+#define SEND ;             /* output c1 and c2, get next */
+#define LAST break         /* end of loop, go closing  */
 
-    if (mimeout_buf_count > 0){
-        lastchar = mimeout_buf[mimeout_buf_count - 1];
-    }else{
-        lastchar = -1;
-    }
+    module_connection();
+    check_bom(f);
 
-    if (mimeout_mode=='Q') {
-        if (c <= DEL && (output_mode==ASCII ||output_mode == ISO_8859_1)) {
-           if (c == CR || c == LF) {
-               close_mime();
-               (*o_mputc)(c);
-               base64_count = 0;
-               return;
-            } else if (c <= SP) {
-                close_mime();
-               if (base64_count > 70) {
-                   PUT_NEWLINE((*o_mputc));
-                   base64_count = 0;
-               }
-               if (!nkf_isblank(c)) {
-                   (*o_mputc)(SP);
-                   base64_count++;
-               }
-            } else {
-               if (base64_count > 70) {
-                   close_mime();
-                   PUT_NEWLINE((*o_mputc));
-                   (*o_mputc)(SP);
-                   base64_count = 1;
-                   open_mime(output_mode);
-               }
-               if (!nkf_noescape_mime(c)) {
-                   mimeout_addchar(c);
-                   return;
+    while ((c1 = (*i_getc)(f)) != EOF) {
+#ifdef INPUT_CODE_FIX
+       if (!input_encoding)
+#endif
+           code_status(c1);
+        if (c2) {
+            /* second byte */
+            if (c2 > ((input_encoding && nkf_enc_cp5022x_p(input_encoding)) ? 0x92 : DEL)) {
+                /* in case of 8th bit is on */
+                if (!estab_f&&!mime_decode_mode) {
+                    /* in case of not established yet */
+                    /* It is still ambiguious */
+                    if (h_conv(f, c2, c1)==EOF)
+                        LAST;
+                    else
+                        c2 = 0;
+                    NEXT;
+                } else {
+                   /* in case of already established */
+                   if (c1 < AT) {
+                       /* ignore bogus code and not CP5022x UCD */
+                       c2 = 0;
+                       NEXT;
+                   } else {
+                       SEND;
+                   }
                }
-           }
-           (*o_mputc)(c);
-           base64_count++;
-        }
-        return;
-    }
-
-    if (mimeout_mode <= 0) {
-        if (c <= DEL && (output_mode==ASCII ||output_mode == ISO_8859_1)) {
-            if (nkf_isspace(c)) {
-               int flag = 0;
-               if (mimeout_mode == -1) {
-                   flag = 1;
+            } else
+                /* second byte, 7 bit code */
+                /* it might be kanji shitfted */
+                if ((c1 == DEL) || (c1 <= SP)) {
+                    /* ignore bogus first code */
+                    c2 = 0;
+                    NEXT;
+                } else
+                    SEND;
+        } else {
+            /* first byte */
+#ifdef UTF8_INPUT_ENABLE
+           if (iconv == w_iconv16) {
+               if (input_endian == ENDIAN_BIG) {
+                   c2 = c1;
+                   if ((c1 = (*i_getc)(f)) != EOF) {
+                       if (0xD8 <= c2 && c2 <= 0xDB) {
+                           if ((c0 = (*i_getc)(f)) != EOF) {
+                               c0 <<= 8;
+                               if ((c3 = (*i_getc)(f)) != EOF) {
+                                   c0 |= c3;
+                               } else c2 = EOF;
+                           } else c2 = EOF;
+                       }
+                   } else c2 = EOF;
+               } else {
+                   if ((c2 = (*i_getc)(f)) != EOF) {
+                       if (0xD8 <= c2 && c2 <= 0xDB) {
+                           if ((c3 = (*i_getc)(f)) != EOF) {
+                               if ((c0 = (*i_getc)(f)) != EOF) {
+                                   c0 <<= 8;
+                                   c0 |= c3;
+                               } else c2 = EOF;
+                           } else c2 = EOF;
+                       }
+                   } else c2 = EOF;
                }
-                if (c==CR || c==LF) {
-                   if (flag) {
-                       open_mime(output_mode);
-                       output_mode = 0;
-                   } else {
-                       base64_count = 0;
+               SEND;
+            } else if(iconv == w_iconv32){
+               int c3 = c1;
+               if((c2 = (*i_getc)(f)) != EOF &&
+                  (c1 = (*i_getc)(f)) != EOF &&
+                  (c0 = (*i_getc)(f)) != EOF){
+                   switch(input_endian){
+                   case ENDIAN_BIG:
+                       c1 = (c2&0xFF)<<16 | (c1&0xFF)<<8 | (c0&0xFF);
+                       break;
+                   case ENDIAN_LITTLE:
+                       c1 = (c3&0xFF) | (c2&0xFF)<<8 | (c1&0xFF)<<16;
+                       break;
+                   case ENDIAN_2143:
+                       c1 = (c3&0xFF)<<16 | (c1&0xFF) | (c0&0xFF)<<8;
+                       break;
+                   case ENDIAN_3412:
+                       c1 = (c3&0xFF)<<8 | (c2&0xFF) | (c0&0xFF)<<16;
+                       break;
                    }
-                }
-                for (i=0;i<mimeout_buf_count;i++) {
-                    (*o_mputc)(mimeout_buf[i]);
-                    if (mimeout_buf[i] == CR || mimeout_buf[i] == LF){
-                        base64_count = 0;
-                    }else{
-                        base64_count++;
-                    }
-                }
-               if (flag) {
-                   eof_mime();
-                   base64_count = 0;
-                   mimeout_mode = 0;
-                }
-               mimeout_buf[0] = (char)c;
-               mimeout_buf_count = 1;
-            }else{
-                if (base64_count > 1
-                    && base64_count + mimeout_buf_count > 76
-                   && mimeout_buf[0] != CR && mimeout_buf[0] != LF){
-                    PUT_NEWLINE((*o_mputc));
-                    base64_count = 0;
-                    if (!nkf_isspace(mimeout_buf[0])){
-                        (*o_mputc)(SP);
-                        base64_count++;
+                   c2 = 0;
+               }else{
+                   c2 = EOF;
+               }
+               SEND;
+            } else
+#endif
+#ifdef NUMCHAR_OPTION
+            if (is_unicode_capsule(c1)){
+                SEND;
+           } else
+#endif
+           if (c1 > ((input_encoding && nkf_enc_cp5022x_p(input_encoding)) ? 0x92 : DEL)) {
+                /* 8 bit code */
+                if (!estab_f && !iso8859_f) {
+                    /* not established yet */
+                    c2 = c1;
+                    NEXT;
+                } else { /* estab_f==TRUE */
+                    if (iso8859_f) {
+                        c2 = ISO_8859_1;
+                        c1 &= 0x7f;
+                        SEND;
+                    } else if (SSP<=c1 && c1<0xe0 && iconv == s_iconv) {
+                        /* SJIS X0201 Case... */
+                        if (iso2022jp_f && !x0201_f) {
+                            (*oconv)(GETA1, GETA2);
+                            NEXT;
+                        } else {
+                           c2 = JIS_X_0201;
+                           c1 &= 0x7f;
+                           SEND;
+                       }
+                    } else if (c1==SSO && iconv != s_iconv) {
+                        /* EUC X0201 Case */
+                        c1 = (*i_getc)(f);  /* skip SSO */
+                        code_status(c1);
+                        if (SSP<=c1 && c1<0xe0) {
+                           if (iso2022jp_f && !x0201_f) {
+                               (*oconv)(GETA1, GETA2);
+                               NEXT;
+                           } else {
+                               c2 = JIS_X_0201;
+                               c1 &= 0x7f;
+                               SEND;
+                           }
+                        } else  { /* bogus code, skip SSO and one byte */
+                            NEXT;
+                        }
+                   } else if (ms_ucs_map_f == UCS_MAP_CP10001 &&
+                              (c1 == 0xFD || c1 == 0xFE)) {
+                       /* CP10001 */
+                       c2 = JIS_X_0201;
+                       c1 &= 0x7f;
+                       SEND;
+                    } else {
+                       /* already established */
+                       c2 = c1;
+                       NEXT;
                     }
                 }
-                mimeout_buf[mimeout_buf_count++] = (char)c;
-                if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
-                    open_mime(output_mode);
-                }
-            }
-            return;
-        }else{
-            if (lastchar==CR || lastchar == LF){
-                for (i=0;i<mimeout_buf_count;i++) {
-                    (*o_mputc)(mimeout_buf[i]);
-                }
-                base64_count = 0;
-                mimeout_buf_count = 0;
-            }
-            if (lastchar==SP) {
-                for (i=0;i<mimeout_buf_count-1;i++) {
-                    (*o_mputc)(mimeout_buf[i]);
-                    base64_count++;
-                }
-                mimeout_buf[0] = SP;
-                mimeout_buf_count = 1;
-            }
-            open_mime(output_mode);
-        }
-    }else{
-        /* mimeout_mode == 'B', 1, 2 */
-        if ( c<=DEL && (output_mode==ASCII ||output_mode == ISO_8859_1)) {
-            if (lastchar == CR || lastchar == LF){
-                if (nkf_isblank(c)) {
-                    for (i=0;i<mimeout_buf_count;i++) {
-                        mimeout_addchar(mimeout_buf[i]);
+            } else if ((c1 > SP) && (c1 != DEL)) {
+                /* in case of Roman characters */
+                if (shift_mode) {
+                    /* output 1 shifted byte */
+                    if (iso8859_f) {
+                        c2 = ISO_8859_1;
+                        SEND;
+                    } else if (SP <= c1 && c1 < (0xe0&0x7f)){
+                      /* output 1 shifted byte */
+                       if (iso2022jp_f && !x0201_f) {
+                           (*oconv)(GETA1, GETA2);
+                           NEXT;
+                       } else {
+                           c2 = JIS_X_0201;
+                           SEND;
+                       }
+                    } else {
+                        /* look like bogus code */
+                        NEXT;
                     }
-                    mimeout_buf_count = 0;
-                } else if (SP<c && c<DEL) {
-                    eof_mime();
-                    for (i=0;i<mimeout_buf_count;i++) {
-                        (*o_mputc)(mimeout_buf[i]);
+                } else if (input_mode == JIS_X_0208 || input_mode == JIS_X_0212 ||
+                          input_mode == JIS_X_0213_1 || input_mode == JIS_X_0213_2) {
+                    /* in case of Kanji shifted */
+                    c2 = c1;
+                    NEXT;
+                } else if (c1 == '=' && mime_f && !mime_decode_mode) {
+                    /* Check MIME code */
+                    if ((c1 = (*i_getc)(f)) == EOF) {
+                        (*oconv)(0, '=');
+                        LAST;
+                    } else if (c1 == '?') {
+                        /* =? is mime conversion start sequence */
+                       if(mime_f == STRICT_MIME) {
+                           /* check in real detail */
+                           if (mime_begin_strict(f) == EOF)
+                               LAST;
+                           else
+                               NEXT;
+                       } else if (mime_begin(f) == EOF)
+                            LAST;
+                        else
+                            NEXT;
+                    } else {
+                        (*oconv)(0, '=');
+                        (*i_ungetc)(c1,f);
+                        NEXT;
                     }
-                    base64_count = 0;
-                    mimeout_buf_count = 0;
+                } else {
+                    /* normal ASCII code */
+                    SEND;
                 }
-                mimeout_buf[mimeout_buf_count++] = (char)c;
-               return;
-            }
-            if (c==SP || c==TAB || c==CR || c==LF) {
-                for (i=0;i<mimeout_buf_count;i++) {
-                    if (SP<mimeout_buf[i] && mimeout_buf[i]<DEL) {
-                        eof_mime();
-                        for (i=0;i<mimeout_buf_count;i++) {
-                            (*o_mputc)(mimeout_buf[i]);
-                            base64_count++;
+            } else if (c1 == SI && (!is_8bit || mime_decode_mode)) {
+                shift_mode = FALSE;
+                NEXT;
+            } else if (c1 == SO && (!is_8bit || mime_decode_mode)) {
+                shift_mode = TRUE;
+                NEXT;
+            } else if (c1 == ESC && (!is_8bit || mime_decode_mode)) {
+                if ((c1 = (*i_getc)(f)) == EOF) {
+                    /*  (*oconv)(0, ESC); don't send bogus code */
+                    LAST;
+                } else if (c1 == '$') {
+                    if ((c1 = (*i_getc)(f)) == EOF) {
+                        /*
+                        (*oconv)(0, ESC); don't send bogus code
+                        (*oconv)(0, '$'); */
+                        LAST;
+                    } else if (c1 == '@'|| c1 == 'B') {
+                        /* This is kanji introduction */
+                        input_mode = JIS_X_0208;
+                        shift_mode = FALSE;
+                        set_input_codename("ISO-2022-JP");
+#ifdef CHECK_OPTION
+                        debug("ISO-2022-JP");
+#endif
+                        NEXT;
+                    } else if (c1 == '(') {
+                        if ((c1 = (*i_getc)(f)) == EOF) {
+                            /* don't send bogus code
+                            (*oconv)(0, ESC);
+                            (*oconv)(0, '$');
+                            (*oconv)(0, '(');
+                                */
+                            LAST;
+                        } else if (c1 == '@'|| c1 == 'B') {
+                            /* This is kanji introduction */
+                            input_mode = JIS_X_0208;
+                            shift_mode = FALSE;
+                            NEXT;
+#ifdef X0212_ENABLE
+                        } else if (c1 == 'D'){
+                            input_mode = JIS_X_0212;
+                            shift_mode = FALSE;
+                            NEXT;
+#endif /* X0212_ENABLE */
+                        } else if (c1 == 0x4F){
+                            input_mode = JIS_X_0213_1;
+                            shift_mode = FALSE;
+                            NEXT;
+                        } else if (c1 == 0x50){
+                            input_mode = JIS_X_0213_2;
+                            shift_mode = FALSE;
+                            NEXT;
+                        } else {
+                            /* could be some special code */
+                            (*oconv)(0, ESC);
+                            (*oconv)(0, '$');
+                            (*oconv)(0, '(');
+                            (*oconv)(0, c1);
+                            NEXT;
                         }
-                        mimeout_buf_count = 0;
-                    }
-                }
-                mimeout_buf[mimeout_buf_count++] = (char)c;
-                if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
-                    eof_mime();
-                    for (i=0;i<mimeout_buf_count;i++) {
-                        (*o_mputc)(mimeout_buf[i]);
-                        base64_count++;
+                    } else if (broken_f&0x2) {
+                        /* accept any ESC-(-x as broken code ... */
+                        input_mode = JIS_X_0208;
+                        shift_mode = FALSE;
+                        NEXT;
+                    } else {
+                        (*oconv)(0, ESC);
+                        (*oconv)(0, '$');
+                        (*oconv)(0, c1);
+                        NEXT;
                     }
-                    mimeout_buf_count = 0;
-                }
-                return;
-           }
-            if (mimeout_buf_count>0 && SP<c && c!='=') {
-                mimeout_buf[mimeout_buf_count++] = (char)c;
-                if (mimeout_buf_count>MIMEOUT_BUF_LENGTH) {
-                    j = mimeout_buf_count;
-                    mimeout_buf_count = 0;
-                    for (i=0;i<j;i++) {
-                        mimeout_addchar(mimeout_buf[i]);
+                } else if (c1 == '(') {
+                    if ((c1 = (*i_getc)(f)) == EOF) {
+                        /* don't send bogus code
+                        (*oconv)(0, ESC);
+                        (*oconv)(0, '('); */
+                        LAST;
+                    } else {
+                        if (c1 == 'I') {
+                            /* This is X0201 kana introduction */
+                            input_mode = JIS_X_0201; shift_mode = JIS_X_0201;
+                            NEXT;
+                        } else if (c1 == 'B' || c1 == 'J' || c1 == 'H') {
+                            /* This is X0208 kanji introduction */
+                            input_mode = ASCII; shift_mode = FALSE;
+                            NEXT;
+                        } else if (broken_f&0x2) {
+                            input_mode = ASCII; shift_mode = FALSE;
+                            NEXT;
+                        } else {
+                            (*oconv)(0, ESC);
+                            (*oconv)(0, '(');
+                            /* maintain various input_mode here */
+                            SEND;
+                        }
                     }
+               } else if ( c1 == 'N' || c1 == 'n'){
+                   /* SS2 */
+                   c3 = (*i_getc)(f);  /* skip SS2 */
+                   if ( (SP<=c3 && c3 < 0x60) || (0xa0<=c3 && c3 < 0xe0)){
+                       c1 = c3;
+                       c2 = JIS_X_0201;
+                       SEND;
+                   }else{
+                       (*i_ungetc)(c3, f);
+                       /* lonely ESC  */
+                       (*oconv)(0, ESC);
+                       SEND;
+                   }
+                } else {
+                    /* lonely ESC  */
+                    (*oconv)(0, ESC);
+                    SEND;
                 }
-                return;
-            }
+           } else if (c1 == ESC && iconv == s_iconv) {
+               /* ESC in Shift_JIS */
+               if ((c1 = (*i_getc)(f)) == EOF) {
+                   /*  (*oconv)(0, ESC); don't send bogus code */
+                   LAST;
+               } else if (c1 == '$') {
+                   /* J-PHONE emoji */
+                   if ((c1 = (*i_getc)(f)) == EOF) {
+                       /*
+                          (*oconv)(0, ESC); don't send bogus code
+                          (*oconv)(0, '$'); */
+                       LAST;
+                   } else {
+                       if (('E' <= c1 && c1 <= 'G') ||
+                           ('O' <= c1 && c1 <= 'Q')) {
+                           /*
+                              NUM : 0 1 2 3 4 5
+                              BYTE: G E F O P Q
+                              C%7 : 1 6 0 2 3 4
+                              C%7 : 0 1 2 3 4 5 6
+                              NUM : 2 0 3 4 5 X 1
+                            */
+                           static const char jphone_emoji_first_table[7] = {2, 0, 3, 4, 5, 0, 1};
+                           c0 = (jphone_emoji_first_table[c1 % 7] << 8) - SP + 0xE000 + CLASS_UNICODE;
+                           while ((c1 = (*i_getc)(f)) != EOF) {
+                               if (SP <= c1 && c1 <= 'z') {
+                                   (*oconv)(0, c1 + c0);
+                               } else break; /* c1 == SO */
+                           }
+                       }
+                   }
+                   if (c1 == EOF) LAST;
+                   NEXT;
+               } else {
+                   /* lonely ESC  */
+                   (*oconv)(0, ESC);
+                   SEND;
+               }
+           } else if (c1 == LF || c1 == CR) {
+               if (broken_f&4) {
+                   input_mode = ASCII; set_iconv(FALSE, 0);
+                   SEND;
+               } else if (mime_decode_f && !mime_decode_mode){
+                   if (c1 == LF) {
+                       if ((c1=(*i_getc)(f))!=EOF && c1 == SP) {
+                           i_ungetc(SP,f);
+                           continue;
+                       } else {
+                           i_ungetc(c1,f);
+                       }
+                       c1 = LF;
+                       SEND;
+                   } else  { /* if (c1 == CR)*/
+                       if ((c1=(*i_getc)(f))!=EOF) {
+                           if (c1==SP) {
+                               i_ungetc(SP,f);
+                               continue;
+                           } else if (c1 == LF && (c1=(*i_getc)(f))!=EOF && c1 == SP) {
+                               i_ungetc(SP,f);
+                               continue;
+                           } else {
+                               i_ungetc(c1,f);
+                           }
+                           i_ungetc(LF,f);
+                       } else {
+                           i_ungetc(c1,f);
+                       }
+                       c1 = CR;
+                       SEND;
+                   }
+               }
+           } else if (c1 == DEL && input_mode == JIS_X_0208) {
+               /* CP5022x */
+               c2 = c1;
+               NEXT;
+           } else
+                SEND;
         }
-    }
-    if (mimeout_buf_count>0) {
-       j = mimeout_buf_count;
-       mimeout_buf_count = 0;
-       for (i=0;i<j;i++) {
-           if (mimeout_buf[i]==CR || mimeout_buf[i]==LF)
+        /* send: */
+       switch(input_mode){
+       case ASCII:
+           switch ((*iconv)(c2, c1, c0)) {  /* can be EUC / SJIS / UTF-8 / UTF-16 */
+           case -2:
+               /* 4 bytes UTF-8 */
+               if ((c0 = (*i_getc)(f)) != EOF) {
+                   code_status(c0);
+                   c0 <<= 8;
+                   if ((c3 = (*i_getc)(f)) != EOF) {
+                       code_status(c3);
+                       (*iconv)(c2, c1, c0|c3);
+                   }
+               }
+               break;
+           case -1:
+               /* 3 bytes EUC or UTF-8 */
+               if ((c0 = (*i_getc)(f)) != EOF) {
+                   code_status(c0);
+                   (*iconv)(c2, c1, c0);
+               }
                break;
-           mimeout_addchar(mimeout_buf[i]);
-       }
-       if (i<j) {
-           eof_mime();
-           base64_count=0;
-           for (;i<j;i++) {
-               (*o_mputc)(mimeout_buf[i]);
            }
-           open_mime(output_mode);
-       }
-    }
-    mimeout_addchar(c);
-}
-
-#ifdef HAVE_ICONV_H
-typedef struct nkf_iconv_t {
-    iconv_t cd;
-    char *input_buffer;
-    size_t input_buffer_size;
-    char *output_buffer;
-    size_t output_buffer_size;
-}
-
-nkf_iconv_t nkf_iconv_new(char *tocode, char *fromcode)
-{
-    nkf_iconv_t converter;
-
-    converter->input_buffer_size = IOBUF_SIZE;
-    converter->input_buffer = malloc(converter->input_buffer_size);
-    if (converter->input_buffer == NULL)
-        perror("can't malloc");
-
-    converter->output_buffer_size = IOBUF_SIZE * 2;
-    converter->output_buffer = malloc(converter->output_buffer_size);
-    if (converter->output_buffer == NULL)
-        perror("can't malloc");
-
-    converter->cd = iconv_open(tocode, fromcode);
-    if (converter->cd == (iconv_t)-1)
-    {
-        switch (errno) {
-        case EINVAL:
-            perror(fprintf("iconv doesn't support %s to %s conversion.", fromcode, tocode));
-            return -1;
-        default:
-            perror("can't iconv_open");
-        }
-    }
-}
-
-size_t nkf_iconv_convert(nkf_iconv_t *converter, FILE *input)
-{
-    size_t invalid = (size_t)0;
-    char *input_buffer = converter->input_buffer;
-    size_t input_length = (size_t)0;
-    char *output_buffer = converter->output_buffer;
-    size_t output_length = converter->output_buffer_size;
-    int c;
-
-    do {
-        if (c != EOF) {
-            while ((c = (*i_getc)(f)) != EOF) {
-                input_buffer[input_length++] = c;
-                if (input_length < converter->input_buffer_size) break;
-            }
-        }
-
-        size_t ret = iconv(converter->cd, &input_buffer, &input_length, &output_buffer, &output_length);
-        while (output_length-- > 0) {
-            (*o_putc)(output_buffer[converter->output_buffer_size-output_length]);
-        }
-        if (ret == (size_t) - 1) {
-            switch (errno) {
-            case EINVAL:
-                if (input_buffer != converter->input_buffer)
-                    memmove(converter->input_buffer, input_buffer, input_length);
-                break;
-            case E2BIG:
-                converter->output_buffer_size *= 2;
-                output_buffer = realloc(converter->outbuf, converter->output_buffer_size);
-                if (output_buffer == NULL) {
-                    perror("can't realloc");
-                    return -1;
-                }
-                converter->output_buffer = output_buffer;
-                break;
-            default:
-                perror("can't iconv");
-                return -1;
-            }
-        } else {
-            invalid += ret;
-        }
-    } while (1);
-
-    return invalid;
-}
-
-
-void nkf_iconv_close(nkf_iconv_t *convert)
-{
-        free(converter->inbuf);
-        free(converter->outbuf);
-        iconv_close(converter->cd);
-}
-#endif
+           break;
+       case JIS_X_0208:
+       case JIS_X_0213_1:
+           if (ms_ucs_map_f &&
+               0x7F <= c2 && c2 <= 0x92 &&
+               0x21 <= c1 && c1 <= 0x7E) {
+               /* CP932 UDC */
+               if(c1 == 0x7F) return 0;
+               c1 = (c2 - 0x7F) * 94 + c1 - 0x21 + 0xE000 + CLASS_UNICODE;
+               c2 = 0;
+           }
+           (*oconv)(c2, c1); /* this is JIS, not SJIS/EUC case */
+           break;
+#ifdef X0212_ENABLE
+       case JIS_X_0212:
+           (*oconv)(PREFIX_EUCG3 | c2, c1);
+           break;
+#endif /* X0212_ENABLE */
+       case JIS_X_0213_2:
+           (*oconv)(PREFIX_EUCG3 | c2, c1);
+           break;
+       default:
+           (*oconv)(input_mode, c1);  /* other special case */
+       }
 
+        c2 = 0;
+        c0 = 0;
+        continue;
+        /* goto next_word */
+    }
 
-void reinit(void)
-{
+    /* epilogue */
+    (*iconv)(EOF, 0, 0);
+    if (!input_codename)
     {
-        struct input_code *p = input_code_list;
-        while (p->name){
-            status_reinit(p++);
-        }
-    }
-    unbuf_f = FALSE;
-    estab_f = FALSE;
-    nop_f = FALSE;
-    binmode_f = TRUE;
-    rot_f = FALSE;
-    hira_f = FALSE;
-    alpha_f = FALSE;
-    mime_f = MIME_DECODE_DEFAULT;
-    mime_decode_f = FALSE;
-    mimebuf_f = FALSE;
-    broken_f = FALSE;
-    iso8859_f = FALSE;
-    mimeout_f = FALSE;
-    x0201_f = X0201_DEFAULT;
-    iso2022jp_f = FALSE;
-#if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
-    ms_ucs_map_f = UCS_MAP_ASCII;
-#endif
-#ifdef UTF8_INPUT_ENABLE
-    no_cp932ext_f = FALSE;
-    no_best_fit_chars_f = FALSE;
-    encode_fallback = NULL;
-    unicode_subchar  = '?';
-    input_endian = ENDIAN_BIG;
-#endif
-#ifdef UTF8_OUTPUT_ENABLE
-    output_bom_f = FALSE;
-    output_endian = ENDIAN_BIG;
-#endif
-#ifdef UNICODE_NORMALIZATION
-    nfc_f = FALSE;
-#endif
-#ifdef INPUT_OPTION
-    cap_f = FALSE;
-    url_f = FALSE;
-    numchar_f = FALSE;
-#endif
+       if (is_8bit) {
+           struct input_code *p = input_code_list;
+           struct input_code *result = p;
+           while (p->name){
+               if (p->score < result->score) result = p;
+               ++p;
+           }
+           set_input_codename(result->name);
 #ifdef CHECK_OPTION
-    noout_f = FALSE;
-    debug_f = FALSE;
-#endif
-    guess_f = 0;
-#ifdef EXEC_IO
-    exec_f = 0;
-#endif
-#ifdef SHIFTJIS_CP932
-    cp51932_f = TRUE;
-    cp932inv_f = TRUE;
-#endif
-#ifdef X0212_ENABLE
-    x0212_f = FALSE;
-    x0213_f = FALSE;
+           debug(result->name);
 #endif
-    {
-        int i;
-        for (i = 0; i < 256; i++){
-            prefix_table[i] = 0;
-        }
+       }
     }
-    hold_count = 0;
-    mimeout_buf_count = 0;
-    mimeout_mode = 0;
-    base64_count = 0;
-    f_line = 0;
-    f_prev = 0;
-    fold_preserve_f = FALSE;
-    fold_f = FALSE;
-    fold_len = 0;
-    kanji_intro = DEFAULT_J;
-    ascii_intro = DEFAULT_R;
-    fold_margin  = FOLD_MARGIN;
-    o_zconv = no_connection;
-    o_fconv = no_connection;
-    o_nlconv = no_connection;
-    o_rot_conv = no_connection;
-    o_hira_conv = no_connection;
-    o_base64conv = no_connection;
-    o_iso2022jp_check_conv = no_connection;
-    o_putc = std_putc;
-    i_getc = std_getc;
-    i_ungetc = std_ungetc;
-    i_bgetc = std_getc;
-    i_bungetc = std_ungetc;
-    o_mputc = std_putc;
-    i_mgetc = std_getc;
-    i_mungetc  = std_ungetc;
-    i_mgetc_buf = std_getc;
-    i_mungetc_buf = std_ungetc;
-    output_mode = ASCII;
-    input_mode =  ASCII;
-    shift_mode =  FALSE;
-    mime_decode_mode = FALSE;
-    file_out_f = FALSE;
-    nlmode_f = 0;
-    input_newline = 0;
-    prev_cr = 0;
-    option_mode = 0;
-    broken_counter = 0;
-    broken_last = 0;
-    z_prev2=0,z_prev1=0;
-#ifdef CHECK_OPTION
-    iconv_for_check = 0;
-#endif
-    input_codename = NULL;
-    input_encoding = NULL;
-    output_encoding = NULL;
-#ifdef WIN32DLL
-    reinitdll();
-#endif /*WIN32DLL*/
+    return 1;
 }
 
-void no_connection(nkf_char c2, nkf_char c1)
+#ifdef WIN32DLL
+#include "nkf32dll.c"
+#elif defined(PERL_XS)
+#else /* WIN32DLL */
+int main(int argc, char **argv)
 {
-    no_connection2(c2,c1,0);
-}
+    FILE  *fin;
+    unsigned char  *cp;
 
-nkf_char no_connection2(nkf_char c2, nkf_char c1, nkf_char c0)
-{
-    fprintf(stderr,"nkf internal module connection failure.\n");
-    exit(1);
-    return 0; /* LINT */
-}
+    char *outfname = NULL;
+    char *origfname;
 
-#ifndef PERL_XS
-#ifdef WIN32DLL
-#define fprintf dllprintf
+#ifdef EASYWIN /*Easy Win */
+    _BufferSize.y = 400;/*Set Scroll Buffer Size*/
 #endif
+    setlocale(LC_CTYPE, "");
 
-void version(void)
-{
-    fprintf(HELP_OUTPUT,"Network Kanji Filter Version " NKF_VERSION " (" NKF_RELEASE_DATE ") \n" COPY_RIGHT "\n");
-}
-
-void usage(void)
-{
-    fprintf(HELP_OUTPUT,
-           "USAGE:  nkf(nkf32,wnkf,nkf2) -[flags] [in file] .. [out file for -O flag]\n"
-           "Flags:\n"
-           "b,u      Output is buffered (DEFAULT),Output is unbuffered\n"
-           "j,s,e,w  Output code is ISO-2022-JP, Shift JIS, EUC-JP, UTF-8N\n"
-#ifdef UTF8_OUTPUT_ENABLE
-           "         After 'w' you can add more options. -w[ 8 [0], 16 [[BL] [0]] ]\n"
+    for (argc--,argv++; (argc > 0) && **argv == '-'; argc--, argv++) {
+        cp = (unsigned char *)*argv;
+        options(cp);
+#ifdef EXEC_IO
+        if (exec_f){
+            int fds[2], pid;
+            if (pipe(fds) < 0 || (pid = fork()) < 0){
+                abort();
+            }
+            if (pid == 0){
+                if (exec_f > 0){
+                    close(fds[0]);
+                    dup2(fds[1], 1);
+                }else{
+                    close(fds[1]);
+                    dup2(fds[0], 0);
+                }
+                execvp(argv[1], &argv[1]);
+            }
+            if (exec_f > 0){
+                close(fds[1]);
+                dup2(fds[0], 0);
+            }else{
+                close(fds[0]);
+                dup2(fds[1], 1);
+            }
+            argc = 0;
+            break;
+        }
 #endif
-           "J,S,E,W  Input assumption is JIS 7 bit , Shift JIS, EUC-JP, UTF-8\n"
-#ifdef UTF8_INPUT_ENABLE
-           "         After 'W' you can add more options. -W[ 8, 16 [BL] ] \n"
+    }
+
+    if (guess_f) {
+#ifdef CHECK_OPTION
+       int debug_f_back = debug_f;
 #endif
-           "t        no conversion\n"
-           "i[@B]    Specify the Esc Seq for JIS X 0208-1978/83 (DEFAULT B)\n"
-           "o[BJH]   Specify the Esc Seq for ASCII/Roman        (DEFAULT B)\n"
-           "r        {de/en}crypt ROT13/47\n"
-           "h        1 katakana->hiragana, 2 hiragana->katakana, 3 both\n"
-           "m[BQSN0] MIME decode [B:base64,Q:quoted,S:strict,N:non-strict,0:no decode]\n"
-           "M[BQ]    MIME encode [B:base64 Q:quoted]\n"
-           "l        ISO8859-1 (Latin-1) support\n"
-           "f/F      Folding: -f60 or -f or -f60-10 (fold margin 10) F preserve nl\n"
-           "Z[0-4]   Default/0: Convert JISX0208 Alphabet to ASCII\n"
-           "         1: Kankaku to one space  2: to two spaces  3: HTML Entity\n"
-           "         4: JISX0208 Katakana to JISX0201 Katakana\n"
-           "X,x      Assume X0201 kana in MS-Kanji, -x preserves X0201\n"
-           "B[0-2]   Broken input  0: missing ESC,1: any X on ESC-[($]-X,2: ASCII on NL\n"
-#ifdef MSDOS
-           "T        Text mode output\n"
+#ifdef EXEC_IO
+       int exec_f_back = exec_f;
 #endif
-           "O        Output to File (DEFAULT 'nkf.out')\n"
-           "I        Convert non ISO-2022-JP charactor to GETA\n"
-           "d,c      Convert line breaks  -d: LF  -c: CRLF\n"
-           "-L[uwm]  line mode u:LF w:CRLF m:CR (DEFAULT noconversion)\n"
-           "v, V     Show this usage. V: show configuration\n"
-           "\n"
-           "Long name options\n"
-           " --ic=<input codeset>  --oc=<output codeset>\n"
-           "                   Specify the input or output codeset\n"
-           " --fj  --unix --mac  --windows\n"
-           " --jis  --euc  --sjis  --utf8  --utf16  --mime  --base64\n"
-           "                   Convert for the system or code\n"
-           " --hiragana  --katakana  --katakana-hiragana\n"
-           "                   To Hiragana/Katakana Conversion\n"
-           " --prefix=         Insert escape before troublesome characters of Shift_JIS\n"
-#ifdef INPUT_OPTION
-           " --cap-input, --url-input  Convert hex after ':' or '%%'\n"
+#ifdef X0212_ENABLE
+       int x0212_f_back = x0212_f;
 #endif
-#ifdef NUMCHAR_OPTION
-           " --numchar-input   Convert Unicode Character Reference\n"
+       int x0213_f_back = x0213_f;
+       int guess_f_back = guess_f;
+       reinit();
+       guess_f = guess_f_back;
+       mime_f = FALSE;
+#ifdef CHECK_OPTION
+       debug_f = debug_f_back;
 #endif
-#ifdef UTF8_INPUT_ENABLE
-           " --fb-{skip, html, xml, perl, java, subchar}\n"
-           "                   Specify how nkf handles unassigned characters\n"
+#ifdef EXEC_IO
+       exec_f = exec_f_back;
+#endif
+#ifdef X0212_ENABLE
+       x0212_f = x0212_f_back;
+#endif
+       x0213_f = x0213_f_back;
+    }
+
+    if (binmode_f == TRUE)
+#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
+    if (freopen("","wb",stdout) == NULL)
+        return (-1);
+#else
+    setbinmode(stdout);
+#endif
+
+    if (unbuf_f)
+      setbuf(stdout, (char *) NULL);
+    else
+      setvbuffer(stdout, (char *) stdobuf, IOBUF_SIZE);
+
+    if (argc == 0) {
+      if (binmode_f == TRUE)
+#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
+      if (freopen("","rb",stdin) == NULL) return (-1);
+#else
+      setbinmode(stdin);
+#endif
+      setvbuffer(stdin, (char *) stdibuf, IOBUF_SIZE);
+      if (nop_f)
+          noconvert(stdin);
+      else {
+          kanji_convert(stdin);
+          if (guess_f) print_guessed_code(NULL);
+      }
+    } else {
+      int nfiles = argc;
+       int is_argument_error = FALSE;
+      while (argc--) {
+           input_codename = NULL;
+           input_eol = 0;
+#ifdef CHECK_OPTION
+           iconv_for_check = 0;
 #endif
+          if ((fin = fopen((origfname = *argv++), "r")) == NULL) {
+               perror(*(argv-1));
+               is_argument_error = TRUE;
+               continue;
+          } else {
 #ifdef OVERWRITE
-           " --in-place[=SUFFIX]  --overwrite[=SUFFIX]\n"
-           "                   Overwrite original listed files by filtered result\n"
-           "                   --overwrite preserves timestamp of original files\n"
+              int fd = 0;
+              int fd_backup = 0;
 #endif
-           " -g  --guess       Guess the input code\n"
-           " --help  --version Show this help/the version\n"
-           "                   For more information, see also man nkf\n"
-           "\n");
-    version();
-}
 
-void show_configuration(void)
-{
-    fprintf(HELP_OUTPUT,
-           "Summary of my nkf " NKF_VERSION " (" NKF_RELEASE_DATE ") configuration:\n"
-           "  nkf identity:\n"
-           "    " NKF_IDENT "\n"
-           "  Compile-time options:\n"
-           "    Compiled at:                 " __DATE__ " " __TIME__ "\n"
-          );
-    fprintf(HELP_OUTPUT,
-           "    Default output encoding:     "
-#ifdef DEFAULT_ENCIDX
-           "%s\n", nkf_enc_name(nkf_default_encoding())
+/* reopen file for stdout */
+              if (file_out_f == TRUE) {
+#ifdef OVERWRITE
+                  if (overwrite_f){
+                      outfname = malloc(strlen(origfname)
+                                        + strlen(".nkftmpXXXXXX")
+                                        + 1);
+                      if (!outfname){
+                          perror(origfname);
+                          return -1;
+                      }
+                      strcpy(outfname, origfname);
+#ifdef MSDOS
+                      {
+                          int i;
+                          for (i = strlen(outfname); i; --i){
+                              if (outfname[i - 1] == '/'
+                                  || outfname[i - 1] == '\\'){
+                                  break;
+                              }
+                          }
+                          outfname[i] = '\0';
+                      }
+                      strcat(outfname, "ntXXXXXX");
+                      mktemp(outfname);
+                       fd = open(outfname, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
+                                S_IREAD | S_IWRITE);
 #else
-           "%s (%s)\n", nkf_locale_encoding() ? "LOCALE" : "DEFAULT",
-           nkf_enc_name(nkf_default_encoding())
+                      strcat(outfname, ".nkftmpXXXXXX");
+                      fd = mkstemp(outfname);
 #endif
-          );
-    fprintf(HELP_OUTPUT,
-           "    Default output newline:      "
-#if DEFAULT_NEWLINE == CR
-           "CR"
-#elif DEFAULT_NEWLINE == CRLF
-           "CRLF"
+                      if (fd < 0
+                          || (fd_backup = dup(fileno(stdout))) < 0
+                          || dup2(fd, fileno(stdout)) < 0
+                          ){
+                          perror(origfname);
+                          return -1;
+                      }
+                  }else
+#endif
+                 if(argc == 1) {
+                     outfname = *argv++;
+                     argc--;
+                 } else {
+                     outfname = "nkf.out";
+                 }
+
+                 if(freopen(outfname, "w", stdout) == NULL) {
+                     perror (outfname);
+                     return (-1);
+                 }
+                  if (binmode_f == TRUE) {
+#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
+                      if (freopen("","wb",stdout) == NULL)
+                           return (-1);
 #else
-           "LF"
+                      setbinmode(stdout);
 #endif
-           "\n"
-           "    Decode MIME encoded string:  "
-#if MIME_DECODE_DEFAULT
-           "ON"
+                  }
+              }
+              if (binmode_f == TRUE)
+#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
+                 if (freopen("","rb",fin) == NULL)
+                    return (-1);
 #else
-           "OFF"
+                 setbinmode(fin);
 #endif
-           "\n"
-           "    Convert JIS X 0201 Katakana: "
-#if X0201_DEFAULT
-           "ON"
+              setvbuffer(fin, (char *) stdibuf, IOBUF_SIZE);
+              if (nop_f)
+                  noconvert(fin);
+              else {
+                  char *filename = NULL;
+                  kanji_convert(fin);
+                  if (nfiles > 1) filename = origfname;
+                  if (guess_f) print_guessed_code(filename);
+              }
+              fclose(fin);
+#ifdef OVERWRITE
+              if (overwrite_f) {
+                  struct stat     sb;
+#if defined(MSDOS) && !defined(__MINGW32__) && !defined(__WIN32__) && !defined(__WATCOMC__) && !defined(__EMX__) && !defined(__OS2__) && !defined(__DJGPP__)
+                  time_t tb[2];
 #else
-           "OFF"
+                  struct utimbuf  tb;
 #endif
-           "\n"
-           "    --help, --version output:    "
-#if HELP_OUTPUT_HELP_OUTPUT
-           "HELP_OUTPUT"
+
+                  fflush(stdout);
+                  close(fd);
+                  if (dup2(fd_backup, fileno(stdout)) < 0){
+                      perror("dup2");
+                  }
+                  if (stat(origfname, &sb)) {
+                      fprintf(stderr, "Can't stat %s\n", origfname);
+                  }
+                  /* \e$B%Q!<%_%C%7%g%s$rI|85\e(B */
+                  if (chmod(outfname, sb.st_mode)) {
+                      fprintf(stderr, "Can't set permission %s\n", outfname);
+                  }
+
+                  /* \e$B%?%$%`%9%?%s%W$rI|85\e(B */
+                   if(preserve_time_f){
+#if defined(MSDOS) && !defined(__MINGW32__) && !defined(__WIN32__) && !defined(__WATCOMC__) && !defined(__EMX__) && !defined(__OS2__) && !defined(__DJGPP__)
+                       tb[0] = tb[1] = sb.st_mtime;
+                       if (utime(outfname, tb)) {
+                           fprintf(stderr, "Can't set timestamp %s\n", outfname);
+                       }
 #else
-           "STDOUT"
+                       tb.actime  = sb.st_atime;
+                       tb.modtime = sb.st_mtime;
+                       if (utime(outfname, &tb)) {
+                           fprintf(stderr, "Can't set timestamp %s\n", outfname);
+                       }
 #endif
-           "\n");
+                   }
+                   if(backup_f){
+                       char *backup_filename = get_backup_filename(backup_suffix, origfname);
+#ifdef MSDOS
+                       unlink(backup_filename);
+#endif
+                       if (rename(origfname, backup_filename)) {
+                           perror(backup_filename);
+                           fprintf(stderr, "Can't rename %s to %s\n",
+                                   origfname, backup_filename);
+                       }
+                   }else{
+#ifdef MSDOS
+                       if (unlink(origfname)){
+                           perror(origfname);
+                       }
+#endif
+                   }
+                  if (rename(outfname, origfname)) {
+                      perror(origfname);
+                      fprintf(stderr, "Can't rename %s to %s\n",
+                              outfname, origfname);
+                  }
+                  free(outfname);
+              }
+#endif
+          }
+      }
+       if (is_argument_error)
+           return(-1);
+    }
+#ifdef EASYWIN /*Easy Win */
+    if (file_out_f == FALSE)
+        scanf("%d",&end_check);
+    else
+        fclose(stdout);
+#else /* for Other OS */
+    if (file_out_f == TRUE)
+        fclose(stdout);
+#endif /*Easy Win */
+    return (0);
 }
-#endif /*PERL_XS*/
+#endif /* WIN32DLL */