OSDN Git Service

UTF-16 入力の変換の一部バグ修正
[nkf/nkf.git] / nkf.c
diff --git a/nkf.c b/nkf.c
index 4340616..57534e2 100644 (file)
--- a/nkf.c
+++ b/nkf.c
 #include "config.h"
 
 static char *CopyRight =
-      "Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa),2000 S. Kono, COW, 2002 Kono, Furukawa";
+      "Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa),2000 S. Kono, COW, 2002-2003 Kono, Furukawa";
 static char *Version =
       "2.0";
 static char *Patchlevel =
-      "1/0209/Shinji Kono";
+      "2/0301/Shinji Kono";
 
 /*
 **
@@ -95,8 +95,11 @@ static char *Patchlevel =
 **
 **/
 
-#if (defined(__TURBOC__) || defined(LSI_C)) && !defined(MSDOS)
+#if (defined(__TURBOC__) || defined(_MSC_VER) || defined(LSI_C)) && !defined(MSDOS)
 #define MSDOS
+#if (defined(__Win32__) || defined(_WIN32)) && !defined(__WIN32__)
+#define __WIN32__
+#endif
 #endif
 
 #ifdef PERL_XS
@@ -125,7 +128,7 @@ static char *Patchlevel =
 #define setbinmode(fp)
 #endif
 
-#ifdef _IOFBF /* SysV and MSDOS */
+#ifdef _IOFBF /* SysV and MSDOS, Windows */
 #define       setvbuffer(fp, buf, size)       setvbuf(fp, buf, _IOFBF, size)
 #else /* BSD */
 #define       setvbuffer(fp, buf, size)       setbuffer(fp, buf, size)
@@ -134,15 +137,25 @@ static char *Patchlevel =
 /*Borland C++ 4.5 EasyWin*/
 #if defined(__TURBOC__) && defined(_Windows) && !defined(__WIN32__) /*Easy Win */
 #define         EASYWIN
+#ifndef __WIN16__
+#define __WIN16__
+#endif
 #include <windows.h>
 #endif
 
 #ifdef OVERWRITE
 /* added by satoru@isoternet.org */
 #include <sys/stat.h>
-#ifndef MSDOS
+#ifndef MSDOS /* UNIX, OS/2 */
 #include <unistd.h>
 #include <utime.h>
+#else
+#if defined(_MSC_VER) /* VC++ */
+#include <sys/utime.h>
+#elif defined(__TURBOC__) /* BCC */
+#include <utime.h>
+#elif defined(LSI_C) /* LSI C */
+#endif
 #endif
 #endif 
 
@@ -253,6 +266,7 @@ struct input_code{
     int buf[3];
     void (*status_func)PROTO((struct input_code *, int));
     int (*iconv_func)PROTO((int c2, int c1, int c0));
+    int _file_stat;
 };
 
 STATIC  int     noconvert PROTO((FILE *f));
@@ -275,6 +289,7 @@ STATIC  void    w_oconv PROTO((int c2,int c1));
 STATIC  void    w_oconv16 PROTO((int c2,int c1));
 #endif
 STATIC  void    e_oconv PROTO((int c2,int c1));
+STATIC  void    e2s_conv PROTO((int c2, int c1, int *p2, int *p1));
 STATIC  void    s_oconv PROTO((int c2,int c1));
 STATIC  void    j_oconv PROTO((int c2,int c1));
 STATIC  void    fold_conv PROTO((int c2,int c1));
@@ -356,10 +371,11 @@ static int             x0201_f = NO_X0201;     /* Assume NO JISX0201 */
 static int             iso2022jp_f = FALSE;    /* convert ISO-2022-JP */
 #ifdef UTF8_OUTPUT_ENABLE
 static int             w_oconv16_begin_f= 0;   /* utf-16 header */
+static int             w_oconv16_LE = 0;   /* utf-16 little endian */
 #endif
 
 
-#ifdef CAP_URL_OPTION
+#ifdef INPUT_OPTION
 static int cap_f = FALSE;
 static int (*i_cgetc)PROTO((FILE *)) = std_getc; /* input of cgetc */
 static int (*i_cungetc)PROTO((int c ,FILE *f)) = std_ungetc;
