OSDN Git Service

Release 2.1.0.
[nkf/nkf.git] / nkf.c
diff --git a/nkf.c b/nkf.c
index 993daba..9e52ce3 100644 (file)
--- a/nkf.c
+++ b/nkf.c
@@ -1,42 +1,30 @@
-/** Network Kanji Filter. (PDS Version)
- ** -*- coding: ISO-2022-JP -*-
- ************************************************************************
- ** Copyright (C) 1987, Fujitsu LTD. (Itaru ICHIKAWA)
- ** \e$BO"Mm@h!'\e(B \e$B!J3t!KIY;NDL8&5f=j!!%=%U%H#38&!!;T@n!!;j\e(B
- ** \e$B!J\e(BE-Mail Address: ichikawa@flab.fujitsu.co.jp\e$B!K\e(B
- ** Copyright (C) 1996,1998
- ** Copyright (C) 2002
- ** \e$BO"Mm@h!'\e(B \e$BN05eBg3X>pJs9)3X2J\e(B \e$B2OLn\e(B \e$B??<#\e(B  mime/X0208 support
- ** \e$B!J\e(BE-Mail Address: kono@ie.u-ryukyu.ac.jp\e$B!K\e(B
- ** \e$BO"Mm@h!'\e(B COW for DOS & Win16 & Win32 & OS/2
- ** \e$B!J\e(BE-Mail Address: GHG00637@niftyserve.or.p\e$B!K\e(B
- **
- **    \e$B$3$N%=!<%9$N$$$+$J$kJ#<L!$2~JQ!$=$@5$b5vBz$7$^$9!#$?$@$7!"\e(B
- **    \e$B$=$N:]$K$O!"C/$,9W8%$7$?$r<($9$3$NItJ,$r;D$9$3$H!#\e(B
- **    \e$B:FG[I[$d;(;o$NIUO?$J$I$NLd$$9g$o$;$bI,MW$"$j$^$;$s!#\e(B
- **    \e$B1DMxMxMQ$b>e5-$KH?$7$J$$HO0O$G5v2D$7$^$9!#\e(B
- **    \e$B%P%$%J%j$NG[I[$N:]$K$O\e(Bversion message\e$B$rJ]B8$9$k$3$H$r>r7o$H$7$^$9!#\e(B
- **    \e$B$3$N%W%m%0%i%`$K$D$$$F$OFC$K2?$NJ]>Z$b$7$J$$!"0-$7$+$i$:!#\e(B
- **
- **    Everyone is permitted to do anything on this program
- **    including copying, modifying, improving,
- **    as long as you don't try to pretend that you wrote it.
- **    i.e., the above copyright notice has to appear in all copies.
- **    Binary distribution requires original version messages.
- **    You don't have to ask before copying, redistribution or publishing.
- **    THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.
- ***********************************************************************/
-
-/***********************************************************************
- * \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.191 2008/11/09 21:10:04 naruse Exp $"
-#define NKF_VERSION "2.0.8"
-#define NKF_RELEASE_DATE "2008-11-10"
+/*
+ * Copyright (c) 1987, Fujitsu LTD. (Itaru ICHIKAWA).
+ * Copyright (c) 1996-2009, The nkf Project.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+#define NKF_VERSION "2.1.0"
+#define NKF_RELEASE_DATE "2009-11-17"
 #define COPY_RIGHT \
-    "Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa),2000 S. Kono, COW\n" \
-    "Copyright (C) 2002-2008 Kono, Furukawa, Naruse, mastodon"
+    "Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa).\n" \
+    "Copyright (C) 1996-2009, The nkf Project."
 
 #include "config.h"
 #include "nkf.h"
@@ -52,6 +40,7 @@
 #endif
 #include <assert.h>
 
+
 /* state of output_mode and input_mode
 
    c2           0 means ASCII
@@ -140,7 +129,7 @@ enum nkf_encodings {
     JIS_X_0212        = 0x1159, /* D */
     /* JIS_X_0213_2000_1 = 0x1228, */ /* O */
     JIS_X_0213_2 = 0x1229, /* P */
-    JIS_X_0213_1 = 0x1233, /* Q */
+    JIS_X_0213_1 = 0x1233 /* Q */
 };
 
 static nkf_char s_iconv(nkf_char c2, nkf_char c1, nkf_char c0);
@@ -306,7 +295,7 @@ struct {
                               && (c != '(') && (c != ')') && (c != '.') && (c != 0x22)))
 
 #define is_ibmext_in_sjis(c2) (CP932_TABLE_BEGIN <= c2 && c2 <= CP932_TABLE_END)
-#define nkf_byte_jisx0201_katakana_p(c) (SP <= c && c < (0xE0&0x7F))
+#define nkf_byte_jisx0201_katakana_p(c) (SP <= c && c <= 0x5F)
 
 #define         HOLD_SIZE       1024
 #if defined(INT_IS_SHORT)
@@ -479,6 +468,8 @@ struct input_code input_code_list[] = {
     {"Shift_JIS", 0, 0, 0, {0, 0, 0}, s_status, s_iconv, 0},
 #ifdef UTF8_INPUT_ENABLE
     {"UTF-8",     0, 0, 0, {0, 0, 0}, w_status, w_iconv, 0},
+    {"UTF-16",     0, 0, 0, {0, 0, 0}, NULL, w_iconv16, 0},
+    {"UTF-32",     0, 0, 0, {0, 0, 0}, NULL, w_iconv32, 0},
 #endif
     {0}
 };
