DEFAULT_CODE_JIS
/* #define DEFAULT_CODE_SJIS */
/* #define DEFAULT_CODE_EUC */
/******************************/

#if (defined(__TURBOC__) || defined(LSI_C)) && !defined(MSDOS)
#define MSDOS
#endif

#ifndef PERL_XS
#include <stdio.h>
#endif

#if defined(MSDOS) || defined(__OS2__) 
#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#endif

#ifdef MSDOS
#ifdef LSI_C
#define setbinmode(fp) fsetbin(fp)
#else /* Microsoft C, Turbo C */
#define setbinmode(fp) setmode(fileno(fp), O_BINARY)
#endif
#else /* UNIX,OS/2 */
#define setbinmode(fp)
#endif

#ifdef _IOFBF /* SysV and MSDOS */
#define       setvbuffer(fp, buf, size)       setvbuf(fp, buf, _IOFBF, size)
#else /* BSD */
#define       setvbuffer(fp, buf, size)       setbuffer(fp, buf, size)
#endif

/*Borland C++ 4.5 EasyWin*/
#if defined(__TURBOC__) && defined(_Windows) && !defined(__WIN32__) /*Easy Win */
#define         EASYWIN
#include <windows.h>
#endif

#define         FALSE   0
#define         TRUE    1

/* state of output_mode and input_mode  */

#define         ASCII           0
#define         X0208           1
#define         X0201           2
#define         NO_X0201        3
#define         JIS_INPUT       4
#define         SJIS_INPUT      5
#define         LATIN1_INPUT    6
#define         FIXED_MIME      7
#define         DOUBLE_SPACE    -2

#define         NL      0x0a
#define         ESC     0x1b
#define         SPACE   0x20
#define         AT      0x40
#define         SSP     0xa0
#define         DEL     0x7f
#define         SI      0x0f
#define         SO      0x0e
#define         SSO     0x8e

#define         HOLD_SIZE       32
#define         IOBUF_SIZE      16384

#define         DEFAULT_J       'B'
#define         DEFAULT_R       'B'

#define         SJ0162  0x00e1          /* 01 - 62 ku offset */
#define         SJ6394  0x0161          /* 63 - 94 ku offset */


/* MIME preprocessor */

#undef STRICT_MIME       /* do stupid strict mime integrity check */
#define GETC(p) ((!mime_mode)?getc(p):mime_getc(p))
#define UNGETC(c,p)     ((!mime_mode)?ungetc(c,p):mime_ungetc(c))


#ifdef EASYWIN /*Easy Win */
extern POINT _BufferSize;
#endif

/*      function prototype  */

#ifndef _
# ifdef __STDC__
#  define _(args) args
# else
#  define _(args) ()
# endif
#endif

#ifndef PERL_XS
static  void    noconvert _((FILE *f));
static  int     mime_integrity _((FILE *f,unsigned char *p));
static  int     usage _((void));
static char            stdibuf[IOBUF_SIZE];
static char            stdobuf[IOBUF_SIZE];
static unsigned int            mime_input = 0; /* undecoded */
static int             end_check;
#endif

static  void    kanji_convert _((FILE *f));
static  void    h_conv _((FILE *f,int c2,int c1));
static  int     push_hold_buf _((int c2,int c1));
static  void    s_iconv _((int c2,int c1));
static  void    e_oconv _((int c2,int c1));
static  void    s_oconv _((int c2,int c1));
static  void    j_oconv _((int c2,int c1));
static  int     line_fold _((int c2,int c1));
static  int     pre_convert _((int c1,int c2));
static  int     mime_begin _((FILE *f));
static  int     mime_getc _((FILE *f));
static  int     mime_ungetc _((unsigned int c));
static  int     base64decode _((int c));
static  void    arguments _((char *c));
static  void    reinit _((void));

/* buffers */

static unsigned char   hold_buf[HOLD_SIZE*2];
static int             hold_count;

/* 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 */

