/* vi: set sw=4 ts=4: */
/*
 * CCE - Console Chinese Environment -
 * Copyright (C) 1998-2003 Rui He (rhe@3eti.com)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *  Name: cceconv
 *  Documentation:
 *    Universal file encoding convertor (GB/GBK/Big5/JIS/ShiftJIS/KSC)
 *
 *   This program is based on the following programs:
 *      dos2unix/unix2dos  Benjamin Lin(blin@socs.uts.edu.au)   
 *      hc 3.0             Ricky Yeung(Ricky.Yeung@eng.sun.com) and
 *                         Fung F. Leeconvert.c(lee@umunhum.stanford.edu)
 *          (The GBToBig5Tbl & Big5ToGBTbl is generated from hc 3.0's hc.tab)
 *
 *    Other gb<->jis gbk<->big5 gb<->ksc conversion table is generated from NJStar
 */

#define VER_AUTHOR   "Rui He"
#define VER_DATE     "2003.08.09"
#define VER_REVISION "1.0"

#ifdef __MSDOS__
#  include <dir.h>
#endif /* __MSDOS__ */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <utime.h>
#include <sys/stat.h>

#include "defs.h"
#include "convert.h"

#define LOBYTE(n)   ((n) & 0xFF)
#define HIBYTE(n)   ((n) / 256 )

#define DOS_MODE	(CODE_NUM)    /* 0x0D 0A */
#define UNIX_MODE	(CODE_NUM+1)  /* 0x */

char *codingName[] = { "2022JP", "JIS", "Shift-JIS", "Big5", "GB", "GBK", "KSC", "UHC", "Unicode",
                       "DOS", "Unix" };

typedef struct
{
  int OldCoding;			/* old coding */
  int NewCoding;			/* new coding */

  int ConvMode;				/* for DOS/Unix */

  int NewFile;                          /* is in new file mode? */
  int Quiet;                            /* is in quiet mode? */
  int KeepDate;                         /* should keep date stamp? */
  int KeepPerm;                         /* should keep permision stamp? */
} CFlag;

#if 0

static int D2UAsciiTable[256] =
{
  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
  '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
  '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
  '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f' ,
  '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
  '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
  '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
  '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
  '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
  '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
  '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
  '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
  '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
  '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
  '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
  '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
  '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
  '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
  '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
  '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf' ,
  '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
  '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
  '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
  '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
  '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
  '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff',
};

static int D2U7BitTable[256] =
{
  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
  '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
  '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
  '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f' ,
  '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
  '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
  '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
  '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
  '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
  '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
};

static int D2UIsoTable[256] =
{
  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
  '\x10', '\x11', '\x12', '\x13', '\xb6', '\xa7', '\x16', '\x17',
  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
  '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
  '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f' ,
  '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
  '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
  '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
  '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
  '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
  '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x81',
  '\xc7', '\xfc', '\xe9', '\xe2', '\xe4', '\xe0', '\xe5', '\xe7',
  '\xea', '\xeb', '\xe8', '\xef', '\xee', '\xec', '\xc4', '\xc5',
  '\xc9', '\xe6', '\xc6', '\xf4', '\xf6', '\xf2', '\xfb', '\xf9',
  '\xff', '\xd6', '\xdc', '\xa2', '\xa3', '\xa5', '\xa4', '\x96',
  '\xe1', '\xed', '\xf3', '\xfa', '\xf1', '\xd1', '\xaa', '\xba',
  '\xbf', '\xa8', '\xac', '\xbd', '\xbc', '\xa1', '\xab', '\xaf',
  '\x97', '\x98', '\x99', '\xfe', '\xb3', '\xb4', '\xb5', '\xb8',
  '\xb9', '\xa0', '\xa6', '\xa9', '\xad', '\xbb', '\xbe', '\xc0',
  '\xc1', '\xc2', '\xc3', '\xc8', '\xfd', '\xca', '\xcb', '\xcc',
  '\xae', '\xd0', '\xd7', '\xdd', '\xde', '\xcd', '\xf0', '\xce' ,
  '\xcf', '\xd2', '\xd3', '\xd4', '\xd5', '\xd8', '\xd9', '\xda',
  '\xdb', '\xe3', '\xf5', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e',
  '\x80', '\xdf', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
  '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
  '\x14', '\xb1', '\xf8', '\x7f', '\x9f', '\x15', '\xf7', '\x95',
  '\xb0', '\xb7', '\x94', '\x93', '\x92', '\xb2', '\x91', '\x90',
};

#endif