@@ -512,7 +503,7 @@ static nkf_char
 no_connection2(nkf_char c2, nkf_char c1, nkf_char c0)
 {
     fprintf(stderr,"nkf internal module connection failure.\n");
-    exit(1);
+    exit(EXIT_FAILURE);
     return 0; /* LINT */
 }
 
@@ -660,12 +651,8 @@ static nkf_char prev_cr = 0; /* CR or 0 */
 static int             end_check;
 #endif /*Easy Win */
 
-#define STD_GC_BUFSIZE (256)
-nkf_char std_gc_buf[STD_GC_BUFSIZE];
-nkf_char std_gc_ndx;
-
 static void *
-nkf_malloc(size_t size)
+nkf_xmalloc(size_t size)
 {
     void *ptr;
 
@@ -681,7 +668,7 @@ nkf_malloc(size_t size)
 }
 
 static void *
-nkf_realloc(void *ptr, size_t size)
+nkf_xrealloc(void *ptr, size_t size)
 {
     if (size == 0) size = 1;
 
@@ -694,7 +681,7 @@ nkf_realloc(void *ptr, size_t size)
     return ptr;
 }
 
-#define nkf_free(ptr) free(ptr)
+#define nkf_xfree(ptr) free(ptr)
 
 static int
 nkf_str_caseeql(const char *src, const char *target)
@@ -756,22 +743,15 @@ nkf_enc_find(const char *name)
                                nkf_enc_to_index(enc) == CP50222)
 
 #ifdef DEFAULT_CODE_LOCALE
-static char*
+static const char*
 nkf_locale_charmap()
 {
 #ifdef HAVE_LANGINFO_H
     return nl_langinfo(CODESET);
 #elif defined(__WIN32__)
-    char buf[16];
-    char *str;
-    int len = sprintf(buf, "CP%d", GetACP());
-    if (len > 0) {
-      str = nkf_malloc(len + 1);
-      strcpy(str, buf);
-      str[len] = '\0';
-      return str;
-    }
-    else return NULL;
+    static char buf[16];
+    sprintf(buf, "CP%d", GetACP());
+    return buf;
 #elif defined(__OS2__)
 # if defined(INT_IS_SHORT)
     /* OS/2 1.x */
@@ -787,16 +767,15 @@ nkf_locale_charmap()
         sprintf(buf, "CP%lu", ulCP[0]);
     return buf;
 # endif
-#else
-    return NULL;
 #endif
+    return NULL;
 }
 
 static nkf_encoding*
 nkf_locale_encoding()
 {
     nkf_encoding *enc = 0;
-    char *encname = nkf_locale_charmap();
+    const char *encname = nkf_locale_charmap();
     if (encname)
        enc = nkf_enc_find(encname);
     return enc;
@@ -822,6 +801,64 @@ nkf_default_encoding()
     return enc;
 }
 
+typedef struct {
+    long capa;
+    long len;
+    nkf_char *ptr;
+} nkf_buf_t;
+
+static nkf_buf_t *
+nkf_buf_new(int length)
+{
+    nkf_buf_t *buf = nkf_xmalloc(sizeof(nkf_buf_t));
+    buf->ptr = nkf_xmalloc(length);
+    buf->capa = length;
+    buf->len = 0;
+    return buf;
+} 
+
+#if 0
+static void
+nkf_buf_dispose(nkf_buf_t *buf)
+{
+    nkf_xfree(buf->ptr);
+    nkf_xfree(buf);
+}
+#endif
+
+#define nkf_buf_length(buf) ((buf)->len)
+#define nkf_buf_empty_p(buf) ((buf)->len == 0)
+
+static unsigned char
+nkf_buf_at(nkf_buf_t *buf, int index)
+{
+    assert(index <= buf->len);
+    return buf->ptr[index];
+}
+
+static void
+nkf_buf_clear(nkf_buf_t *buf)
+{
+    buf->len = 0;
+}
+
+static void
+nkf_buf_push(nkf_buf_t *buf, nkf_char c)
+{
+    if (buf->capa <= buf->len) {
+       exit(EXIT_FAILURE);
+    }
+    buf->ptr[buf->len++] = c;
+}
+
+static unsigned char
+nkf_buf_pop(nkf_buf_t *buf)
+{
+    assert(!nkf_buf_empty_p(buf));
+    return buf->ptr[--buf->len];
+}
+
+/* Normalization Form C */
 #ifndef PERL_XS
 #ifdef WIN32DLL
 #define fprintf dllprintf
@@ -837,68 +874,61 @@ static 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"
+           "Usage:  nkf -[flags] [--] [in file] .. [out file for -O flag]\n"
 #ifdef UTF8_OUTPUT_ENABLE
-           "         After 'w' you can add more options. -w[ 8 [0], 16 [[BL] [0]] ]\n"
+           " j/s/e/w  Specify output encoding ISO-2022-JP, Shift_JIS, EUC-JP\n"
+           "          UTF options is -w[8[0],{16,32}[{B,L}[0]]]\n"
+#else
 #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"
-#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"
+           " J/S/E/W  Specify input encoding ISO-2022-JP, Shift_JIS, EUC-JP\n"
+           "          UTF option is -W[8,[16,32][B,L]]\n"
+#else
+           " J/S/E    Specify output encoding ISO-2022-JP, Shift_JIS, EUC-JP\n"
 #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"