/* flags */
static int             unbuf_f = FALSE;
static int             estab_f = FALSE;
static int             nop_f = FALSE;
static int             binmode_f = TRUE;       /* binary mode */
static int             rot_f = FALSE;          /* rot14/43 mode */
static int             input_f = FALSE;        /* non fixed input code  */
static int             alpha_f = FALSE;        /* convert JIx0208 alphbet to ASCII */
static int             mime_f = TRUE;         /* convert MIME B base64 or Q */
static int             mimebuf_f = FALSE;      /* MIME buffered input */
static int             broken_f = FALSE;       /* convert ESC-less broken JIS */
static int             iso8859_f = FALSE;      /* ISO8859 through */
#if defined(MSDOS) || defined(__OS2__) 
static int             x0201_f = TRUE;         /* Assume JISX0201 kana */
#else
static int             x0201_f = NO_X0201;     /* Assume NO JISX0201 */
#endif

/* X0208 -> ASCII converter */

static int             c1_return;

/* fold parameter */
static int line = 0;    /* chars in line */
static int prev = 0;
static int             fold_f  = FALSE;
static int             fold_len  = 0;

/* options */
static char            kanji_intro = DEFAULT_J,
                ascii_intro = DEFAULT_R;

/* Folding */

int line_fold();
#define FOLD_MARGIN  10
#define DEFAULT_FOLD 60

/* converters */

#ifdef DEFAULT_CODE_JIS
#   define  DEFAULT_CONV j_oconv
#endif
#ifdef DEFAULT_CODE_SJIS
#   define  DEFAULT_CONV s_oconv
#endif
#ifdef DEFAULT_CODE_EUC
#   define  DEFAULT_CONV e_oconv
#endif

static void            (*iconv) _((int c2,int c1));
					/* s_iconv or oconv */
static void            (*oconv) _((int c2,int c1)) = DEFAULT_CONV; 
					  /* [ejs]_oconv */

/* Global states */
static int             output_mode = ASCII,    /* output kanji mode */
                input_mode =  ASCII,    /* input kanji mode */
                shift_mode =  FALSE;    /* TRUE shift out, or X0201  */
static int             mime_mode =   FALSE;    /* MIME mode B base64, Q hex */

/* X0201 / X0208 conversion tables */

/* X0201 kana conversion table */
/* 90-9F A0-DF */
unsigned char cv[]= {
0x21,0x21,0x21,0x23,0x21,0x56,0x21,0x57,
0x21,0x22,0x21,0x26,0x25,0x72,0x25,0x21,
0x25,0x23,0x25,0x25,0x25,0x27,0x25,0x29,
0x25,0x63,0x25,0x65,0x25,0x67,0x25,0x43,
0x21,0x3c,0x25,0x22,0x25,0x24,0x25,0x26,
0x25,0x28,0x25,0x2a,0x25,0x2b,0x25,0x2d,
0x25,0x2f,0x25,0x31,0x25,0x33,0x25,0x35,
0x25,0x37,0x25,0x39,0x25,0x3b,0x25,0x3d,
0x25,0x3f,0x25,0x41,0x25,0x44,0x25,0x46,
0x25,0x48,0x25,0x4a,0x25,0x4b,0x25,0x4c,
0x25,0x4d,0x25,0x4e,0x25,0x4f,0x25,0x52,
0x25,0x55,0x25,0x58,0x25,0x5b,0x25,0x5e,
0x25,0x5f,0x25,0x60,0x25,0x61,0x25,0x62,
0x25,0x64,0x25,0x66,0x25,0x68,0x25,0x69,
0x25,0x6a,0x25,0x6b,0x25,0x6c,0x25,0x6d,
0x25,0x6f,0x25,0x73,0x21,0x2b,0x21,0x2c,
0x00,0x00};