int ConvertDosToUnix(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag)
{
    int RetVal = 0;
    int TempChar;
    
    switch (ipFlag->ConvMode)
    {
        case 0: /* ASCII */
            while ((TempChar = getc(ipInF)) != EOF)
                if ((TempChar != '\x0d') &&
                    (putc(/* D2UAsciiTable[TempChar] */ TempChar, ipOutF) == EOF))
                {
                    RetVal = -1;
                    if (!ipFlag->Quiet)
                        fprintf(stderr, "cceconv: can not write to out file\n");
                    break;
                }
            break;
#if 0
        case 1: /* 7Bit */
            while ((TempChar = getc(ipInF)) != EOF)
                if ((TempChar != '\x0d') &&
                    (putc(D2U7BitTable[TempChar], ipOutF) == EOF))
                {
                    RetVal = -1;
                    if (!ipFlag->Quiet)
                        fprintf(stderr, "dos2unix: can not write to out file\n");
                    break;
                }
            break;
        case 2: /* ISO */
            while ((TempChar = getc(ipInF)) != EOF)
                if ((TempChar != '\x0d') &&
                    (putc(D2UIsoTable[TempChar], ipOutF) == EOF))
                {
                    RetVal = -1;
                    if (!ipFlag->Quiet)
                        fprintf(stderr, "dos2unix: can not write to out file\n");
                    break;
                }
            break;
        case 3: /* Mac */
            while ((TempChar = getc(ipInF)) != EOF)
            if ((TempChar != '\x0d'))
            {
		  		if(putc(D2UAsciiTable[TempChar], ipOutF) == EOF)
				{
                    RetVal = -1;
                    if (!ipFlag->Quiet)
		     			 fprintf(stderr, "dos2unix: can not write to out file\n");
                    break;
		  		}
            }
	        else
			{
		  		if (putc('\x0a', ipOutF) == EOF)
		    	{
                    RetVal = -1;
                    if (!ipFlag->Quiet)
                        fprintf(stderr, "dos2unix: can not write to out file\n");
                    break;
		    	}
			}
            break;
#endif
        default: /* unknown convmode */
            ;
#ifdef DEBUG
            fprintf(stderr, "cceconv: program error, invalid conversion mode %d\n",ipFlag->ConvMode);
            exit(1);
#endif /* DEBUG */
    }
                
    return RetVal;
}

#if 0

static int U2DAsciiTable[256] =
{
  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
  '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
  '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
  '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f' ,
  '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
  '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
  '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
  '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
  '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
  '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
  '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
  '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
  '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
  '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
  '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
  '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
  '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
  '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
  '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
  '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf' ,
  '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
  '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
  '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
  '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
  '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
  '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff',
};

static int U2D7BitTable [256] =
{
  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
  '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
  '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
  '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f' ,
  '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
  '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
  '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
  '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
  '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
  '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
  '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20',
};

static int U2DIsoTable[256] =
{
  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
  '\x10', '\x11', '\x12', '\x13', '\xf0', '\xf5', '\x16', '\x17',
  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
  '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
  '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f' ,
  '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
  '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
  '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
  '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
  '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
  '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\xf3',
  '\xe0', '\x7f', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
  '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
  '\xff', '\xfe', '\xfc', '\xfb', '\xfa', '\xf7', '\x9f', '\xb0',
  '\xb1', '\xb2', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', '\xf4',
  '\xb9', '\xad', '\x9b', '\x9c', '\x9e', '\x9d', '\xba', '\x15',
  '\xa9', '\xbb', '\xa6', '\xae', '\xaa', '\xbc', '\xc8', '\xaf',
  '\xf8', '\xf1', '\xfd', '\xb4', '\xb5', '\xb6', '\x14', '\xf9',
  '\xb7', '\xb8', '\xa7', '\xbd', '\xac', '\xab', '\xbe', '\xa8',
  '\xbf', '\xc0', '\xc1', '\xc2', '\x8e', '\x8f', '\x92', '\x80',
  '\xc3', '\x90', '\xc5', '\xc6', '\xc7', '\xcd', '\xcf', '\xd0' ,
  '\xc9', '\xa5', '\xd1', '\xd2', '\xd3', '\xd4', '\x99', '\xca',
  '\xd5', '\xd6', '\xd7', '\xd8', '\x9a', '\xcb', '\xcc', '\xe1',
  '\x85', '\xa0', '\x83', '\xd9', '\x84', '\x86', '\x91', '\x87',
  '\x8a', '\x82', '\x88', '\x89', '\x8d', '\xa1', '\x8c', '\x8b',
  '\xce', '\xa4', '\x95', '\xa2', '\x93', '\xda', '\x94', '\xf6',
  '\xf2', '\x97', '\xa3', '\x96', '\x81', '\xc4', '\xb3', '\x98',
};

#endif