+           );
+    fprintf(HELP_OUTPUT,
+           " m[BQSN0] MIME decode [B:base64,Q:quoted,S:strict,N:nonstrict,0:no decode]\n"
+           " M[BQ]    MIME encode [B:base64 Q:quoted]\n"
+           " f/F      Folding: -f60 or -f or -f60-10 (fold margin 10) F preserve nl\n"
+           );
+    fprintf(HELP_OUTPUT,
+           " 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"
+           );
+    fprintf(HELP_OUTPUT,
+           " O        Output to File (DEFAULT 'nkf.out')\n"
+           " L[uwm]   Line mode u:LF w:CRLF m:CR (DEFAULT noconversion)\n"
+           );
+    fprintf(HELP_OUTPUT,
+           " --ic=<encoding>        Specify the input encoding\n"
+           " --oc=<encoding>        Specify the output encoding\n"
+           " --hiragana --katakana  Hiragana/Katakana Conversion\n"
+           " --katakana-hiragana    Converts each other\n"
+           );
+    fprintf(HELP_OUTPUT,
 #ifdef INPUT_OPTION
-           " --cap-input, --url-input  Convert hex after ':' or '%%'\n"
+           " --{cap, url}-input     Convert hex after ':' or '%%'\n"
 #endif
 #ifdef NUMCHAR_OPTION
-           " --numchar-input   Convert Unicode Character Reference\n"
+           " --numchar-input        Convert Unicode Character Reference\n"
 #endif
 #ifdef UTF8_INPUT_ENABLE
            " --fb-{skip, html, xml, perl, java, subchar}\n"
-           "                   Specify how nkf handles unassigned characters\n"
+           "                        Specify unassigned character's replacement\n"
 #endif
+           );
+    fprintf(HELP_OUTPUT,
 #ifdef OVERWRITE
-           " --in-place[=SUFFIX]  --overwrite[=SUFFIX]\n"
-           "                   Overwrite original listed files by filtered result\n"
-           "                   --overwrite preserves timestamp of original files\n"
+           " --in-place[=SUF]       Overwrite original files\n"
+           " --overwrite[=SUF]      Preserve 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");
+           " -g --guess             Guess the input code\n"
+           " -v --version           Print the version\n"
+           " --help/-V              Print this help / configuration\n"
+           );
     version();
 }
 
@@ -907,8 +937,6 @@ 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"
           );
