UTF-16 to ISO-2022-JP への文字コード変換のサンプル実装。
MinGW + gcc 3.4.2 環境において動作確認してあります。

以下の例は、Utf16ToIso2022jp()の実装の例です。 [utf16_to_iso2022jp_c.zip]

Example Code
/*
 * utf16_to_iso2022jp.c
 *
 *  Created on: 2008/10/19
 *      Author: yanch
 */
/** @file
 * @brief UTF-16 → ISO-2022-JP への変換実装サンプルプログラム。
 * 
 * UTF-16 → ISO-2022-JP への変換実装サンプルプログラム。
 * UTF-16 にて用意された"data.txt"ファイルを読み込み、
 * ISO-2022-JP へと変換、
 * "out.txt"ファイルへと出力します。
 * 変換前の文字列にBOMが見つかれば、除去します。
 */
#define STRICT

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

#include "utf16_to_iso2022jp_table.h"

/********************************************************************/
/**
 * バッファ長。
 * 一行毎の文字列を処理するのに必要なバイト数
 */
#define DEFAULT_BUFF_LEN    4096

/********************************************************************/
/**
 * _OPTIONS 構造体
 * プログラム起動オプションを格納する構造体
 */
struct _OPTIONS
{
    char    i[DEFAULT_BUFF_LEN];
    char    o[DEFAULT_BUFF_LEN];
};

typedef struct _OPTIONS T_OPTIONS;

/********************************************************************/
int bytelen(const unsigned char array[], int max_len);
int getEscape(unsigned char dest[], const unsigned char src[]);
int printUsage();
int Utf16ToIso2022jp(char *dest, size_t dest_size, wchar_t *src
        , size_t src_size);

/********************************************************************/
/**
 * メイン関数。
 * ここからプログラムの実行を開始します。
 * 
 * @param[in] argc 引数の数
 * @param[in] argv 引数へのポインタ
 * @return 戻り値(正常終了時は0を戻す)
 */
int main(int argc, char *argv[])
{
    wchar_t     buffer[DEFAULT_BUFF_LEN];
    int         convertCharCount            = 0;
    char        dest[DEFAULT_BUFF_LEN];
    size_t      dest_size                   = 0;
    int         i                           = 0;
    int         iResult                     = 0;
    char        key[DEFAULT_BUFF_LEN];
    int         n                           = 0;
    T_OPTIONS   options;
    FILE        *pInputFile                 = NULL;
    FILE        *pOutputFile                = NULL;
    wchar_t     *src                        = NULL;
    size_t      src_size                    = 0;
    
    /*
     * ●ロケールを設定
     */
    _wsetlocale(LC_ALL, L"japanese");
    
    /*
     * ●入力パラメタチェック
     */
    if (argc < 5)
    {
        printUsage();
        return 0;
    }
    else
    {
        memset(&options, 0, sizeof(options));
        memset(key, 0, DEFAULT_BUFF_LEN);
        for (i = 1; i < argc; i++)
        {
            if (*argv[i] == '-')
            {
                strcpy(key, argv[i]);
            }
            else
            {
                if (strcmp(key, "-i") == 0)
                {
                    strcpy(options.i, argv[i]);
                }
                else if (strcmp(key, "-o") == 0)
                {
                    strcpy(options.o, argv[i]);
                }
                strcpy(key, "");
            }
        }
    }
    if (*(options.i) == '\0' || *(options.o) == '\0')
    {
        printUsage();
        return 0;
    }
    
    /* 
     * ●ファイルを開く
     */
    pInputFile = fopen(options.i, "rb");
    if (pInputFile == NULL)
    {
        fwprintf(stderr, L"ファイルが開けません: %s\n", options.i);
    }
    pOutputFile = fopen(options.o, "wb");
    if (pOutputFile == NULL)
    {
        fwprintf(stderr, L"ファイルが開けません: %s\n", options.o);
    }
    
    if ((pInputFile != NULL) && (pOutputFile != NULL))
    {
        while (feof(pInputFile) == 0)
        {
            /* 
             * ●ファイル読込
             */
            memset(buffer, 0, sizeof(wchar_t) * DEFAULT_BUFF_LEN);
            n = DEFAULT_BUFF_LEN - 1;
            if (NULL == fgetws(buffer, n, pInputFile))
            {
                buffer[0] = L'\0';
            }
            
            src = buffer;
            
            /*
             * ●BOMの除去
             */
            if (*src == 0xfeff)
            {
                src++;
            }
            
            /* 
             * ●文字コード変換
             * UTF-16:src -> ISO-2022-JP:dest 変換
             */
            memset(dest, 0, sizeof(char) * DEFAULT_BUFF_LEN);
            dest_size = DEFAULT_BUFF_LEN - 1;
            src_size = wcslen(src);
            iResult = Utf16ToIso2022jp(dest, dest_size, src, src_size);
            if (iResult == (-1))
            {
                fwprintf(stderr, L"Utf16ToIso2022jp() Failed.\n");
                if (pInputFile != NULL)
                {
                    fclose(pInputFile);
                    pInputFile = NULL;
                }
                if (pOutputFile != NULL)
                {
                    fclose(pOutputFile);
                    pOutputFile = NULL;
                }
                return 1;
            }
            convertCharCount += iResult;
            
            /* 
             * ●ファイル書込
             */
            fputs(dest, pOutputFile);
        }
    }
    
    /* 
     * ●ファイルを閉じる
     */
    if (pInputFile != NULL)
    {
        fclose(pInputFile);
        pInputFile = NULL;
    }
    if (pOutputFile != NULL)
    {
        fclose(pOutputFile);
        pOutputFile = NULL;
    }
    
    wprintf(L"%d バイト変換しました。\n", convertCharCount);
    
    return 0;
}