int ConvertUnixToDos(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag)
{
    int RetVal = 0;
    int TempChar;

    switch (ipFlag->ConvMode)
    {
        case 0: /* ASCII */
            while ( (TempChar = getc(ipInF)) != EOF )
                if (((TempChar == '\x0a') && ( putc('\x0d', ipOutF) == EOF)) ||
                    ((TempChar == '\x0d') && ( ((TempChar = getc(ipInF)) == EOF) || (putc('\x0d', ipOutF) == EOF))) ||
                    (putc(TempChar /* U2DAsciiTable[TempChar] */, ipOutF) == EOF) )
                {
                    RetVal = -1;
                    if (!ipFlag->Quiet)
                        fprintf(stderr, "cceconv: can not write to output file\n");
                    break;
                }
            break;
#if 0
      case 1: /* 7Bit */
            while ((TempChar = getc(ipInF)) != EOF)
                if ((TempChar == '\x0a') && (putc('\x0d', ipOutF) == EOF) ||
                    (TempChar == '\x0d') && (((TempChar = getc(ipInF)) == EOF) || (putc('\x0d', ipOutF) == EOF)) ||
                    (putc(U2D7BitTable[TempChar], ipOutF) == EOF))
                {
                    RetVal = -1;
                    if (!ipFlag->Quiet)
                        fprintf(stderr, "unix2dos: can not write to output file\n");
                    break;
                }
            break;
      case 2: /* ISO */
            while ((TempChar = getc(ipInF)) != EOF)
                if ((TempChar == '\x0a') && (putc('\x0d', ipOutF) == EOF) ||
                    (TempChar == '\x0d') && (((TempChar = getc(ipInF)) == EOF) || (putc('\x0d', ipOutF) == EOF)) ||
                    (putc(U2DIsoTable[TempChar], ipOutF) == EOF))
                {
                    RetVal = -1;
                    if (!ipFlag->Quiet)
                        fprintf(stderr, "unix2dos: can not write to output file\n");
                    break;
                }
            break;
#endif

      default: /*unknown convmode */
          ;
#ifdef DEBUG
            fprintf(stderr, "cceconv: program error, invalid conversion mode %d\n",ipFlag->ConvMode);
            exit(1);
#endif /* DEBUG */
  }
  return RetVal;
}

#define EUCbox  0xA1A1  /* JIS empty box symbol */
#define SJISbox 0x8140  /* Shift JIS code for the empty box symbol */

#define GBbox   0xA1F5  /* GB code for the empty box symbol */
#define GBKbox  0xA1F5  /* GBK code for the empty box symbol */
#define BIGbox  0xA1BC  /* BIG code for the empty box symbol */
#define KSCbox  0xA1E0  /* KSC code for the empty box symbol */

unsigned short EmptyBoxSymbols[CODE_NUM] = {
	0x0000, EUCbox, SJISbox, BIGbox, GBbox, GBKbox, KSCbox, KSCbox, 0x00000,  /* last two: UHC, Unicode */
};

void CCEConvertChar(int High, int Low, FILE *ipOutF, int OldCoding, int NewCoding)
{
	int OutChar = ConvertEncoding_Char(OldCoding, NewCoding, High, Low, NULL, NULL);
			   
   	if (OutChar == 0 || OutChar == -1)  /* -1 is the error flag */
		OutChar = EmptyBoxSymbols[NewCoding];
           	
	putc(HIBYTE(OutChar), ipOutF); 
	putc(LOBYTE(OutChar), ipOutF);
}           	
	
static unsigned short zenmap[] = {
	0x2121,0x2123,0x2156,0x2157,0x2122,0x2126,0x2572,0x2521,
	0x2523,0x2525,0x2527,0x2529,0x2563,0x2565,0x2567,0x2543,
	0x213c,0x2522,0x2524,0x2526,0x2528,0x252a,0x252b,0x252d,
	0x252f,0x2531,0x2533,0x2535,0x2537,0x2539,0x253b,0x253d,
	0x253f,0x2541,0x2544,0x2546,0x2548,0x254a,0x254b,0x254c,
	0x254d,0x254e,0x254f,0x2552,0x2555,0x2558,0x255b,0x255e,
	0x255f,0x2560,0x2561,0x2562,0x2564,0x2566,0x2568,0x2569,
	0x256a,0x256b,0x256c,0x256d,0x256f,0x2573,0x212b,0x212c, /* 64 points 0xA0-DF, in JIS */

#if 0 /* in GB coding */
	0x2121,0x2123, 0x2138/*0x2156*/, 0x2139/*0x2157*/, 0x2122, 0x2124/* 0x2126*/, 0x2572,0x2521,
	0x2523,0x2525,0x2527,0x2529,0x2563,0x2565,0x2567,0x2543,
	0x212A/*0x213c*/, 0x2522,0x2524,0x2526,0x2528,0x252a,0x252b,0x252d,
	0x252f,0x2531,0x2533,0x2535,0x2537,0x2539,0x253b,0x253d,
	0x253f,0x2541,0x2544,0x2546,0x2548,0x254a,0x254b,0x254c,
	0x254d,0x254e,0x254f,0x2552,0x2555,0x2558,0x255b,0x255e,
	0x255f,0x2560,0x2561,0x2562,0x2564,0x2566,0x2568,0x2569,
	0x256a,0x256b,0x256c,0x256d,0x256f,0x2573,  0x2165/* 0x212b */ , 0x2163/*0x212c */, 
#endif

	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x252c,0x252e,
	0x2530,0x2532,0x2534,0x2536,0x2538,0x253a,0x253c,0x253e,
	0x2540,0x2542,0x2545,0x2547,0x2549,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x2550,0x2553,0x2556,0x2559,0x255c,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, /* [A0-DD] DE */
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, /* 64 chars, same in GB&JIS */

	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x2551,0x2554,0x2557,0x255a,0x255d,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, /* [A0-DD] DF */
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, /* 64 chars, same in GB&JIS */
};