@@ -371,6 +387,12 @@ static int (*i_ugetc)PROTO((FILE *)) = std_getc; /* input of ugetc */
 static int (*i_uungetc)PROTO((int c ,FILE *f)) = std_ungetc;
 STATIC int url_getc PROTO((FILE *f));
 STATIC int url_ungetc PROTO((int c,FILE *f));
+
+static int numchar_f = FALSE;
+static int (*i_ngetc)PROTO((FILE *)) = std_getc; /* input of ugetc */
+static int (*i_nungetc)PROTO((int c ,FILE *f)) = std_ungetc;
+STATIC int numchar_getc PROTO((FILE *f));
+STATIC int numchar_ungetc PROTO((int c,FILE *f));
 #endif
 
 #ifdef CHECK_OPTION
@@ -380,18 +402,27 @@ static int debug_f = FALSE;
 STATIC void debug PROTO((char *str));
 #endif
 
+#ifdef SHIFTJIS_CP932
+STATIC int cp932_f = FALSE;
+#define CP932_TABLE_BEGIN (0xfa)
+#define CP932_TABLE_END   (0xfc)
+
+#endif /* SHIFTJIS_CP932 */
+
 STATIC void e_status PROTO((struct input_code *, int));
 STATIC void s_status PROTO((struct input_code *, int));
 
 #ifdef UTF8_INPUT_ENABLE
 STATIC void w_status PROTO((struct input_code *, int));
+STATIC void w16_status PROTO((struct input_code *, int));
 static int             utf16_mode = UTF16_INPUT;
 #endif
 
 struct input_code input_code_list[] = {
-    {"EUC-JP",    0, 0, 0, {0, 0, 0}, e_status, e_iconv},
-    {"Shift_JIS", 0, 0, 0, {0, 0, 0}, s_status, s_iconv},
-    {"UTF-8",     0, 0, 0, {0, 0, 0}, w_status, w_iconv},
+    {"EUC-JP",    0, 0, 0, {0, 0, 0}, e_status, e_iconv, 0},
+    {"Shift_JIS", 0, 0, 0, {0, 0, 0}, s_status, s_iconv, 0},
+    {"UTF-8",     0, 0, 0, {0, 0, 0}, w_status, w_iconv, 0},
+    {"UTF-16",     0, 0, 0, {0, 0, 0}, w16_status, w_iconv16, 0},
     {0}
 };
 
@@ -805,14 +836,18 @@ struct {
 #ifdef OVERWRITE
     {"overwrite", ""},
 #endif
-#ifdef CAP_URL_OPTION
+#ifdef INPUT_OPTION
     {"cap-input", ""},
     {"url-input", ""},
+    {"numchar-input", ""},
 #endif
 #ifdef CHECK_OPTION
     {"no-output", ""},
     {"debug", ""},
 #endif
+#ifdef SHIFTJIS_CP932
+    {"cp932", ""},
+#endif
 };
 
 static int option_mode;
@@ -851,7 +886,7 @@ options(cp)
                     continue;
                 }
 #endif
-#ifdef CAP_URL_OPTION
+#ifdef INPUT_OPTION
                 if (strcmp(long_option[i].name, "cap-input") == 0){
                     cap_f = TRUE;
                     continue;
@@ -860,6 +895,10 @@ options(cp)
                     url_f = TRUE;
                     continue;
                 }
+                if (strcmp(long_option[i].name, "numchar-input") == 0){
+                    numchar_f = TRUE;
+                    continue;
+                }
 #endif
 #ifdef CHECK_OPTION
                 if (strcmp(long_option[i].name, "no-output") == 0){
@@ -871,6 +910,12 @@ options(cp)
                     continue;
                 }
 #endif
+#ifdef SHIFTJIS_CP932
+                if (strcmp(long_option[i].name, "cp932") == 0){
+                    cp932_f = TRUE;
+                    continue;
+                }
+#endif
             }
             continue;
         case 'b':           /* buffered mode */
@@ -938,7 +983,16 @@ options(cp)
                output_conv = w_oconv16; cp+=2;
                if (cp[0]=='L') {
                    w_oconv16_begin_f=2; cp++;
-               }
+                   w_oconv16_LE = 1;
+                    if (cp[0] == '0'){
+                        w_oconv16_begin_f=1; cp++;
+                    }
+               } else if (cp[0] == 'B') {
+                   w_oconv16_begin_f=2; cp++;
+                    if (cp[0] == '0'){
+                        w_oconv16_begin_f=1; cp++;
+                    }
+                }
            } else
                 output_conv = w_oconv;
             continue;