/********************************************************************/
/**
 * バイト配列の長さを得る。
 * 0ターミネイトバイト配列の長さ(バイト数)を得ます。
 * バイト配列の長さが max_len を超える場合は、max_len を戻します。
 * 
 * @param[in] array バイト配列
 * @param[in] max_len 最大長
 * @return バイト長
 */
int bytelen(const unsigned char array[], int max_len)
{
    int i = 0;
    
    if (array == NULL)
    {
        return 0;
    }
    
    for (i = 0; i < max_len; i++)
    {
        if (array[i] == '\0')
        {
            break;
        }
    }
    
    return i;
}

/********************************************************************/
/**
 * ISO-2022-JP で文字コードに対応するエスケープシーケンスを抜き出します。
 * src の先頭が ESCコード にて始まっているならば、src の先頭から3バイトを戻します。
 * それ以外の場合は、ASCIIモードを示すエスケープシーケンスを戻します。
 * 
 * @param[out] dest エスケープシーケンス
 * @param[in] src 入力文字列
 * @return 結果(0:成功時、(-1):失敗時)
 */
int getEscape(unsigned char dest[], const unsigned char src[])
{
    int     len     = 0;
    /* ASCII */
    const unsigned char escapeASCII[]       = {0x1b, 0x28, 0x42, 0x00};
    
    if ((dest == NULL) || (src == NULL))
    {
        return (-1);
    }
    
    len = bytelen(src, 5);
    if ((len == 0) || (len == 1))
    {
        strcpy((char*)dest, (char*)escapeASCII);
    }
    else if (3 <= len)
    {
        dest[0] = src[0];
        dest[1] = src[1];
        dest[2] = src[2];
        dest[3] = '\0';
    }
    
    return 0;
}

/********************************************************************/
/**
 * printUsage() 関数。
 * 使用方法をコンソールに出力します。
 */
int printUsage()
{
    wprintf(L"utf16_to_iso2022jp.exe\n");
    wprintf(L"UTF-16 から ISO-2022-JP へ文字コードを変換します。\n");
    wprintf(L"使用法\n");
    wprintf(L"> utf16_to_iso2022jp -i 入力ファイル -o 出力ファイル[Enter]\n");
    
    return 0;
}

/********************************************************************/
/**
 * 文字コードを UTF-16 より ISO-2022-JP へと変換。
 * 
 * @param[out] dest 出力文字列 ISO-2022-JP
 * @param[in]  dest_size destのバイト数
 * @param[in]  src 入力文字列 UTF-16
 * @param[in]  src_size 入力文字列の文字数
 * 
 * @return 成功時には出力文字列のバイト数を戻します。
 *         dest_size に0を指定し、こちらの関数を呼び出すと、変換された
 *         文字列を格納するのに必要なdestのバイト数を戻します。
 *         関数が失敗した場合には、(-1)を戻します。
 */