static void CCEKanaConvert(int inChar1, int inChar2, FILE* ipOutF, CFlag *ipFlag)
{
	int OutChar;

	inChar1 &= 0xFF;
	inChar2 &= 0xFF;

    if (inChar1 >= 0xA0 && inChar1 <= 0xDF)
	{
		if (inChar2 == 0xDE && zenmap[inChar1 - 0xA0 + 0x40] != 0)
           	OutChar = zenmap[inChar1 - 0xA0 + 0x40] | 0x8080;
	    else if (inChar2 == 0xDF && zenmap[inChar1 - 0xA0 + 0x80] != 0)
        	OutChar = zenmap[inChar1 - 0xA0 + 0x80] | 0x8080;
		else OutChar = zenmap[inChar1 - 0xA0] | 0x8080;
				
		CCEConvertChar(OutChar >> 8, OutChar & 0xFF, ipOutF, CODE_EUC, ipFlag->NewCoding);
	}
	else
	{
		putc(inChar1, ipOutF); /* inChar2 should be -1 now */
	}
}

int CCEConvertFile_FromEUCJP(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag)
{
	int RetVal = 0;
   	int TempChar,LastChar = 0;

   	while ((TempChar = getc(ipInF)) != EOF)
   	{
       	if (TempChar == 0x0A || TempChar == 0x0D)   /* new line */
       	{
			if ((LastChar & 0xFF) == 0x8E) LastChar >>= 8;
           	if (LastChar != 0)
				CCEKanaConvert(LastChar & 0xFF, -1, ipOutF, ipFlag);

			LastChar = 0; 

           	putc(TempChar, ipOutF);
       	}
       	else if (LastChar != 0)  /* a Chinese/Japanese/Korean char second byte? */
       	{
			if (LastChar == 0x8E) /* CHAR_SS2 */
			{
				if (ipFlag->NewCoding == CODE_SJIS || TempChar < 0xA0 || TempChar > 0xDF)
	    		{
					putc(TempChar, ipOutF);
					LastChar = 0;
					continue;
	     		}
				else  /* now TempChar is in A0-DF range  -> 0x8EA0-8EDF */
				{
					LastChar = 0x8E00 | TempChar;
					continue;
 				}
			}
			else if ((LastChar & 0xFFFF00) == 0x8E00) /* 0x8EA0-0x8EDF */
			{
				if (TempChar == 0x8E) 
				{
					LastChar = LastChar << 8 || TempChar; /* 0x8E[A0-DF]8E */
					continue;
				}
				else /* not 8E for this one */
				{
					CCEKanaConvert(LastChar & 0xFF, -1, ipOutF, ipFlag);
					LastChar = 0;
					ungetc(TempChar, ipInF); /* put back */
					continue;
				}
			}
			else if ((LastChar & 0xFF00FF) == 0x8E008E) /* 8E[A0-DF]8E */
			{
				if (TempChar == 0xDE || TempChar == 0xDF) 
				{
					CCEKanaConvert((LastChar >> 8) & 0xFF, TempChar, ipOutF, ipFlag);
					LastChar = 0;
					continue;
				}
				else if (TempChar >= 0xA0 && TempChar <= 0xDF)
				{
					CCEKanaConvert((LastChar >> 8) & 0xFF, -1, ipOutF, ipFlag); /* output */
					LastChar = 0x8E00 || TempChar;
					continue;
				}
				else
				{
					CCEKanaConvert((LastChar >> 8) & 0xFF, -1, ipOutF, ipFlag); /* output */
					LastChar = 0;
					putc(TempChar, ipOutF); /* 8E [A0-DF] 8E ![A0-DF] */
					continue;
				}
			}

			CCEConvertChar(LastChar, TempChar,ipOutF,ipFlag->OldCoding,ipFlag->NewCoding );
			LastChar = 0;
       	}
       	else  /* now single byte output */
		{
			if (TempChar == 0x8E || iskanji_byte1(ipFlag->OldCoding, TempChar)) 
			   LastChar=TempChar; 
			else putc(TempChar,ipOutF);

		}
	}

    if (ferror(ipInF) || ferror(ipOutF))
    {
        RetVal = -1;
        if (!ipFlag->Quiet)
           fprintf(stderr, "big2gb: Error while converting file!\n");
    }
    else 
	{
		if ((LastChar & 0xFF) == 0x8E) LastChar >>= 8;
		if (LastChar != 0)
			CCEKanaConvert(LastChar & 0xFF, -1, ipOutF, ipFlag);
	}
    return RetVal;
}