@@ -1116,10 +1170,15 @@ void set_iconv(f, iconv_func)
 #endif
 }
 
-#define SCORE_KANA     (1)                      /* \e$B$$$o$f$kH>3Q%+%J\e(B */
-#define SCORE_DEPEND   (SCORE_KANA << 1)        /* \e$B5!<o0MB8J8;z\e(B */
-#define SCORE_NO_EXIST (SCORE_DEPEND << 1)      /* \e$BB8:_$7$J$$J8;z\e(B */
-#define SCORE_ERROR    (SCORE_NO_EXIST << 1)    /* \e$B%(%i!<\e(B */
+#define SCORE_KANA     (1)                   /* \e$B$$$o$f$kH>3Q%+%J\e(B */
+#define SCORE_DEPEND   (SCORE_KANA << 1)     /* \e$B5!<o0MB8J8;z\e(B */
+#ifdef SHIFTJIS_CP932
+#define SCORE_CP932    (SCORE_DEPEND << 1)   /* CP932 \e$B$K$h$kFI$_49$(\e(B */
+#define SCORE_NO_EXIST (SCORE_CP932 << 1)    /* \e$BB8:_$7$J$$J8;z\e(B */
+#else
+#define SCORE_NO_EXIST (SCORE_DEPEND << 1)   /* \e$BB8:_$7$J$$J8;z\e(B */
+#endif
+#define SCORE_ERROR    (SCORE_NO_EXIST << 1) /* \e$B%(%i!<\e(B */
 int score_table_A0[] = {
     0, 0, 0, 0,
     0, 0, 0, 0,
@@ -1134,27 +1193,32 @@ int score_table_F0[] = {
     SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST, SCORE_ERROR,
 };
 
+void set_code_score(ptr, score)
+     struct input_code *ptr;
+     int score;
+{
+    ptr->score |= score;
+}
+
 void code_score(ptr)
      struct input_code *ptr;
 {
-    int s = ptr->score;
     int c2 = ptr->buf[0];
     int c1 = ptr->buf[1];
     if (c2 < 0){
-        s |= SCORE_ERROR;
+        set_code_score(ptr, SCORE_ERROR);
     }else if ((c2 & 0xf0) == 0xa0){
-        s |= score_table_A0[c2 & 0x0f];
+        set_code_score(ptr, score_table_A0[c2 & 0x0f]);
     }else if ((c2 & 0xf0) == 0xf0){
-        s |= score_table_F0[c2 & 0x0f];
+        set_code_score(ptr, score_table_F0[c2 & 0x0f]);
     }else if (c2 == SSO){
-        s |= SCORE_KANA;
+        set_code_score(ptr, SCORE_KANA);
     }
 #ifdef UTF8_OUTPUT_ENABLE
     else if (!e2w_conv(c2, c1)){
-        s |= SCORE_NO_EXIST;
+        set_code_score(ptr, SCORE_NO_EXIST);
     }
 #endif
-    ptr->score = s;
 }
 
 void status_disable(ptr)
@@ -1181,6 +1245,13 @@ void status_reset(ptr)
     ptr->index = 0;
 }
 
+void status_reinit(ptr)
+     struct input_code *ptr;
+{
+    status_reset(ptr);
+    ptr->_file_stat = 0;
+}
+
 void status_check(ptr, c)
      struct input_code *ptr;
      int c;
@@ -1201,20 +1272,26 @@ void s_status(ptr, c)
       case 0:
           if (c <= DEL){
               break;
-          }else if (0xa1 <= c && c <= 0xef){
+          }else if (0xa1 <= c && c <= 0xdf){
               status_push_ch(ptr, SSO);
               status_push_ch(ptr, c);
               code_score(ptr);
               status_reset(ptr);
-          }else if ((0x81 <= c && c < 0xa0) || (0xe0 <= c && c <= 0xea)){
+          }else if ((0x81 <= c && c < 0xa0) || (0xe0 <= c && c <= 0xef)){
               ptr->stat = 1;
               status_push_ch(ptr, c);
+#ifdef SHIFTJIS_CP932
+          }else if (cp932_f
+                    && CP932_TABLE_BEGIN <= c && c <= CP932_TABLE_END){
+              ptr->stat = 2;
+              status_push_ch(ptr, c);
+#endif /* SHIFTJIS_CP932 */
           }else{
               status_disable(ptr);
           }
           break;
       case 1:
