ユニコード (UTF-8) の使用が一般的になってきた現在、IBM の EBCDIC コードを
ユニコードに変換する必要のある機会も多くなってくるはずだ。
コード変換API と言えば QDCXLATE が良く知られているが QDCXLATE は
EBCDIC/ASCII 間の変換しかサポートしていない。
すべての言語コードのあいだの変換を行なうAPI は、ここで紹介する iconv である。
iconv 関数は UNIX の API としても良く知られているが IBM System i では
独自の使用方法があるので、それをここで紹介する。
iconv による言語コードの変換には次の3段階のステップを必要とする。
(1) 変換ハンドルの作成
どのCCSID から どのCCSID への変換であることを宣言して変換ハンドルを生成する。
(2) 実際のコード変換
iconv 関数を使って変換ハンドルを指定して実際に変換を実行する。
(3) ハンドルのクローズ
使用済みの変換ハンドルをクローズする。
このステップを経ることが必要であることがIBM API マニュアルには明確に書かれていないので
当初は苦労すると思われる。
また QDCXLATE と iconv のちがいも API マニュアルには解説されていない。
ユニコードへの変換には iconv の利用が必要であるとも書かれていない。
実際はユニコードとの変換には iconv を利用するしかないのである。
iconv_t QtqIconvOpen(QtqCode_T* tocode, QtqCode_T* fromcode)
QtqIconvOpen() 関数は fromcode で定義されているCCSID から tocode として定義されている
CCSID へ文字コードを変換するための初期化を行なって変換識別子 iconv_t を戻す。
API には iconv_open という同じ機能の API も用意されていますが iconv_open 関数は正しく動作しない。
この QtqIconvOpen 関数を使用すること。
■ QtqCode_T の形式
| オフセット | タイプ | フィールド | |
|---|---|---|---|
| 10進数 | 16進数 | ||
0 | 0 | BINARY(4) | CCSID |
4 | 4 | BINARY(4) | 変換代替 |
8 | 8 | BINARY(4) | 代用代替 |
12 | C | BINARY(4) | シフト状態代替 |
16 | 10 | BINARY(4) | 入力の長さオプション |
20 | 14 | BINARY(4) | 混合データのエラー・オプション |
24 | 18 | CHAR(8) | 予約済み |
size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char** outbuf, size_t *outbytesleft)
iconv() 関数は入力文字列 : inbuf の値を cd として与えられた変換識別子に基づいて
ある CCSID から別の CCSID へ変換して変換結果の文字列を outbuf に入れて
変換した文字数を size_t として戻す。
ただし 入力inbuf, 出力 outbuf ともにポインターのポインターを定義する仕様になっている
ことに注意すること。
int iconv_close(iconv_t cd)
iconv_close() 関数は 変換識別子 cd をクローズする。
0001.00 #include <stdio.h>
0002.00 #include <stdlib.h>
0003.00 #include <string.h>
0004.00 #include <qtqiconv.h>
0005.00 #include <errno.h>
0006.00
0007.00 #define TRUE 0
0008.00 #define FALSE -1
0009.00 #define UTF8 1208
0010.00
0011.00 void main(void){
0012.00 char ebcbuf[128], unibuf[128];
0013.00 iconv_t cd;
0014.00 QtqCode_T fromcode, tocode;
0015.00 size_t inbyte, outbyte, rtnbyte;
0016.00 char* source, *target;
0017.00 int i, len;
0018.00
0019.00 printf("** TESTICONV : iconv による Unicode 変換テスト **\n");
0020.00 getchar();
0021.00 memset(&fromcode, 0, sizeof(fromcode));
0022.00 memset(&tocode, 0, sizeof(tocode));
0023.00 fromcode.CCSID = 5026;
0024.00 tocode.CCSID = UTF8;
0025.00 /*( 文字「A」を UNICODE に変換する )*/
0026.00 printf(" 文字「A」を UNICODE に変換する \n");
0027.00 memset(ebcbuf, 0, sizeof(ebcbuf));
0028.00 ebcbuf[0] = 0x0e;
0029.00 ebcbuf[1] = 0x42;
0030.00 ebcbuf[2] = 0xc1; /* 倍角の A */
0031.00 ebcbuf[3] = 0x0f;
0032.00 inbyte = strlen(ebcbuf);
0033.00 for(i = 0; i<inbyte; i++){/*for-loop*/
0034.00 printf("ebcbuf[%d] = 0x%02x\n", i, ebcbuf[i]);
0035.00 }/*for-loop*/
0036.00 /*(1) 変換ハンドルを作成 */
0037.00 cd = QtqIconvOpen(&tocode, &fromcode);
0038.00 if(cd.return_value == FALSE){
0039.00 printf("[ERR] QtqIconvOpen errno = %d\n", errno);
0040.00 getchar();
0041.00 exit(-1);
0042.00 }
0043.00 source = ebcbuf;
0044.00 target = unibuf;
0045.00 inbyte = strlen(ebcbuf);
0046.00 outbyte = sizeof(unibuf);
0047.00 /*(2) 変換を実行 */
0048.00 rtnbyte = iconv(cd, &source, &inbyte, &target, &outbyte);
0049.00 if(rtnbyte < 0){
0050.00 printf("failed in iconv: %s\n", strerror(errno));
0051.00 getchar();
0052.00 iconv_close(cd);
0053.00 exit(-1);
0054.00 }
0055.00 printf(" 文字「A」のユニコード変換結果 \n");
0056.00 for(i = 0; i<strlen(unibuf); i++){/*for-loop*/
0057.00 printf("unibuf[%d] = 0x%02x\n", i, unibuf[i]);
0058.00 }/*for-loop*/
0059.00 getchar();
0060.00 /*(3) 変換ハンドルをクローズ */
0061.00 iconv_close(cd);
0062.00 }
このサンプルは文字「A」(CCSID=5026)を UNICODE(CCSID=1208) に iconv を使って変換する
方法を示している。
([注意] CCSID=1399 は UNICODE ではない。UNICODE の漢字は3バイトによって
漢字の1文字を表現する。
CCSID=1399 は EBCDIC なので、やはり漢字は2バイトで表現する。
従ってCCSID=1399 は UNICODE とは何の関係もない。)
最初に「A」とは EBCDIC では
0028.00 ebcbuf[0] = 0x0e; 0029.00 ebcbuf[1] = 0x42; 0030.00 ebcbuf[2] = 0xc1; /* 倍角の A */ 0031.00 ebcbuf[3] = 0x0f;
である。
0023.00 fromcode.CCSID = 5026; 0024.00 tocode.CCSID = UTF8;
0037.00 cd = QtqIconvOpen(&tocode, &fromcode);
によって宣言して変換識別子(ハンドル) cd を取得する。
このハンドル cd を使って
0048.00 rtnbyte = iconv(cd, &source, &inbyte, &target, &outbyte);
によって 変換を実行すれば実行結果は target に収められ変換バイト数は rtnbyte である。
変換結果を
0056.00 for(i = 0; i<strlen(unibuf); i++){/*for-loop*/
0057.00 printf("unibuf[%d] = 0x%02x\n", i, unibuf[i]);
0058.00 }/*for-loop*/
によって表示したら
0061.00 iconv_close(cd);
によって変換ハンドルもクローズして終了する。
API: iconv のパラメータはポインターのポインターを使用しているため実行サンプルが
ないと実際にどのように記述すれば動作するのかが、なかなかわかりづらい。
しかし UNICODE がこれほど急に普及してきた時代背景を考えると EBCDIC/UNICODE の
変換は重要であり必須であると言える。
また国際言語化にとっても iconv の使い方をマスターしておくべきであろう。
最後にすべての CCSID の間を iconv だけですべて変換可能か? というとそういうわけでは
ないことを知ってして欲しい。
異なる CCSID の間の変換テーブルはべて System i に導入されているが、なかには
テーブルが用意されていないものがあり、これは QtqIconvOpen でエラーとなって
変換することはできない。
ただし QDCXLATE に比べて iconv のほうが実行速度も速く、変換精度も高いように思える。