int CCEConvertFile_FromShiftJIS(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag)
{
	int RetVal = 0;
   	int TempChar,LastChar = 0;

   	while ((TempChar = getc(ipInF)) != EOF)
   	{
       	if (TempChar == 0x0A || TempChar == 0x0D)   /* new line */
       	{
           	if (LastChar != 0)
			{
				CCEKanaConvert(LastChar, -1, ipOutF, ipFlag);	
				LastChar = 0; 
			}

           	putc(TempChar, ipOutF);
       	}
       	else if (LastChar != 0)  /* a Japanese char second byte? */
       	{
			if (LastChar >= 0xA0 && LastChar <= 0xDF) /* saved kana */
			{
				if (TempChar == 0xDE || TempChar == 0xDF)
				{
					CCEKanaConvert(LastChar, TempChar, ipOutF, ipFlag);
					LastChar = 0;
					continue;
				}

				CCEKanaConvert(LastChar, -1, ipOutF, ipFlag);
				LastChar = 0;	
				ungetc(TempChar, ipInF); /* push back */
				continue;
			}

			if (!iskanji_byte2(ipFlag->OldCoding, TempChar))
			{
				putc(LastChar, ipOutF); /* send it out */
				LastChar = 0;
				ungetc(TempChar, ipInF); /* push back */
				continue;
			}
			
			CCEConvertChar(LastChar, TempChar,ipOutF,ipFlag->OldCoding,ipFlag->NewCoding);
			LastChar = 0;
       	}
       	else  /* now single byte output */
		{
			if (TempChar >= 0xA0 && TempChar <= 0xDF) /* not a valid SJIS first byte */
			{
				if (ipFlag->NewCoding == CODE_EUC)
				{
					putc(0x8E, ipOutF);  /* EUC-JP 0x8E 0xA0-DF */
				    putc(TempChar, ipOutF); /* keep the half symbol */
					continue; 
				}
				else LastChar = TempChar; /* save it, try to do 0xA0-DF 0xDE/DF */
			}
			else if (iskanji_byte1(ipFlag->OldCoding, TempChar)) 
			   LastChar=TempChar; 
			else putc(TempChar,ipOutF);

		}
	}

    if (ferror(ipInF) || ferror(ipOutF))
    {
        RetVal = -1;
        if (!ipFlag->Quiet)
           fprintf(stderr, "cceconv: Error while converting file!\n");
    }
    else  if (LastChar != 0)  CCEKanaConvert(LastChar, -1, ipOutF, ipFlag);
    return RetVal;
}

int CCEConvertFile(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag)
{
	int RetVal = 0;
   	int TempChar,LastChar = 0;

	if (ipFlag->OldCoding == DOS_MODE)
		return ConvertDosToUnix(ipInF, ipOutF, ipFlag);
	if (ipFlag->OldCoding == UNIX_MODE)
		return ConvertUnixToDos(ipInF, ipOutF, ipFlag);

	if (ipFlag->OldCoding == CODE_EUC)
		return CCEConvertFile_FromEUCJP(ipInF, ipOutF, ipFlag);
	if (ipFlag->OldCoding == CODE_SJIS)
		return CCEConvertFile_FromShiftJIS(ipInF, ipOutF, ipFlag);
		
   	while ((TempChar = getc(ipInF)) != EOF)
   	{
       	if (TempChar == 0x0A || TempChar == 0x0D)   /* new line */
       	{
           	if (LastChar != 0)
			{
				putc(LastChar, ipOutF);	
				LastChar = 0; 
			}

           	putc(TempChar, ipOutF);
       	}
       	else if (LastChar != 0)  /* a Chinese/Japanese/Korean char second byte? */
       	{
			if (!iskanji_byte2(ipFlag->OldCoding, TempChar))
			{
				putc(LastChar, ipOutF);
				LastChar = 0;  /* now send out the LastChar */
				if (iskanji_byte1(ipFlag->OldCoding, TempChar))
		        	LastChar=TempChar;
               	else putc(TempChar,ipOutF);
				continue;
			}

			CCEConvertChar(LastChar, TempChar,ipOutF,ipFlag->OldCoding,ipFlag->NewCoding);
			LastChar = 0;
       	}
       	else  /* now single byte output */
		{
			if (iskanji_byte1(ipFlag->OldCoding, TempChar)) 
			   LastChar=TempChar; 
			else putc(TempChar,ipOutF);

		}
	}

    if (ferror(ipInF) || ferror(ipOutF))
    {
        RetVal = -1;
        if (!ipFlag->Quiet)
           fprintf(stderr, "cceconv: Error while converting file!\n");
    }
    else  if (LastChar != 0)   putc(LastChar, ipOutF);
    return RetVal;
}