-          if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfd)){
+          if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
               status_push_ch(ptr, c);
               s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]);
               code_score(ptr);
@@ -1223,6 +1300,19 @@ void s_status(ptr, c)
               status_disable(ptr);
           }
           break;
+#ifdef SHIFTJIS_CP932
+      case 2:
+          if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
+              status_push_ch(ptr, c);
+              if (s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]) == 0){
+                  set_code_score(ptr, SCORE_CP932);
+                  status_reset(ptr);
+                  break;
+              }
+          }
+          status_disable(ptr);
+          break;
+#endif /* SHIFTJIS_CP932 */
     }
 }
 
@@ -1257,6 +1347,54 @@ void e_status(ptr, c)
 }
 
 #ifdef UTF8_INPUT_ENABLE
+void w16_status(ptr, c)
+     struct input_code *ptr;
+     int c;
+{
+    switch (ptr->stat){
+      case -1:
+          break;
+      case 0:
+          if (ptr->_file_stat == 0){
+              if (c == 0xfe || c == 0xff){
+                  ptr->stat = c;
+                  status_push_ch(ptr, c);
+                  ptr->_file_stat = 1;
+              }else{
+                  status_disable(ptr);
+                  ptr->_file_stat = -1;
+              }
+          }else if (ptr->_file_stat > 0){
+              ptr->stat = 1;
+              status_push_ch(ptr, c);
+          }else if (ptr->_file_stat < 0){
+              status_disable(ptr);
+          }
+          break;
+
+      case 1:
+          if (c == EOF){
+              status_disable(ptr);
+              ptr->_file_stat = -1;
+          }else{
+              status_push_ch(ptr, c);
+              status_reset(ptr);
+          }
+          break;
+
+      case 0xfe:
+      case 0xff:
+          if (ptr->stat != c && (c == 0xfe || c == 0xff)){
+              status_push_ch(ptr, c);
+              status_reset(ptr);
+          }else{
+              status_disable(ptr);
+              ptr->_file_stat = -1;
+          }
+          break;
+    }
+}
+
 void w_status(ptr, c)
      struct input_code *ptr;
      int c;
@@ -1318,7 +1456,7 @@ code_status(c)
     }
 
     if (action_flag){
-        if (result){
+        if (result && !estab_f){
             set_iconv(TRUE, result->iconv_func);
         }else if (c <= DEL){
             struct input_code *ptr = input_code_list;
@@ -1330,10 +1468,21 @@ code_status(c)
     }
 }
 
+#ifdef PERL_XS
+#define STD_GC_BUFSIZE (256)
+int std_gc_buf[STD_GC_BUFSIZE];
+int std_gc_ndx;
+#endif
+
 int 
 std_getc(f)
 FILE *f;
 {
+#ifdef PERL_XS
+    if (std_gc_ndx){
+        return std_gc_buf[--std_gc_ndx];
+    }
+#endif
     return getc(f);
 }
 
@@ -1342,6 +1491,13 @@ std_ungetc(c,f)
 int c;
 FILE *f;
 {
+#ifdef PERL_XS
+    if (std_gc_ndx == STD_GC_BUFSIZE){
+        return EOF;
+    }
+    std_gc_buf[std_gc_ndx++] = c;
+    return c;
+#endif
     return ungetc(c,f);
 }
 
@@ -1410,7 +1566,7 @@ module_connection()
 
     i_getc = std_getc;
     /* input redicrection */
-#ifdef CAP_URL_OPTION
+#ifdef INPUT_OPTION
     if (cap_f){
         i_cgetc = i_getc; i_getc = cap_getc;
         i_cungetc = i_ungetc; i_ungetc= cap_ungetc;
@@ -1419,6 +1575,10 @@ module_connection()
         i_ugetc = i_getc; i_getc = url_getc;
         i_uungetc = i_ungetc; i_ungetc= url_ungetc;
     }
+    if (numchar_f){
+        i_ngetc = i_getc; i_getc = numchar_getc;
+        i_nungetc = i_ungetc; i_ungetc= numchar_ungetc;
+    }
 #endif
     if (mime_f && mimebuf_f==FIXED_MIME) {
        i_mgetc = i_getc; i_getc = mime_getc;
@@ -1445,7 +1605,7 @@ module_connection()
     {
         struct input_code *p = input_code_list;
         while (p->name){
-            status_reset(p++);
+            status_reinit(p++);
         }
     }
 }
@@ -1829,6 +1989,15 @@ int s2e_conv(c2, c1, p2, p1)
      int c2, c1;
      int *p2, *p1;
 {
+#ifdef SHIFTJIS_CP932
+    if (CP932_TABLE_BEGIN <= c2 && c2 <= CP932_TABLE_END){
+        extern unsigned short shiftjis_cp932[3][189];
+        c1 = shiftjis_cp932[c2 - CP932_TABLE_BEGIN][c1 - 0x40];
+        if (c1 == 0) return 1;
+        c2 = c1 >> 8;
+        c1 &= 0xff;
+    }
+#endif /* SHIFTJIS_CP932 */
     c2 = c2 + c2 - ((c2 <= 0x9f) ? SJ0162 : SJ6394);
     if (c1 < 0x9f)
         c1 = c1 - ((c1 > DEL) ? SPACE : 0x1f);
@@ -1838,7 +2007,7 @@ int s2e_conv(c2, c1, p2, p1)
     }
     if (p2) *p2 = c2;
     if (p1) *p1 = c1;
-    return (c2 << 8) | c1;
+    return 0;
 }
 
 int