int Utf16ToIso2022jp(char *dest, size_t dest_size, wchar_t *src
        , size_t src_size)
{
    long                    countNeedsBytes     = 0;
    long                    cursor              = 0;
    const unsigned char dummy_code[] = {0x3f, 0x00, 0x00, 0x00, 0x00};
    const unsigned char *iso2022jpCode      = NULL;
    unsigned long           firstChar           = 0;
    unsigned long           firstIndex          = 0;
    int                     len                 = 0;
    unsigned char           newEscape[4];
    unsigned long           secondChar          = 0;
    unsigned long           secondIndex         = 0;
    long                    sizeBytes           = 0;
    wchar_t                 unicode             = 0x0000;
    unsigned char           currentEscape[4];
    
    /* ASCII */
    const unsigned char escapeASCII[]       = {0x1b, 0x28, 0x42, 0x00};
    
    /*
     * 入力パラメータをチェック
     */
    if (dest_size == 0)
    {
        /*
         * dest_size == 0
         */
    }
    else
    {
        /*
         * dest_size != 0
         */
        if (dest == NULL)
        {
            /* Error : dest is NULL. */
            return (-1);
        }
        if (dest_size < 0)
        {
            /* Error : dest_size < 0. */
            return (-1);
        }
    }
    if (src == NULL)
    {
        /* Error : src is NULL. */
        return (-1);
    }
    if (src_size < 0)
    {
        /* Error : src_size < 0. */
        return (-1);
    }
    
    countNeedsBytes = 0;
    memset(currentEscape, 0, sizeof(currentEscape));
    strcpy((char*)currentEscape, (char*)escapeASCII);
    for (cursor = 0; cursor < src_size; cursor++)
    {
        /* srcより1ワードのデータを読み出し */
        unicode = *(src + cursor);
        iso2022jpCode = dummy_code;
        firstChar = (unicode >> 8) & 0x00ff;
        secondChar = (unicode) & 0x00ff;
        firstIndex = firstChar & 0x00ff;
        /* byType(1:isEmpty 2:BitmapIndex 3:Index) */
        if (utf16_to_iso2022jp_index_table[firstIndex].byType == 2)
        {
            secondIndex = utf16_to_iso2022jp_index_table[firstIndex].dwIndex
                    + secondChar;
            if (utf16_to_iso2022jp_index_table[secondIndex].byType == 3)
            {
                iso2022jpCode = utf16_to_iso2022jp_table[
                        utf16_to_iso2022jp_index_table[secondIndex].dwIndex];
            }
        }
        len = bytelen(iso2022jpCode, 5);
        if ((unicode == 0) || (len <= 1))
        {
            sizeBytes = 1;
        }
        else
        {
            sizeBytes = 2;
        }
        getEscape(newEscape, iso2022jpCode);
        if (strcmp((char*)newEscape, (char*)currentEscape) != 0)
        {
            sizeBytes += 3;
        }
        
        /*
         * dest_size をチェック
         */
        if (dest_size && (dest_size < (countNeedsBytes + sizeBytes)))
        {
            /* Error : memory is not enough for dest */
            return countNeedsBytes;
        }
        
        if (dest_size)
        {
            if (strcmp((char*)newEscape, (char*)currentEscape) != 0)
            {
                *(dest) = newEscape[0];
                dest++;
                *(dest) = newEscape[1];
                dest++;
                *(dest) = newEscape[2];
                dest++;
                strcpy((char*)currentEscape, (char*)newEscape);
            }
            len = bytelen(iso2022jpCode, 5);
            if (len == 0)
            {
                if (unicode == 0)
                {
                    *(dest) = iso2022jpCode[0];
                    dest++;
                }
                else
                {
                    *(dest) = dummy_code[0];
                    dest++;
                }
            }
            else if (len == 1)
            {
                *(dest) = iso2022jpCode[0];
                dest++;
            }
            else
            {
                *(dest) = iso2022jpCode[3];
                dest++;
                *(dest) = iso2022jpCode[4];
                dest++;
            }
        }
        countNeedsBytes += sizeBytes;
    }
    
    if (strcmp((char*)escapeASCII, (char*)currentEscape) != 0)
    {
        sizeBytes = 3;
        
        /*
         * dest_size をチェック
         */
        if (dest_size && (dest_size < (countNeedsBytes + sizeBytes)))
        {
            /* Error : memory is not enough for dest */
            return countNeedsBytes;
        }
        
        if (dest_size)
        {
            *(dest) = escapeASCII[0];
            dest++;
            *(dest) = escapeASCII[1];
            dest++;
            *(dest) = escapeASCII[2];
            dest++;
        }
        countNeedsBytes += sizeBytes;
    }
    
    return countNeedsBytes;
}

・2008-10-21