/* X0201 kana conversion table for daguten */
/* 90-9F A0-DF */
unsigned char dv[]= { 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x25,0x2c,0x25,0x2e,
0x25,0x30,0x25,0x32,0x25,0x34,0x25,0x36,
0x25,0x38,0x25,0x3a,0x25,0x3c,0x25,0x3e,
0x25,0x40,0x25,0x42,0x25,0x45,0x25,0x47,
0x25,0x49,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x25,0x50,0x25,0x53,
0x25,0x56,0x25,0x59,0x25,0x5c,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00};

/* X0201 kana conversion table for han-daguten */
/* 90-9F A0-DF */
unsigned char ev[]= { 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x25,0x51,0x25,0x54,
0x25,0x57,0x25,0x5a,0x25,0x5d,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00};


/* X0208 kigou conversion table */
/* 0x8140 - 0x819e */
unsigned char fv[] = {

0x00,0x00,0x00,0x00,0x2c,0x2e,0x00,0x3a,
0x3b,0x3f,0x21,0x00,0x00,0x27,0x60,0x00,
0x5e,0x00,0x5f,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x2d,0x00,0x2f,
0x5c,0x00,0x00,0x7c,0x00,0x00,0x60,0x27,
0x22,0x22,0x28,0x29,0x00,0x00,0x5b,0x5d,
0x7b,0x7d,0x3c,0x3e,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x2b,0x2d,0x00,0x00,
0x00,0x3d,0x00,0x3c,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x24,0x00,0x00,0x25,0x23,0x26,0x2a,0x40,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
} ;


static int             file_out = FALSE;
static int             add_cr = FALSE;
static int             del_cr = FALSE;

#ifndef PERL_XS
int
main(argc, argv)
    int             argc;
    char          **argv;
{
    FILE  *fin;
    char  *cp;

#ifdef EASYWIN /*Easy Win */
    _BufferSize.y = 400;/*Set Scroll Buffer Size*/
#endif

    for (argc--,argv++; (argc > 0) && **argv == '-'; argc--, argv++) {
        cp = *argv;
	arguments(cp);
    }

    if(iso8859_f && (oconv != j_oconv || !x0201_f )) {
        fprintf(stderr,"Mixed ISO8859/JISX0201/SJIS/EUC output is not allowed.\n");
        exit(1);
    }

    if(binmode_f == TRUE)
#ifdef __OS2__
    if(freopen("","wb",stdout) == NULL) 
        return (-1);
#else
    setbinmode(stdout);
#endif

    if(unbuf_f)
      setbuf(stdout, (char *) NULL);
    else
      setvbuffer(stdout, stdobuf, IOBUF_SIZE);

    if(argc == 0) {
      if(binmode_f == TRUE)
#ifdef __OS2__
      if(freopen("","rb",stdin) == NULL) return (-1);
#else
      setbinmode(stdin);
#endif
      setvbuffer(stdin, stdibuf, IOBUF_SIZE);
      if(nop_f)
          noconvert(stdin);
      else
          kanji_convert(stdin);
    } else {
      while (argc--) {
          if((fin = fopen(*argv++, "r")) == NULL) {
              perror(*--argv);
              return(-1);
          } else {
/* reopen file for stdout */
              if(file_out == TRUE){ 
                  if(argc == 1 ) {
                      if(freopen(*argv++, "w", stdout) == NULL) {
                          perror(*--argv);
                          return (-1);
                      }
                      argc--;
                  } else {
                      if(freopen("nkf.out", "w", stdout) == NULL) {
                         perror(*--argv);
                         return (-1);
                      }
                  }
                  if(binmode_f == TRUE) {
#ifdef __OS2__
                      if(freopen("","wb",stdout) == NULL) 
                           return (-1);
#else
                      setbinmode(stdout);
#endif
                  }
              }
              if(binmode_f == TRUE)
#ifdef __OS2__
                 if(freopen("","rb",fin) == NULL) 
                    return (-1);
#else
                 setbinmode(fin);
#endif 
              setvbuffer(fin, stdibuf, IOBUF_SIZE);
              if(nop_f)
                  noconvert(fin);
              else
                  kanji_convert(fin);
              fclose(fin);
          }
      }
    }
#ifdef EASYWIN /*Easy Win */
    if(file_out == FALSE) 
        scanf("%d",&end_check);
    else 
        fclose(stdout);
#else /* for Other OS */
    if(file_out == TRUE) 
        fclose(stdout);
#endif 
    return (0);
}
#endif