void PrintUsage(char *argv[])
{
  fprintf(stderr, " %s %s Copyright (c) 1998-2003 %s. (%s)\n", 
		  argv[0], VER_REVISION, VER_AUTHOR, VER_DATE);
  fprintf(stderr, " Usage: %s <CONVOPTION> [-hkqV] [-o file ...] [-n infile outfile ...]\n", argv[0]);
  fprintf(stderr, "  -h --help        give this help\n");
  fprintf(stderr, "  -k --keepdate    keep output file date\n");
  fprintf(stderr, "  -p --keepperm    keep output file permision\n");
  fprintf(stderr, "  -q --quiet       quiet mode, suppress all warnings\n");
  fprintf(stderr, "                   always on in stdin->stdout mode\n");
  fprintf(stderr, "  -V --version     display version number\n");
  fprintf(stderr, "  -o --oldfile     write to old file\n");
  fprintf(stderr, "  file ...         files to convert in old file mode\n");
  fprintf(stderr, "  -n --newfile     write to new file(filename specified in pairs)\n");
  fprintf(stderr, "  infile           original file in new file mode\n");
  fprintf(stderr, "  outfile          output file in new file mode\n");
  fprintf(stderr, "  <CONVOPTION>    -gb2big|-big2gb|-gbk2big|-big2gbk|-gb2sjis|-sjis2gb\n");
  fprintf(stderr, "                   -sjis2euc|-euc2sjis|-gb2ksc|-ksc2gb|...\n");
  fprintf(stderr, "                   -dos2unix|-unix2dos|-d2u|-u2d\n");
  fprintf(stderr, "                   you can use any combination from gb/gbk/big/sjis/jis(euc)/ksc/uhc\n");
  fprintf(stderr, "  With only a CONVOPTION option, %s will operate in stdin/stdout mode.\n", argv[0]);
}

void PrintVersion(char *argv[])
{
  fprintf(stderr, "%s %s (%s)\n", VER_REVISION, VER_DATE, argv[0]);
}

FILE* OpenInFile(char *ipFN)
{
  return (fopen(ipFN, R_CNTRL));
}

FILE* OpenOutFile(char *ipFN)
{
  return (fopen(ipFN, W_CNTRL));
}

int CCEConvertNewFile(char *ipInFN, char *ipOutFN, CFlag *ipFlag)
{
  int RetVal = 0;
  FILE *InF = NULL;
  FILE *TempF = NULL;
  char TempPath[16];
  struct stat StatBuf;
  struct utimbuf UTimeBuf;

  if ((ipFlag->KeepDate || ipFlag->KeepPerm) && stat(ipInFN, &StatBuf))
    RetVal = -1;

  strcpy(TempPath, "./ccetmpXXXXXX");
#ifndef __MINGW32__
  mkstemp (TempPath);  /* FIXME: a hack for MinGW32, no mkstemp, dangerous! */
#endif

#ifdef DEBUG
  fprintf(stderr, "cceconv: using %s as temp file\n", TempPath);
#endif /* DEBUG */

  if ((!RetVal) && ((InF=OpenInFile(ipInFN)) == NULL))
    RetVal = -1;

  if ((!RetVal) && (InF) && ((TempF=OpenOutFile(TempPath)) == NULL))
  {
    fclose (InF);
    RetVal = -1;
  }

  if ((!RetVal) && (CCEConvertFile(InF, TempF, ipFlag)))
    RetVal = -1;

  if ((InF) && (fclose(InF) == EOF))
    RetVal = -1;

  if ((TempF) && (fclose(TempF) == EOF))
    RetVal = -1;

  if ((!RetVal) && (ipFlag->KeepDate))
  {
    UTimeBuf.actime = StatBuf.st_atime;
    UTimeBuf.modtime = StatBuf.st_mtime;

    if (utime(TempPath, &UTimeBuf) == -1)
      RetVal = -1;
  }

 if ((!RetVal) && (ipFlag->KeepPerm))
 {
   if (chmod(TempPath,StatBuf.st_mode) == -1)
      RetVal = -1;
 }

  if ((RetVal) && (unlink(TempPath)))
    RetVal = -1;

  if (!RetVal)
  {
    if (stat(ipOutFN, &StatBuf) == 0)
      unlink(ipOutFN);

    if ((rename(TempPath, ipOutFN) == -1) && (!ipFlag->Quiet))
    {
      fprintf(stderr, "cceconv: problems renaming '%s' to '%s'\n", TempPath, ipOutFN);
      fprintf(stderr, "          output file remains in '%s'\n", TempPath);
      RetVal = -1;
    }
  }

  return RetVal;
}