@@ -1851,7 +2020,8 @@ s_iconv(c2, c1, c0)
     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
         /* NOP */
     } else {
-        s2e_conv(c2, c1, &c2, &c1);
+        int ret = s2e_conv(c2, c1, &c2, &c1);
+        if (ret) return ret;
     }
     (*oconv)(c2, c1);
     return 0;
@@ -1864,6 +2034,9 @@ e_iconv(c2, c1, c0)
 {
     if (c2 == X0201) {
        c1 &= 0x7f;
+    } else if (c2 == SSO){
+        c2 = X0201;
+        c1 &= 0x7f;
     } else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
         /* NOP */
     } else {
@@ -1913,15 +2086,56 @@ w_iconv(c2, c1, c0)
     return ret;
 }
 
+void
+w16w_conv(val, p2, p1, p0)
+     unsigned short val;
+     int *p2, *p1, *p0;
+{
+    if (val < 0x80){
+        *p2 = val;
+        *p1 = 0;
+        *p0 = 0;
+    }else if (val < 0x800){
+       *p2 = 0xc0 | (val >> 6);
+       *p1 = 0x80 | (val & 0x3f);
+        *p0 = 0;
+    }else{
+        *p2 = 0xe0 | (val >> 12);
+        *p1 = 0x80 | ((val >> 6) & 0x3f);
+        *p0 = 0x80 | (val        & 0x3f);
+    }
+}
+
 int