static void
arguments(cp) 
    char *cp;
{
    while (*cp) {
	switch (*cp++) {
	case 'b':           /* buffered mode */
	    unbuf_f = FALSE;
	    continue;
	case 'u':           /* non bufferd mode */
	    unbuf_f = TRUE;
	    continue;
	case 't':           /* transparent mode */
	    nop_f = TRUE;
	    continue;
	case 'j':           /* JIS output */
	case 'n':
	    oconv = j_oconv;
	    continue;
	case 'e':           /* AT&T EUC output */
	    oconv = e_oconv;
	    continue;
	case 's':           /* SJIS output */
	    oconv = s_oconv;
	    continue;
	case 'l':           /* ISO8859 Latin-1 support, no conversion */
	    iso8859_f = TRUE;  /* Only compatible with ISO-2022-JP */
	    input_f = LATIN1_INPUT;
	    continue;
	case 'i':           /* Kanji IN ESC-$-@/B */
	    if(*cp=='@'||*cp=='B') 
		kanji_intro = *cp++;
	    continue;
	case 'o':           /* ASCII IN ESC-(-J/B */
	    if(*cp=='J'||*cp=='B'||*cp=='H') 
		ascii_intro = *cp++;
	    continue;
	case 'r':
	    rot_f = TRUE;
	    continue;
#if defined(MSDOS) || defined(__OS2__) 
	case 'T':
	    binmode_f = FALSE;
	    continue;
#endif
#ifndef PERL_XS
	case 'v':
	    usage();
	    exit(1);
	    break;
#endif
	/* Input code assumption */
	case 'J':   /* JIS input */
	case 'E':   /* AT&T EUC input */
	    input_f = JIS_INPUT;
	    continue;
	case 'S':   /* MS Kanji input */
	    input_f = SJIS_INPUT;
	    if(x0201_f==NO_X0201) x0201_f=TRUE;
	    continue;
	case 'Z':   /* Convert X0208 alphabet to asii */
	    /*  bit:0   Convert X0208
		bit:1   Convert Kankaku to one space
		bit:2   Convert Kankaku to two spaces
	    */
	    if('9'>= *cp && *cp>='0') 
		alpha_f |= 1<<(*cp++ -'0');
	    else 
		alpha_f |= TRUE;
	    continue;
	case 'x':   /* Convert X0201 kana to X0208 or X0201 Conversion */
	    x0201_f = FALSE;    /* No X0201->X0208 conversion */
	    /* accept  X0201
		    ESC-(-I     in JIS, EUC, MS Kanji
		    SI/SO       in JIS, EUC, MS Kanji
		    SSO         in EUC, JIS, not in MS Kanji
		    MS Kanji (0xa0-0xdf) 
	       output  X0201
		    ESC-(-I     in JIS (0x20-0x5f)
		    SSO         in EUC (0xa0-0xdf)
		    0xa0-0xd    in MS Kanji (0xa0-0xdf) 
	    */
	    continue;
	case 'X':   /* Assume X0201 kana */
	    /* Default value is NO_X0201 for EUC/MS-Kanji mix */
	    x0201_f = TRUE;
	    continue;
	case 'f':   /* folding -f60 or -f */
	    fold_f = TRUE;
	    fold_len = atoi(cp);
	    if(!(0<fold_len && fold_len<BUFSIZ)) 
		fold_len = DEFAULT_FOLD;
	    while('0'<= *cp && *cp <='9') cp++;
	    continue;
	case 'm':   /* MIME support */
	    mime_f = TRUE;
	    if(*cp=='B'||*cp=='Q') {
		mime_mode = *cp++;
		mimebuf_f = FIXED_MIME;
	    } else if (*cp=='0') {
		mime_f = FALSE;
	    }
	    continue;
	case 'M':   /* MIME output */
	    oconv = j_oconv;    /* sorry... not yet done.. */
	    continue;
	case 'B':   /* Broken JIS support */
	    /*  bit:0   no ESC JIS
		bit:1   allow any x on ESC-(-x or ESC-$-x
		bit:2   reset to ascii on NL
	    */
	    if('9'>= *cp && *cp>='0') 
		broken_f |= 1<<(*cp++ -'0');
	    else 
		broken_f |= TRUE;
	    continue;
#ifndef PERL_XS
	case 'O':/* for Output file */
	    file_out = TRUE;
	    continue;
#endif
	case 'c':/* add cr code */
	    add_cr = TRUE;
	    continue;
	case 'd':/* delete cr code */
	    del_cr = TRUE;
	    continue;
	default:
	    /* bogus option but ignored */
	    continue;
	}
    }
}

