RPG

179. RPG で Unicode ファイルを IFS に出力するには ? (1)

好むと好まざるにかかわらず RPG で Unicode を扱う必要がある時代はすぐそこにやってきている。
今から少しずつでも Unicode に馴染んでおきたいものである。
RPG で Unicode ( UTF-8 ) のストリーム・ファイルを IFS に出力するにはどのようにすればよいのだろうか ?

RPG で IFS へ Unicode ファイルを出力するサンプルを紹介しよう。

【 サンプル: TESTUNI 】
------------------------------------------------------------------------------------
0001.00 H DFTNAME(TESTUNI) DATEDIT(*YMD/) BNDDIR('QC2LE')                           
0002.00 F******** IFS への UNICODE 出力 ***************************************     
0003.00 F*                                                                          
0004.00 F*   CRTRPGMOD QTEMP/TESTUNI SRCFILE(PGMRLIB/QRPGLESRC) AUT(*ALL)           
0005.00 F*   CRTPGM    OBJLIB/TESTUNI MODULE(QTEMP/TESTUNI)                         
0006.00 F*               SRVPGM(QSYS/QP0LLIB1) AUT(*ALL)                            
0007.00 F*                                                                          
0008.00 F**********************************************************************     
0009.00 D FD              S             10I 0                                       
0010.00 D DATA            S           1000C   CCSID(1200)                           
0011.00                                                                             
0012.00 D OPEN_           PR            10I 0 EXTPROC('open')                       
0013.00 D  PATH                           *   VALUE                                 
0014.00 D  FLAG                         10I 0 VALUE                                 
0015.00 D  MODE                         10I 0 VALUE OPTIONS(*NOPASS)                
0016.00 D  CODEPAGE                     10I 0 VALUE OPTIONS(*NOPASS)                
0017.00 D  TOPAGE                       10I 0 VALUE OPTIONS(*NOPASS)                
0018.00                                                                             
0019.00 D WRITE_          PR            10I 0 EXTPROC('write')                      
0020.00 D  DESC                         10I 0 VALUE                                 
0021.00 D  DATA                           *   VALUE                                 
0022.00 D  DTALEN                       10I 0 VALUE                                 
0023.00                                                                             
0024.00 D CLOSE_          PR                  EXTPROC('close')                   
0025.00 D  DESC                         10I 0 VALUE                              
0026.00                                                                          
0027.00 D PERROR_         PR                  EXTPROC('perror')                  
0028.00 D  STR                            *   VALUE                              
0029.00                                                                          
0030.00 D O_CREAT         S             10I 0 INZ(8)                             
0031.00 D O_TRUNC         S             10I 0 INZ(64)                            
0032.00 D O_CCSID         S             10I 0 INZ(32)                            
0033.00 D O_WRONLY        S             10I 0 INZ(2)                             
0034.00 D S_IWUSR         S             10I 0 INZ(128)                           
0035.00 D S_IRUSR         S             10I 0 INZ(256)                           
0036.00 D PATH            S             14A   INZ('/A001/TEST.TXT')              
0037.00 D MSG             S             80A   INZ(' オープン・エラーです ')      
0038.00                                                                          
0039.00  /FREE                                                                   
0040.00      FD = OPEN_(%ADDR(PATH):                                             
0041.00                O_CREAT + O_TRUNC + O_CCSID + O_WRONLY :                  
0042.00                S_IWUSR + S_IRUSR :                                       
0043.00                1208);                                                    
0044.00     IF (FD < 0);                                                         
0045.00        PERROR_(%ADDR(MSG));                                              
0046.00        RETURN;                                                           
0047.00     ENDIF;                                                               
0048.00     DATA = %UCS2('hello UNICODE');                       
0049.00     WRITE_(FD : %ADDR(DATA) : %LEN(%TRIMR(DATA)) * 2);   
0050.00     CLOSE_(FD);                                          
0051.00     *INLR = *ON;                                         
0052.00  /END-FREE                                               
------------------------------------------------------------------------------------
【 コンパイル 】
CRTRPGMOD QTEMP/TESTUNI SRCFILE(PGMRLIB/QRPGLESRC) AUT(*ALL)
CRTPGM    OBJLIB/TESTUNI MODULE(QTEMP/TESTUNI) SRVPGM(QSYS/QP0LLIB1) AUT(*ALL)

のようにして QSYS/QP0LLIB1 *SRVPGM をバインドしてビルドする必要がある。
QSYS/QP0LLIB1 とは open, read, write, close 等の IFS API が保管されている
サービス・プログラムである。これらの関数は C/400 の関数( QC2LE ) ではないので
BNDDIR('QC2LE') には含まれていない。従って明示的にバインドしてやる必要がある。

米国雑誌でも IFS の入出力を RPG で行う方法のサンプル・ソースはよく紹介されているが
いずれも ある公開ライブラリーをダウンロードして導入しなければならない。
上記のように、どのような System i でも 動作する IFS への入出力の事例を示しているのは
珍しいはずである。(もちろん IBM マニュアルには掲載されていない。)

【 解説 】

上記の例では IFS の入出力の open, write, close を使っている以外として Unicode に係わる部分は

0010.00 D DATA            S           1000C   CCSID(1200)

0040.00      FD = OPEN_(%ADDR(PATH):
0041.00                O_CREAT + O_TRUNC + O_CCSID + O_WRONLY :
0042.00                S_IWUSR + S_IRUSR :
0043.00                1208);

0048.00     DATA = %UCS2('hello UNICODE');

の行だけである。
最初に DATA という 1000バイトのフィールドの定義で 1000CC は、この DATA
UCS-2 ( CCSID 13488 ) であることを宣言している。
CCSID(1200) は UTF-16 という意味である。( UTF-8 つまり CCSID(1208) を定義することはできない。)
次に CCSID = 1208 (UTF-8) を無理やり指定して ( UTF-16 であれば 1200 ) O_CCSID
オプション指定することによって open 関数を実行している。
これによって WRKLNK で作成された IFS ストリーム・ファイルの属性を調べれば
CCSID は 1208 つまり UTF-8 となっているはずである。
さらに

DATA = %UCS2('hello UNICODE');

によって 'hello UNICODE' という文字列を UTF-16 に置き換えている。
%UCS2 とは IBM によって RPG 上で提供されている Unicode 変換のための BIFF 関数である。

この TESTUNI というプログラムを実行してみると IFS には

h e l l o   U N I C O D E

という文字列が UTF-16 として出力されてるのを確認することができる。
半角で入力したはずの英小文字も倍角となっているのだから、これは UTF-16 である。

ところで %UCS2 は日本語漢字も UTF-16 に変換できるのだろうか ?
試してみたところ文字化けして全くダメであった。
また RPG は UTF-8 への変換をサポートする機能はあるのだろうか ?
これも %USC2UCS-2 ( CCSID 13488 ) だけへの変換であり、 UTF-8 への変換は
全くサポートされていない。
現実では Uncode は UTF-8 による使用が全世界で圧倒的多数を占めている。
IBM の対応は遅れている感が否めない。
EnterpriseServer では UNI_CODE *SRVPGM をユーザーに提供して UTF-8, EBCDIC, ASCII
の相互変換をサポートしている。