-w_iconv16(c2, c1, c0)
-    int    c2, c1,c0;
+w16e_conv(val, p2, p1)
+     unsigned short val;
+     int *p2, *p1;
 {
     extern unsigned short * utf8_to_euc_2bytes[];
     extern unsigned short ** utf8_to_euc_3bytes[];
+    int c2, c1, c0;
     unsigned short **pp;
-    unsigned short val;
     int psize;
+
+    w16w_conv(val, &c2, &c1, &c0);
+    if (c1){
+        if (c0){
+            pp = utf8_to_euc_3bytes[c2 - 0x80];
+            psize = sizeof_utf8_to_euc_C2;
+            return w_iconv_common(c1, c0, pp, psize, p2, p1);
+        }else{
+            pp = utf8_to_euc_2bytes;
+            psize = sizeof_utf8_to_euc_2bytes;
+            return w_iconv_common(c2, c1, pp, psize, p2, p1);
+        }
+    }
+    return val;
+}
+
+int
+w_iconv16(c2, c1, c0)
+    int    c2, c1,c0;
+{
     int ret;
 
     if (c2==0376 && c1==0377){
@@ -1935,29 +2149,11 @@ w_iconv16(c2, c1, c0)
        int tmp;
        tmp=c1; c1=c2; c2=tmp;
     }
-    if (c2==0 || c2==EOF) {
+    if ((c2==0 && c1 < 0x80) || c2==EOF) {
        (*oconv)(c2, c1);
        return 0;
     }
-    val = ((c2<<8)&0xff00) + c1;
-    if (c2 < 0x8){
-       c0 = (0x80 | (c1 & 0x3f));
-       c1 = (0xc0 | (val >> 6));
-       pp = utf8_to_euc_2bytes;
-        psize = sizeof_utf8_to_euc_2bytes;
-    }else{
-       c0 = (0x80 | (c1 & 0x3f));
-       c2 = (0xe0 | (val >> 12));
-       c1 = (0x80 | ((val >> 6) & 0x3f));
-       if (c0 == 0) return -1;
-       if (0<=c2-0x80 && c2-0x80 <sizeof_utf8_to_euc_3bytes){
-           pp = utf8_to_euc_3bytes[c2 - 0x80];
-            psize = sizeof_utf8_to_euc_C2;
-        }else{
-           return 0;
-        }
-    }
-    ret = w_iconv_common(c1, c0, pp, psize, &c2, &c1);
+    ret = w16e_conv(((c2<<8)&0xff00) + c1, &c2, &c1);
     if (ret) return ret;
     (*oconv)(c2, c1);
     return 0;
@@ -2058,25 +2254,36 @@ w_oconv16(c2, c1)
     int    c2,
                     c1;
 {
-    
-    if (w_oconv16_begin_f==2) {
-       (*o_putc)('\376');
-       (*o_putc)('\377');
-       w_oconv16_begin_f=1;
-    }
     if (c2 == EOF) {
         (*o_putc)(EOF);
         return;
-    } else if (c2 == 0) { 
-        (*o_putc)(0);
-        (*o_putc)(c1);
-    } else if (c2 == ISO8859_1) {
-        (*o_putc)(0);
-        (*o_putc)(c1 | 0x080);
-    } else {
+    }    
+
+    if (w_oconv16_begin_f==2) {
+        if (w_oconv16_LE){
+            (*o_putc)((unsigned char)'\377');
+            (*o_putc)('\376');
+        }else{
+            (*o_putc)('\376');
+            (*o_putc)((unsigned char)'\377');
+        }
+       w_oconv16_begin_f=1;
+    }
+
+    if (c2 == ISO8859_1) {
+        c2 = 0;
+        c1 |= 0x80;
+    } else if (c2) {
         unsigned short val = (unsigned short)e2w_conv(c2, c1);
-        (*o_putc)((val&0xff00)>>8);
-        (*o_putc)(val&0xff);
+        c2 = (val >> 8) & 0xff;
+        c1 = val & 0xff;
+    }
+    if (w_oconv16_LE){
+        (*o_putc)(c1);
+        (*o_putc)(c2);
+    }else{
+        (*o_putc)(c2);
+        (*o_putc)(c1);
     }
 }
 
@@ -2111,7 +2318,13 @@ e_oconv(c2, c1)
     }
 }
 
-
+void
+e2s_conv(c2, c1, p2, p1)
+     int c2, c1, *p2, *p1;
+{
+    if (p2) *p2 = ((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1);
+    if (p1) *p1 = c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
+}
 
 void
 s_oconv(c2, c1)
@@ -2137,8 +2350,9 @@ s_oconv(c2, c1)
             return; /* too late to rescue this char */
         }
        output_mode = SHIFT_JIS;
-        (*o_putc)((((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1)));
-        (*o_putc)((c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e)));
+        e2s_conv(c2, c1, &c2, &c1);
+        (*o_putc)(c2);
+        (*o_putc)(c1);
     }
 }
 
@@ -2320,19 +2534,27 @@ int c2,c1;
     int prev0;
     int fold_state=0;
 