int CCEConvertOldFile(char* ipInFN, CFlag *ipFlag)
{
  int RetVal = 0;
  FILE *InF = NULL;
  FILE *TempF = NULL;
  char TempPath[16];
  struct stat StatBuf;
  struct utimbuf UTimeBuf;

  if ((ipFlag->KeepDate || ipFlag->KeepPerm) && stat(ipInFN, &StatBuf))
    RetVal = -1;

  strcpy(TempPath, "./ccetmpXXXXXX");
 
#ifndef __MINGW32__
  mkstemp (TempPath);   /* FIXME: a hack for MinGW32, no mkstemp */
#endif

#ifdef DEBUG
  fprintf(stderr, "cceconv: using %s as temp file\n", TempPath);
#endif /* DEBUG     */

  if ((!RetVal) && ((InF=OpenInFile(ipInFN)) == NULL))
    RetVal = -1;

  if ((!RetVal) && (InF) && ((TempF=OpenOutFile(TempPath)) == NULL))
  {
    fclose (InF);
    RetVal = -1;
  }

  if ((!RetVal) && (CCEConvertFile(InF, TempF, ipFlag)))
    RetVal = -1;

  if ((InF) && (fclose(InF) == EOF))
    RetVal = -1;

  if ((TempF) && (fclose(TempF) == EOF))
    RetVal = -1;

  if ((!RetVal) && (ipFlag->KeepDate))
  {
    UTimeBuf.actime = StatBuf.st_atime;
    UTimeBuf.modtime = StatBuf.st_mtime;

    if (utime(TempPath, &UTimeBuf) == -1)
      RetVal = -1;
  }

 if ((!RetVal) && (ipFlag->KeepPerm))
 {
   if (chmod(TempPath,StatBuf.st_mode) == -1)
      RetVal = -1;
 }

  if ((!RetVal) && (unlink(ipInFN) == -1))
    RetVal = -1;

  if ((RetVal) && (unlink(TempPath)))
    RetVal = -1;

  if ((!RetVal) && (rename(TempPath, ipInFN) == -1))
  {
    if (!ipFlag->Quiet)
    {
      fprintf(stderr, "cceconv: problems renaming '%s' to '%s'\n", TempPath, ipInFN);
      fprintf(stderr, "          output file remains in '%s'\n", TempPath);
    }
    RetVal = -1;
  }
  return RetVal;
}

int CCEConvertStdio(CFlag *ipFlag)
{
    ipFlag->NewFile = 1;
    ipFlag->Quiet = 1;
    ipFlag->KeepDate = 0;
    ipFlag->KeepPerm = 0;
    return (CCEConvertFile(stdin, stdout, ipFlag));
}

static int GetCoding(char *p)
{
	if (!p || !*p) return -1;

	if (strncasecmp(p, "gbk", 3) == 0) return CODE_GBK;
	if (strncasecmp(p, "big", 3) == 0 || strncasecmp(p, "b5", 2) == 0) return CODE_BIG5;
	if (strncasecmp(p, "ks", 2) == 0) return CODE_KSC;
	if (strncasecmp(p, "gb", 2) == 0 )return CODE_GB;
	if (strncasecmp(p, "euc", 3) == 0 || strncasecmp(p, "jis", 3) == 0) return CODE_EUC;
	if (strncasecmp(p, "sjis", 4) == 0 || strncasecmp(p, "shiftjis", 8) == 0) return CODE_SJIS;
	if (strncasecmp(p, "uhc", 3) == 0) return CODE_UHC;
	if (strncasecmp(p, "unicode", 7) == 0) return CODE_UNICODE;

	if (strncasecmp(p, "dos", 3) == 0 || strcasecmp(p, "d") == 0 ) return DOS_MODE;
	if (strncasecmp(p, "unix", 4) == 0 || strcasecmp(p, "u") == 0) return UNIX_MODE;
	return -1;
}