#ifndef PERL_XS
static void
noconvert(f)
    FILE  *f;
{
    int    c;

    while ((c = getc(f)) != EOF)
      putchar(c);
}
#endif


static void
kanji_convert(f)
    FILE  *f;
{
    int    c1, c2;

    c2 = 0;

    if(input_f == JIS_INPUT || input_f == LATIN1_INPUT) {
        estab_f = TRUE; iconv = oconv;
    } else if(input_f == SJIS_INPUT) {
        estab_f = TRUE;  iconv = s_iconv;
    } else {
        estab_f = FALSE; iconv = oconv;
    }
    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  */

    while ((c1 = GETC(f)) != EOF) {
        if(c2) {
            /* second byte */
            if(c2 > DEL) {
                /* in case of 8th bit is on */
                if(!estab_f) {
                    /* in case of not established yet */
                    if(c1 > SSP) {
                        /* It is still ambiguious */
                        h_conv(f, c2, c1);
                        c2 = 0;
                        NEXT;
                    } else if(c1 < AT) {
                        /* ignore bogus code */
                        c2 = 0;
                        NEXT;
                    } else {
                        /* established */
                        /* it seems to be MS Kanji */
                        estab_f = TRUE;
                        iconv = s_iconv;
                        SEND;
                    }
                } else
                    /* in case of already established */
                    if(c1 < AT) {
                        /* ignore bogus code */
                        c2 = 0;
                        NEXT;
                    } else
                        SEND;
            } else
                /* 7 bit code */
                /* it might be kanji shitfted */
                if((c1 == DEL) || (c1 <= SPACE)) {
                    /* ignore bogus first code */
                    c2 = 0;
                    NEXT;
                } else
                    SEND;
        } else {
            /* first byte */
            if(c1 > DEL) {
                /* 8 bit code */
                if(!estab_f && !iso8859_f) {
                    /* not established yet */
                    if(c1 < SSP) {
                        /* it seems to be MS Kanji */
                        estab_f = TRUE;
                        iconv = s_iconv;
                    } else if(c1 < 0xe0) {
                        /* it seems to be EUC */
                        estab_f = TRUE;
                        iconv = oconv;
                    } else {
                        /* still ambiguious */
                    }
                    c2 = c1;
                    NEXT;
                } else { /* estab_f==TRUE */
                    if(iso8859_f) {
                        SEND;
                    } else if(SSP<=c1 && c1<0xe0 && iconv == s_iconv) {
                        /* SJIS X0201 Case... */
                        /* This is too arrogant, but ... */
                        if(x0201_f==NO_X0201) {
                            iconv = oconv;
                            c2 = c1;
                            NEXT;
                        } else 
                        if(x0201_f) {
                            if(dv[(c1-SSP)*2]||ev[(c1-SSP)*2]) {
                            /* look ahead for X0201/X0208conversion */
                                if((c2 = GETC(f)) == EOF) {
                                    (*oconv)(cv[(c1-SSP)*2],cv[(c1-SSP)*2+1]);
                                    LAST;
                                } else if(c2==(0xde)) { /* 