-    if (c1== '\r') {
-       fold_state=0;  /* ignroe cr */
+    if (c1== '\r' && !fold_preserve_f) {
+       fold_state=0;  /* ignore cr */
+    }else if (c1== '\n'&&f_prev=='\r' && fold_preserve_f) {
+        f_prev = '\n';
+       fold_state=0;  /* ignore cr */
     } else if (c1== BS) {
         if (f_line>0) f_line--;
         fold_state =  1;
     } else if (c2==EOF && f_line != 0) {    /* close open last line */
             fold_state = '\n';
-    } else if (c1=='\n') {
+    } else if ((c1=='\n' && !fold_preserve_f)
+               || ((c1=='\r'||(c1=='\n'&&f_prev!='\r'))
+                   && fold_preserve_f)) {
         /* new line */
         if (fold_preserve_f) { 
-                f_line = 0;
-                fold_state =  '\r';
-       } else if (f_prev == c1) {        /* duplicate newline */
+            f_prev = c1;
+            f_line = 0;
+            fold_state =  '\r';
+       } else if ((f_prev == c1 && !fold_preserve_f)
+                   || (f_prev == '\n' && fold_preserve_f)
+                   ) {        /* duplicate newline */
             if (f_line) {
                 f_line = 0;
                 fold_state =  '\n';    /* output two newline */
@@ -2850,7 +3072,7 @@ void debug(str)
 }
 #endif
 
-#ifdef CAP_URL_OPTION
+#ifdef INPUT_OPTION
 int
 hex2bin(x)
      int x;
@@ -2876,12 +3098,12 @@ hex_getc(ch, f, g, u)
         return c1;
     }
     c2 = (*g)(f);
-    if (!nkf_isxdigit(c2) == EOF){
+    if (!nkf_isxdigit(c2)){
         (*u)(c2, f);
         return c1;
     }
     c3 = (*g)(f);
-    if (!nkf_isxdigit(c3) == EOF){
+    if (!nkf_isxdigit(c3)){
         (*u)(c2, f);
         (*u)(c3, f);
         return c1;
@@ -2918,6 +3140,91 @@ url_ungetc(c, f)
 {
     return (*i_uungetc)(c, f);
 }
+
+int
+numchar_getc(f)
+     FILE *f;
+{
+    int (*g)() = i_ngetc;
+    int (*u)() = i_nungetc;
+    int i = 0, j;
+    int 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 < 5; 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 < 6; 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){
+        int c2, c1, c0;
+        if (c < 0x80){
+            return c;
+        }
+        if (0x100 <= c){
+            w16w_conv(c, &c2, &c1, &c0);
+            if (iconv == w_iconv){
+                if (c0){
+                    (*u)(c0, f);
+                }
+                (*u)(c1, f);
+                return c2;
+            }
+            if (w2e_conv(c2, c1, c0, &c2, &c1) == 0){
+                c2 |= 0x80;
+                c1 |= 0x80;
+                if (iconv == s_iconv){
+                    e2s_conv(c2, c1, &c2, &c1);
+                }
+                (*u)(c1, f);
+                return c2;
+            }
+        }
+    }
+    while (i > 0){
+        (*u)(buf[i], f);
+        --i;
+    }
+    return buf[0];
+}
+
+int
+numchar_ungetc(c, f)
+     int c;
+     FILE *f;
+{
+    return (*i_nungetc)(c, f);
+}
 #endif
 
 
@@ -3320,13 +3627,12 @@ reinit()
     option_mode = 0;
     crmode_f = 0;
 
-    e_stat = 0;
-    s_stat = 0;
-#ifdef UTF8_INPUT_ENABLE
-    w_stat = 0;
-#else
-    w_stat = -1;
-#endif
+    {
+        struct input_code *p = input_code_list;
+        while (p->name){
+            status_reinit(p++);
+        }
+    }
 #ifdef UTF8_OUTPUT_ENABLE
     if (w_oconv16_begin_f) {
        w_oconv16_begin_f = 2;
@@ -3411,13 +3717,13 @@ void
 version()
 {
     fprintf(stderr,"Network Kanji Filter Version %s (%s) "
-#if defined(MSDOS) && !defined(_Windows)
+#if defined(MSDOS) && !defined(__WIN32__) && !defined(__WIN16__)
                   "for DOS"
 #endif
-#if !defined(__WIN32__) && defined(_Windows)
+#if defined(MSDOS) && defined(__WIN16__)
                   "for Win16"
 #endif
-#if defined(__WIN32__) && defined(_Windows)
+#if defined(MSDOS) && defined(__WIN32__)
                   "for Win32"
 #endif
 #ifdef __OS2__
@@ -3440,8 +3746,6 @@ version()
  **  kono@ie.u-ryukyu.ac.jp (Shinji Kono)
  **  GHG00637@nifty-serve.or.jp (COW)
  **
- ** \e$B:G=*99?7F|\e(B
- **  2002.9.24
  **/
 
 /* end */