int cceconvert_main (int argc, char *argv[])
{

	int ArgIdx;
	int CanSwitchFileMode;
	int ShouldExit;
	CFlag *pFlag;
	char *p;
	
	ArgIdx = 0;
	CanSwitchFileMode = 1;
	ShouldExit = 0;
	pFlag = (CFlag*)malloc(sizeof(CFlag));  
	pFlag->NewFile = 0;
	pFlag->Quiet = 0;
	pFlag->KeepDate = 0;
	pFlag->KeepPerm = 0;

	pFlag->OldCoding = -1;
	pFlag->NewCoding = -1;

	if (argc == 1) /* no option specified */
	{
		PrintUsage(argv);
		exit(0);
	}
	
	while ((++ArgIdx < argc) && (!ShouldExit))
	{

	  	if (argv[ArgIdx][0] == '-')
	  	{

			p = index(argv[ArgIdx], '2');
			if (p) /* conversion option */
			{
				*p++ = '\0';
				pFlag->OldCoding = GetCoding(argv[ArgIdx]+1);
				pFlag->NewCoding = GetCoding(p);
				if (pFlag->OldCoding < 0 || pFlag->NewCoding < 0 ||
					(pFlag->OldCoding < CODE_NUM && pFlag->NewCoding >= CODE_NUM) || 
					(pFlag->OldCoding >= CODE_NUM && pFlag->NewCoding < CODE_NUM) )
				{
					fprintf(stderr, "%s: Unrecognized conversion request (%s to %s)\n",
						argv[0], argv[ArgIdx]+1, p);
					ShouldExit = 1;
				}
				else if (pFlag->OldCoding == pFlag->NewCoding)
				{
					fprintf(stderr, "%s: No conversion necessary (%s to %s)\n",
						argv[0], argv[ArgIdx]+1, p);
					ShouldExit = 1;
				}
				if (!ShouldExit)
				{
#ifdef CONVTABLE_USE_MMAP
					if (pFlag->OldCoding < CODE_NUM) MmapConvertTable(CCELIB "/" CONV_TABLE_FILE);
#endif					
					if (ArgIdx == 1 && argc == 2)
						exit(CCEConvertStdio(pFlag));
				}
			}
	
	    	if ((strcmp(argv[ArgIdx],"-h") == 0) || (strcmp(argv[ArgIdx],"--help") == 0))
	      		PrintUsage(argv);
	    	if ((strcmp(argv[ArgIdx],"-k") == 0) || (strcmp(argv[ArgIdx],"--keepdate") == 0))
	      		pFlag->KeepDate = 1;
	    	if ((strcmp(argv[ArgIdx],"-p") == 0) || (strcmp(argv[ArgIdx],"--keepperm") == 0))
	      		pFlag->KeepPerm = 1;
	    	if ((strcmp(argv[ArgIdx],"-q") == 0) || (strcmp(argv[ArgIdx],"--quiet") == 0))
	      		pFlag->Quiet = 1;
	    	if ((strcmp(argv[ArgIdx],"-V") == 0) || (strcmp(argv[ArgIdx],"--version") == 0))
	      		PrintVersion(argv);

	    	if ((strcmp(argv[ArgIdx],"-o") == 0) || (strcmp(argv[ArgIdx],"--oldfile") == 0))
	    	{

	      		if (!CanSwitchFileMode)
	      		{
	        		if (!pFlag->Quiet)
	          			fprintf(stderr, "%s: target of file %s not specified in new file mode\n", 
					  		argv[0], argv[ArgIdx-1]);
	        		ShouldExit = 1;
	      		}
	      		pFlag->NewFile = 0;
	    	}

	    	if ((strcmp(argv[ArgIdx],"-n") == 0) || (strcmp(argv[ArgIdx],"--newfile") == 0))
	    	{

	      		if (!CanSwitchFileMode)
	      		{
	        		if (!pFlag->Quiet)
	          			fprintf(stderr, "%s: target of file %s not specified in new file mode\n", 
					  		argv[0], argv[ArgIdx-1]);
	        		ShouldExit = 1;
	      		}
	      		pFlag->NewFile = 1;
	    	}
  		}
	  	else 
	  	{

	    	if (pFlag->NewFile) /* if NewFile mode, filename in pairs */
	    	{
	      		if (CanSwitchFileMode)
	        		CanSwitchFileMode = 0;  /* wait until the next filename */
	      		else
	      		{
					if (pFlag->OldCoding < 0 || pFlag->NewCoding < 0)
					{
						fprintf(stderr, "%s: no conversion option specified.\n", argv[0]);
						ShouldExit = 1;
						continue;
					}
	
	        		if (!pFlag->Quiet)
	          			fprintf(stderr, "%s: converting file %s to file %s in %s format ...\n", 
					  		argv[0], argv[ArgIdx-1], argv[ArgIdx], codingName[pFlag->NewCoding]);
	        		if (CCEConvertNewFile(argv[ArgIdx-1], argv[ArgIdx], pFlag))
	        		{
            			if (!pFlag->Quiet)
              				fprintf(stderr, "%s: problems converting file %s to file %s\n", 
								argv[0], argv[ArgIdx-1], argv[ArgIdx]);
            			ShouldExit = 1;
          			}
          			CanSwitchFileMode = 1;
        		}
      		}
      		else /*OldFile mode, filename not in pairs */
      		{
				if (pFlag->OldCoding < 0 || pFlag->NewCoding < 0)
				{
					fprintf(stderr, "%s: no conversion option specified.\n", argv[0]);
					ShouldExit = 1;
					continue;
				}
				
        		if (!pFlag->Quiet)
          			fprintf(stderr, "%s: converting file %s to %s format ...\n", 
							argv[0], argv[ArgIdx], codingName[pFlag->NewCoding] );
        		if (CCEConvertOldFile(argv[ArgIdx], pFlag))
        		{
          			if (!pFlag->Quiet)
            			fprintf(stderr, "%s: problems converting file %s\n", argv[0], argv[ArgIdx]);
          			ShouldExit = 1;
        		}
      		}
    	}
  	}

	if ((!pFlag->Quiet) && (!CanSwitchFileMode) && (pFlag->OldCoding >=0 && pFlag->NewCoding >= 0))
  	{
    	fprintf(stderr, "%s: target of file %s not specified in new file mode\n", 
			argv[0], argv[ArgIdx-1]);
    	ShouldExit = 1;
 	}
  
	free(pFlag);

#ifdef CONVTABLE_USE_MMAP
  	MunmapConvertTable(); /* unmap the conversion table */
#endif
  
  	return (ShouldExit);
}