@@ -970,7 +998,7 @@ get_backup_filename(const char *suffix, const char *filename)
     }
 
     if(asterisk_count){
-       backup_filename = nkf_malloc(strlen(suffix) + (asterisk_count * (filename_length - 1)) + 1);
+       backup_filename = nkf_xmalloc(strlen(suffix) + (asterisk_count * (filename_length - 1)) + 1);
        for(i = 0, j = 0; suffix[i];){
            if(suffix[i] == '*'){
                backup_filename[j] = '\0';
@@ -984,7 +1012,7 @@ get_backup_filename(const char *suffix, const char *filename)
        backup_filename[j] = '\0';
     }else{
        j = filename_length + strlen(suffix);
-       backup_filename = nkf_malloc(j + 1);
+       backup_filename = nkf_xmalloc(j + 1);
        strcpy(backup_filename, filename);
        strcat(backup_filename, suffix);
        backup_filename[j] = '\0';
@@ -1098,7 +1126,7 @@ static const struct {
     {"euc","e"},
     {"euc-input","E"},
     {"fj","jm"},
-    {"help","v"},
+    {"help",""},
     {"jis","j"},
     {"jis-input","J"},
     {"mac","sLm"},
@@ -1108,7 +1136,7 @@ static const struct {
     {"sjis","s"},
     {"sjis-input","S"},
     {"unix","eLu"},
-    {"version","V"},
+    {"version","v"},
     {"windows","sLw"},
     {"hiragana","h1"},
     {"katakana","h2"},
@@ -1178,6 +1206,7 @@ set_input_encoding(nkf_encoding *enc)
     case CP50220:
     case CP50221:
     case CP50222:
+       x0201_f = TRUE;
 #ifdef SHIFTJIS_CP932
        cp51932_f = TRUE;
 #endif
@@ -1199,6 +1228,7 @@ set_input_encoding(nkf_encoding *enc)
     case SHIFT_JIS:
        break;
     case WINDOWS_31J:
+       x0201_f = TRUE;
 #ifdef SHIFTJIS_CP932
        cp51932_f = TRUE;
 #endif
@@ -1220,6 +1250,7 @@ set_input_encoding(nkf_encoding *enc)
     case EUCJP_NKF:
        break;
     case CP51932:
+       x0201_f = TRUE;
 #ifdef SHIFTJIS_CP932
        cp51932_f = TRUE;
 #endif
@@ -1299,6 +1330,7 @@ set_output_encoding(nkf_encoding *enc)
 #endif
        break;
     case CP50221:
+       x0201_f = TRUE;
 #ifdef SHIFTJIS_CP932
        if (cp932inv_f == TRUE) cp932inv_f = FALSE;
 #endif
@@ -1306,6 +1338,11 @@ set_output_encoding(nkf_encoding *enc)
        ms_ucs_map_f = UCS_MAP_CP932;
 #endif
        break;
+    case ISO_2022_JP:
+#ifdef SHIFTJIS_CP932
+       if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+       break;
     case ISO_2022_JP_1:
        x0212_f = TRUE;
 #ifdef SHIFTJIS_CP932
@@ -1322,6 +1359,7 @@ set_output_encoding(nkf_encoding *enc)
     case SHIFT_JIS:
        break;
     case WINDOWS_31J:
+       x0201_f = TRUE;
 #ifdef UTF8_OUTPUT_ENABLE
        ms_ucs_map_f = UCS_MAP_CP932;
 #endif
@@ -1350,6 +1388,7 @@ set_output_encoding(nkf_encoding *enc)
 #endif
        break;
     case CP51932:
+       x0201_f = TRUE;
 #ifdef SHIFTJIS_CP932
        if (cp932inv_f == TRUE) cp932inv_f = FALSE;
 #endif
@@ -1400,6 +1439,7 @@ set_output_encoding(nkf_encoding *enc)
        output_endian = ENDIAN_LITTLE;
        output_bom_f = TRUE;
        break;
+    case UTF_32:
     case UTF_32BE_BOM:
        output_bom_f = TRUE;
        break;
@@ -1626,7 +1666,7 @@ nkf_unicode_to_utf8(nkf_char val, nkf_char *p1, nkf_char *p2, nkf_char *p3, nkf_
        *p3 = 0x80 | ( val        & 0x3f);
        *p4 = 0;
     } else if (nkf_char_unicode_value_p(val)) {
-       *p1 = 0xe0 |  (val >> 16);
+       *p1 = 0xf0 |  (val >> 18);
        *p2 = 0x80 | ((val >> 12) & 0x3f);
        *p3 = 0x80 | ((val >>  6) & 0x3f);
        *p4 = 0x80 | ( val        & 0x3f);
@@ -2626,25 +2666,25 @@ w_oconv32(nkf_char c2, nkf_char c1)
 }
 #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_L2       (1)                   /* Kanji Level 2 */
+#define SCORE_KANA     (SCORE_L2 << 1)       /* Halfwidth Katakana */
+#define SCORE_DEPEND   (SCORE_KANA << 1)     /* MD Characters */
+#define SCORE_CP932    (SCORE_DEPEND << 1)   /* 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_NO_EXIST (SCORE_X0212 << 1)    /* Undefined Characters */
+#define SCORE_iMIME    (SCORE_NO_EXIST << 1) /* MIME selected */
+#define SCORE_ERROR    (SCORE_iMIME << 1) /* Error */
 
 #define SCORE_INIT (SCORE_iMIME)
 
-static const char score_table_A0[] = {
+static const nkf_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[] = {
+static const nkf_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,
@@ -2953,12 +2993,42 @@ code_status(nkf_char c)
     }
 }
 
+typedef struct {
+    nkf_buf_t *std_gc_buf;
+    nkf_char broken_state;
+    nkf_buf_t *broken_buf;
+    nkf_char mimeout_state;
+    nkf_buf_t *nfc_buf;
+} nkf_state_t;
+
+static nkf_state_t *nkf_state = NULL;
+
+#define STD_GC_BUFSIZE (256)
+
+static void
+nkf_state_init(void)
+{
+    if (nkf_state) {
+       nkf_buf_clear(nkf_state->std_gc_buf);
+       nkf_buf_clear(nkf_state->broken_buf);
+       nkf_buf_clear(nkf_state->nfc_buf);
+    }
+    else {
+       nkf_state = nkf_xmalloc(sizeof(nkf_state_t));
+       nkf_state->std_gc_buf = nkf_buf_new(STD_GC_BUFSIZE);
+       nkf_state->broken_buf = nkf_buf_new(3);
+       nkf_state->nfc_buf = nkf_buf_new(9);
+    }
+    nkf_state->broken_state = 0;
+    nkf_state->mimeout_state = 0;
+}
+
 #ifndef WIN32DLL
 static nkf_char
 std_getc(FILE *f)
 {
-    if (std_gc_ndx){
-       return std_gc_buf[--std_gc_ndx];
+    if (!nkf_buf_empty_p(nkf_state->std_gc_buf)){
+       return nkf_buf_pop(nkf_state->std_gc_buf);
     }
     return getc(f);
 }
@@ -2967,10 +3037,7 @@ std_getc(FILE *f)
 static nkf_char
 std_ungetc(nkf_char c, FILE *f)
 {
-    if (std_gc_ndx == STD_GC_BUFSIZE){
-       return EOF;
-    }
-    std_gc_buf[std_gc_ndx++] = c;
+    nkf_buf_push(nkf_state->std_gc_buf, c);
     return c;
 }
 
@@ -3075,18 +3142,16 @@ h_conv(FILE *f, int c1, int c2)
            } else if ((c3 = (*i_getc)(f)) == EOF) {
                ret = EOF;
                break;
-           } else {
-               code_status(c3);
-               if (hold_index < hold_count){
-                   c4 = hold_buf[hold_index++];
-               } else if ((c4 = (*i_getc)(f)) == EOF) {
-                   c3 = ret = EOF;
-                   break;
-               } else {
-                   code_status(c4);
-                   (*iconv)(c1, c2, (c3<<8)|c4);
-               }
            }
+           code_status(c3);
+           if (hold_index < hold_count){
+               c4 = hold_buf[hold_index++];
+           } else if ((c4 = (*i_getc)(f)) == EOF) {
+               c3 = ret = EOF;
+               break;
+           }
+           code_status(c4);
+           (*iconv)(c1, c2, (c3<<8)|c4);
            break;
        case -1:
            /* 3 bytes EUC or UTF-8 */
@@ -3218,65 +3283,41 @@ check_bom(FILE *f)
     }
 }
 
-static struct {
-    int count;
-    nkf_char status;
-    nkf_char buf[3];
-} broken_state;
-
-static void
-init_broken_state(void)
-{
-    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_getc(FILE *f)
 {
     nkf_char c, c1;
 
-    if (broken_state.count > 0) {
-       return pop_broken_buf();
+    if (!nkf_buf_empty_p(nkf_state->broken_buf)) {
+       return nkf_buf_pop(nkf_state->broken_buf);
     }
     c = (*i_bgetc)(f);
-    if (c=='$' && broken_state.status != ESC
+    if (c=='$' && nkf_state->broken_state != ESC
        && (input_mode == ASCII || input_mode == JIS_X_0201_1976_K)) {
        c1= (*i_bgetc)(f);
-       broken_state.status = 0;
+       nkf_state->broken_state = 0;
        if (c1=='@'|| c1=='B') {
-           push_broken_buf(c1);
-           push_broken_buf(c);
+           nkf_buf_push(nkf_state->broken_buf, c1);
+           nkf_buf_push(nkf_state->broken_buf, c);
            return ESC;
        } else {
            (*i_bungetc)(c1,f);
            return c;
        }
-    } else if (c=='(' && broken_state.status != ESC
+    } else if (c=='(' && nkf_state->broken_state != ESC
               && (input_mode == JIS_X_0208 || input_mode == JIS_X_0201_1976_K)) {
        c1= (*i_bgetc)(f);
-       broken_state.status = 0;
+       nkf_state->broken_state = 0;
        if (c1=='J'|| c1=='B') {
-           push_broken_buf(c1);
-           push_broken_buf(c);
+           nkf_buf_push(nkf_state->broken_buf, c1);
+           nkf_buf_push(nkf_state->broken_buf, c);
            return ESC;
        } else {
            (*i_bungetc)(c1,f);
            return c;
        }
     } else {
-       broken_state.status = c;
+       nkf_state->broken_state = c;
        return c;
     }
 }
@@ -3284,8 +3325,8 @@ broken_getc(FILE *f)
 static nkf_char
 broken_ungetc(nkf_char c, FILE *f)
 {
-    if (broken_state.count < 2)
-       push_broken_buf(c);
+    if (nkf_buf_length(nkf_state->broken_buf) < 2)
+       nkf_buf_push(nkf_state->broken_buf, c);
     return c;
 }
 
@@ -3386,9 +3427,7 @@ fold_conv(nkf_char c2, nkf_char c1)
        f_prev = LF;
        f_line = 0;
        fold_state =  LF;            /* output newline and clear */
-    } else if ( (c2==0  && c1==SP)||
-              (c2==0  && c1==TAB)||
-              (c2=='!'&& c1=='!')) {
+    } else if ((c2==0 && nkf_isblank(c1)) || (c2 == '!' && c1 == '!')) {
        /* X0208 kankaku or ascii space */
        if (f_prev == SP) {
            fold_state = 0;         /* remove duplicate spaces */
@@ -3586,7 +3625,7 @@ z_conv(nkf_char c2, nkf_char c1)
     if (alpha_f & 16) {
        /* JIS X 0208 Katakana to JIS X 0201 Katakana */
        if (c2 == 0x21) {
-           char c = 0;
+           nkf_char c = 0;
            switch (c1) {
            case 0x23:
                /* U+3002 (0x8142) Ideographic Full Stop -> U+FF61 (0xA1) Halfwidth Ideographic Full Stop */
@@ -4226,91 +4265,36 @@ numchar_ungetc(nkf_char c, FILE *f)
 
 #ifdef UNICODE_NORMALIZATION
 
-typedef struct {
-    unsigned char *ary;
-    int max_length;
-    int count;
-} nkf_ary;
-
-static nkf_ary *
-nkf_ary_new(int length)
-{
-    nkf_ary *ary = nkf_malloc(sizeof(nkf_ary));
-    ary->ary = nkf_malloc(length);
-    ary->max_length = length;
-    ary->count = 0;
-    return ary;
-} 
-
-static void
-nkf_ary_dispose(nkf_ary *ary)
-{
-    nkf_free(ary->ary);
-    nkf_free(ary);
-}
-
-#define nkf_ary_length(ary) ((ary)->count)
-#define nkf_ary_empty_p(ary) ((ary)->count == 0)
-
-static unsigned char
-nkf_ary_at(nkf_ary *ary, int index)
-{
-    assert(index <= ary->count);
-    return ary->ary[index];
-}
-
-static void
-nkf_ary_clear(nkf_ary *ary)
-{
-    ary->count = 0;
-}
-
-static unsigned char
-nkf_ary_push(nkf_ary *ary, nkf_char c)
-{
-    assert(ary->max_length > ary->count);
-    ary->ary[ary->count++] = c;
-    return ary->count;
-}
-
-static unsigned char
-nkf_ary_pop(nkf_ary *ary)
-{
-    assert(0 < ary->count);
-    return ary->ary[--ary->count];
-}
-
-/* Normalization Form C */
 static 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;
-    nkf_ary *buf = nkf_ary_new(9);
+    nkf_buf_t *buf = nkf_state->nfc_buf;
     const unsigned char *array;
     int lower=0, upper=NORMALIZATION_TABLE_LENGTH-1;
     nkf_char c = (*g)(f);
 
     if (c == EOF || c > 0xFF || (c & 0xc0) == 0x80) return c;
 
-    nkf_ary_push(buf, (unsigned char)c);
+    nkf_buf_push(buf, c);
     do {
        while (lower <= upper) {
            int mid = (lower+upper) / 2;
            int len;
            array = normalization_table[mid].nfd;
            for (len=0; len < NORMALIZATION_TABLE_NFD_LENGTH && array[len]; len++) {
-               if (len >= nkf_ary_length(buf)) {
+               if (len >= nkf_buf_length(buf)) {
                    c = (*g)(f);
                    if (c == EOF) {
                        len = 0;
                        lower = 1, upper = 0;
                        break;
                    }
-                   nkf_ary_push(buf, c);
+                   nkf_buf_push(buf, c);
                }
-               if (array[len] != nkf_ary_at(buf, len)) {
-                   if (array[len] < nkf_ary_at(buf, len)) lower = mid + 1;
+               if (array[len] != nkf_buf_at(buf, len)) {
+                   if (array[len] < nkf_buf_at(buf, len)) lower = mid + 1;
                    else  upper = mid - 1;
                    len = 0;
                    break;
@@ -4319,17 +4303,16 @@ nfc_getc(FILE *f)
            if (len > 0) {
                int i;
                array = normalization_table[mid].nfc;
-               nkf_ary_clear(buf);
+               nkf_buf_clear(buf);
                for (i=0; i < NORMALIZATION_TABLE_NFC_LENGTH && array[i]; i++)
-                   nkf_ary_push(buf, array[i]);
+                   nkf_buf_push(buf, array[i]);
                break;
            }
        }
     } while (lower <= upper);
 
-    while (nkf_ary_length(buf) > 1) (*u)(nkf_ary_pop(buf), f);
-    c = nkf_ary_pop(buf);
-    nkf_ary_dispose(buf);
+    while (nkf_buf_length(buf) > 1) (*u)(nkf_buf_pop(buf), f);
+    c = nkf_buf_pop(buf);
 
     return c;
 }
@@ -4405,13 +4388,13 @@ mime_getc(FILE *f)
            /* end Q encoding */
            input_mode = exit_mode;
            lwsp_count = 0;
-           lwsp_buf = nkf_malloc((lwsp_size+5)*sizeof(char));
+           lwsp_buf = nkf_xmalloc((lwsp_size+5)*sizeof(char));
            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)) {
+                       if ((c1=(*i_getc)(f))!=EOF && nkf_isblank(c1)) {
                            i_ungetc(SP,f);
                            continue;
                        } else {
@@ -4420,7 +4403,7 @@ mime_getc(FILE *f)
                        c1 = LF;
                    } else {
                        if ((c1=(*i_getc)(f))!=EOF && c1 == LF) {
-                           if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
+                           if ((c1=(*i_getc)(f))!=EOF && nkf_isblank(c1)) {
                                i_ungetc(SP,f);
                                continue;
                            } else {
@@ -4438,7 +4421,7 @@ mime_getc(FILE *f)
                    lwsp_buf[lwsp_count] = (unsigned char)c1;
                    if (lwsp_count++>lwsp_size){
                        lwsp_size <<= 1;
-                       lwsp_buf_new = nkf_realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
+                       lwsp_buf_new = nkf_xrealloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
                        lwsp_buf = lwsp_buf_new;
                    }
                    continue;
@@ -4451,12 +4434,12 @@ mime_getc(FILE *f)
                    i_ungetc(lwsp_buf[lwsp_count],f);
                c1 = lwsp_buf[0];
            }
-           nkf_free(lwsp_buf);
+           nkf_xfree(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);
+               if (c1 == EOF) return (EOF);
            }
            mime_decode_mode = 'Q'; /* still in MIME */
            goto restart_mime_q;
@@ -4504,13 +4487,13 @@ mime_getc(FILE *f)
     if ((c1 == '?') && (c2 == '=')) {
        input_mode = ASCII;
        lwsp_count = 0;
-       lwsp_buf = nkf_malloc((lwsp_size+5)*sizeof(char));
+       lwsp_buf = nkf_xmalloc((lwsp_size+5)*sizeof(char));
        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)) {
+                   if ((c1=(*i_getc)(f))!=EOF && nkf_isblank(c1)) {
                        i_ungetc(SP,f);
                        continue;
                    } else {
@@ -4522,7 +4505,7 @@ mime_getc(FILE *f)
                        if (c1==SP) {
                            i_ungetc(SP,f);
                            continue;
-                       } else if ((c1=(*i_getc)(f))!=EOF && (c1==SP||c1==TAB)) {
+                       } else if ((c1=(*i_getc)(f))!=EOF && nkf_isblank(c1)) {
                            i_ungetc(SP,f);
                            continue;
                        } else {
@@ -4540,7 +4523,7 @@ mime_getc(FILE *f)
                lwsp_buf[lwsp_count] = (unsigned char)c1;
                if (lwsp_count++>lwsp_size){
                    lwsp_size <<= 1;
-                   lwsp_buf_new = nkf_realloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
+                   lwsp_buf_new = nkf_xrealloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
                    lwsp_buf = lwsp_buf_new;
                }
                continue;
@@ -4553,7 +4536,7 @@ mime_getc(FILE *f)
                i_ungetc(lwsp_buf[lwsp_count],f);
            c1 = lwsp_buf[0];
        }
-       nkf_free(lwsp_buf);
+       nkf_xfree(lwsp_buf);
        return c1;
     }
   mime_c3_retry:
@@ -4600,11 +4583,10 @@ mime_getc(FILE *f)
 static const char basis_64[] =
     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
-#define MIMEOUT_BUF_LENGTH (60)
+#define MIMEOUT_BUF_LENGTH 74
 static struct {
     char buf[MIMEOUT_BUF_LENGTH+1];
     int count;
-    nkf_char state;
 } mimeout_state;
 
 /*nkf_char mime_lastchar2, mime_lastchar1;*/
@@ -4632,15 +4614,12 @@ open_mime(nkf_char mode)
        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)) {
+       if (mimeout_state.count>0 && nkf_isspace(mimeout_state.buf[i])) {
            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) {
+       if (nkf_isspace(mimeout_state.buf[i])) {
            (*o_mputc)(mimeout_state.buf[i]);
            base64_count ++;
        } else {
@@ -4708,13 +4687,13 @@ eof_mime(void)
     case 'B':
        break;
     case 2:
-       (*o_mputc)(basis_64[((mimeout_state.state & 0x3)<< 4)]);
+       (*o_mputc)(basis_64[((nkf_state->mimeout_state & 0x3)<< 4)]);
        (*o_mputc)('=');
        (*o_mputc)('=');
        base64_count += 3;
        break;
     case 1:
-       (*o_mputc)(basis_64[((mimeout_state.state & 0xF) << 2)]);
+       (*o_mputc)(basis_64[((nkf_state->mimeout_state & 0xF) << 2)]);
        (*o_mputc)('=');
        base64_count += 2;
        break;
@@ -4746,19 +4725,19 @@ mimeout_addchar(nkf_char c)
        }
        break;
     case 'B':
-       mimeout_state.state=c;
+       nkf_state->mimeout_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;
+       (*o_mputc)(basis_64[((nkf_state->mimeout_state & 0x3)<< 4) | ((c & 0xF0) >> 4)]);
+       nkf_state->mimeout_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[((nkf_state->mimeout_state & 0xF) << 2) | ((c & 0xC0) >>6)]);
        (*o_mputc)(basis_64[c & 0x3F]);
        mimeout_mode='B';
        base64_count += 2;
@@ -4910,11 +4889,36 @@ mime_putc(nkf_char c)
                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++;
+                   static const char *str = "boundary=\"";
+                   static int len = 10;
+                   i = 0;
+
+                   for (; i < mimeout_state.count - len; ++i) {
+                       if (!strncmp(mimeout_state.buf+i, str, len)) {
+                           i += len - 2;
+                           break;
+                       }
+                   }
+
+                   if (i == 0 || i == mimeout_state.count - len) {
+                       PUT_NEWLINE((*o_mputc));
+                       base64_count = 0;
+                       if (!nkf_isspace(mimeout_state.buf[0])){
+                           (*o_mputc)(SP);
+                           base64_count++;
+                       }
+                   }
+                   else {
+                       int j;
+                       for (j = 0; j <= i; ++j) {
+                           (*o_mputc)(mimeout_state.buf[j]);
+                       }
+                       PUT_NEWLINE((*o_mputc));
+                       base64_count = 1;
+                       for (; j <= mimeout_state.count; ++j) {
+                           mimeout_state.buf[j - i] = mimeout_state.buf[j];
+                       }
+                       mimeout_state.count -= i;
                    }
                }
                mimeout_state.buf[mimeout_state.count++] = (char)c;
@@ -4961,7 +4965,7 @@ mime_putc(nkf_char c)
                mimeout_state.buf[mimeout_state.count++] = (char)c;
                return;
            }
-           if (c==SP || c==TAB || c==CR || c==LF) {
+           if (nkf_isspace(c)) {
                for (i=0;i<mimeout_state.count;i++) {
                    if (SP<mimeout_state.buf[i] && mimeout_state.buf[i]<DEL) {
                        eof_mime();
@@ -5038,9 +5042,9 @@ nkf_iconv_new(char *tocode, char *fromcode)
     nkf_iconv_t converter;
 
     converter->input_buffer_size = IOBUF_SIZE;
-    converter->input_buffer = nkf_malloc(converter->input_buffer_size);
+    converter->input_buffer = nkf_xmalloc(converter->input_buffer_size);
     converter->output_buffer_size = IOBUF_SIZE * 2;
-    converter->output_buffer = nkf_malloc(converter->output_buffer_size);
+    converter->output_buffer = nkf_xmalloc(converter->output_buffer_size);
     converter->cd = iconv_open(tocode, fromcode);
     if (converter->cd == (iconv_t)-1)
     {
@@ -5107,8 +5111,8 @@ nkf_iconv_convert(nkf_iconv_t *converter, FILE *input)
 static void
 nkf_iconv_close(nkf_iconv_t *convert)
 {
-    nkf_free(converter->inbuf);
-    nkf_free(converter->outbuf);
+    nkf_xfree(converter->inbuf);
+    nkf_xfree(converter->outbuf);
     iconv_close(converter->cd);
 }
 #endif
@@ -5219,7 +5223,6 @@ reinit(void)
     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;
@@ -5227,6 +5230,7 @@ reinit(void)
     input_codename = NULL;
     input_encoding = NULL;
     output_encoding = NULL;
+    nkf_state_init();
 #ifdef WIN32DLL
     reinitdll();
 #endif /*WIN32DLL*/
@@ -5452,6 +5456,12 @@ kanji_convert(FILE *f)
            if (input_mode == JIS_X_0208 && DEL <= c1 && c1 < 0x92) {
                /* CP5022x */
                MORE;
+           }else if (input_codename && input_codename[0] == 'I' &&
+                   0xA1 <= c1 && c1 <= 0xDF) {
+               /* JIS X 0201 Katakana in 8bit JIS */
+               c2 = JIS_X_0201_1976_K;
+               c1 &= 0x7f;
+               SEND;
            } else if (c1 > DEL) {
                /* 8 bit code */
                if (!estab_f && !iso8859_f) {
@@ -5526,7 +5536,7 @@ kanji_convert(FILE *f)
                SKIP;
            } else if (c1 == ESC && (!is_8bit || mime_decode_mode)) {
                if ((c1 = (*i_getc)(f)) == EOF) {
-                   /*  (*oconv)(0, ESC); don't send bogus code */
+                   (*oconv)(0, ESC);
                    LAST;
                }
                else if (c1 == '&') {
@@ -5656,7 +5666,7 @@ kanji_convert(FILE *f)
            } 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 */
+                   (*oconv)(0, ESC);
                    LAST;
                } else if (c1 == '$') {
                    /* J-PHONE emoji */
@@ -5852,6 +5862,12 @@ options(unsigned char *cp)
                cp_back = cp;
                cp = (unsigned char *)long_option[i].alias;
            }else{
+#ifndef PERL_XS
+               if (strcmp(long_option[i].name, "help") == 0){
+                   usage();
+                   exit(EXIT_SUCCESS);
+               }
+#endif
                if (strcmp(long_option[i].name, "ic=") == 0){
                    enc = nkf_enc_find((char *)p);
                    if (!enc) continue;
@@ -5885,8 +5901,7 @@ options(unsigned char *cp)
                    overwrite_f = TRUE;
                    preserve_time_f = TRUE;
                    backup_f = TRUE;
-                   backup_suffix = nkf_malloc(strlen((char *) p) + 1);
-                   strcpy(backup_suffix, (char *) p);
+                   backup_suffix = (char *)p;
                    continue;
                }
                if (strcmp(long_option[i].name, "in-place") == 0){
@@ -5900,8 +5915,7 @@ options(unsigned char *cp)
                    overwrite_f = TRUE;
                    preserve_time_f = FALSE;
                    backup_f = TRUE;
-                   backup_suffix = nkf_malloc(strlen((char *) p) + 1);
-                   strcpy(backup_suffix, (char *) p);
+                   backup_suffix = (char *)p;
                    continue;
                }
 #endif
@@ -6092,7 +6106,7 @@ options(unsigned char *cp)
            output_encoding = nkf_enc_from_index(EUCJP_NKF);
            continue;
        case 's':           /* SJIS output */
-           output_encoding = nkf_enc_from_index(WINDOWS_31J);
+           output_encoding = nkf_enc_from_index(SHIFT_JIS);
            continue;
        case 'l':           /* ISO8859 Latin-1 support, no conversion */
            iso8859_f = TRUE;  /* Only compatible with ISO-2022-JP */
@@ -6102,7 +6116,8 @@ options(unsigned char *cp)
            if (*cp=='@'||*cp=='B')
                kanji_intro = *cp++;
            continue;
-       case 'o':           /* ASCII IN ESC-(-J/B */
+       case 'o':           /* ASCII IN ESC-(-J/B/H */
+           /* ESC ( H was used in initial JUNET messages */
            if (*cp=='J'||*cp=='B'||*cp=='H')
                ascii_intro = *cp++;
            continue;
@@ -6127,11 +6142,11 @@ options(unsigned char *cp)
 #ifndef PERL_XS
        case 'V':
            show_configuration();
-           exit(1);
+           exit(EXIT_SUCCESS);
            break;
        case 'v':
-           usage();
-           exit(1);
+           version();
+           exit(EXIT_SUCCESS);
            break;
 #endif
 #ifdef UTF8_OUTPUT_ENABLE
@@ -6162,9 +6177,6 @@ options(unsigned char *cp)
                    output_endian = ENDIAN_LITTLE;
                } else if (cp[0] == 'B') {
                    cp++;
-               } else {
-                   output_encoding = nkf_enc_from_index(enc_idx);
-                   continue;
                }
                if (cp[0] == '0'){
                    cp++;
@@ -6221,8 +6233,8 @@ options(unsigned char *cp)
        case 'E':   /* EUC-JP input */
            input_encoding = nkf_enc_from_index(EUCJP_NKF);
            continue;
-       case 'S':   /* Windows-31J input */
-           input_encoding = nkf_enc_from_index(WINDOWS_31J);
+       case 'S':   /* Shift_JIS input */
+           input_encoding = nkf_enc_from_index(SHIFT_JIS);
            continue;
        case 'Z':   /* Convert X0208 alphabet to asii */
            /* alpha_f
@@ -6232,10 +6244,10 @@ options(unsigned char *cp)
               bit:3   Convert HTML Entity
               bit:4   Convert JIS X 0208 Katakana to JIS X 0201 Katakana
             */
-           while ('0'<= *cp && *cp <='9') {
+           while ('0'<= *cp && *cp <='4') {
                alpha_f |= 1 << (*cp++ - '0');
            }
-           if (!alpha_f) alpha_f = 1;
+           alpha_f |= 1;
            continue;
        case 'x':   /* Convert X0201 kana to X0208 or X0201 Conversion */
            x0201_f = FALSE;    /* No X0201->X0208 conversion */
@@ -6382,6 +6394,8 @@ main(int argc, char **argv)
 #ifdef DEFAULT_CODE_LOCALE
     setlocale(LC_CTYPE, "");
 #endif
+    nkf_state_init();
+
     for (argc--,argv++; (argc > 0) && **argv == '-'; argc--, argv++) {
        cp = (unsigned char *)*argv;
        options(cp);
@@ -6489,7 +6503,7 @@ main(int argc, char **argv)
                if (file_out_f == TRUE) {
 #ifdef OVERWRITE
                    if (overwrite_f){
-                       outfname = nkf_malloc(strlen(origfname)
+                       outfname = nkf_xmalloc(strlen(origfname)
                                          + strlen(".nkftmpXXXXXX")
                                          + 1);
                        strcpy(outfname, origfname);
@@ -6605,7 +6619,7 @@ main(int argc, char **argv)
                            fprintf(stderr, "Can't rename %s to %s\n",
                                    origfname, backup_filename);
                        }
-                       nkf_free(backup_filename);
+                       nkf_xfree(backup_filename);
                    }else{
 #ifdef MSDOS
                        if (unlink(origfname)){
@@ -6618,7 +6632,7 @@ main(int argc, char **argv)
                        fprintf(stderr, "Can't rename %s to %s\n",
                                outfname, origfname);
                    }
-                   nkf_free(outfname);
+                   nkf_xfree(outfname);
                }
 #endif
            }