Tools

72. ファイルの CCSID を取得する RTVCCSID

ツールを作成しているとファイルの CCSID を指定して変換などを行う場合
どうしてもそのファイルの CCSID を取得する必要に迫られてくる。
しかし DSPFD のようなコマンドは存在しないし RTVOBJD では CCSID を
取得することはできない。
データ・ベースの記述を検索する API: QDBRTVFD が提供されているが
これは莫大な情報量を持っていて簡単には扱うことはできない。
一般には API : QDBRTVFD を C 言語や RPG で検索することになるが
( https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_72/apis/qdbrtvfd.htm )
どこにどんな情報が載っているかを調べるだけで相当な時間を要する。
そこでここでは CLP でお手頃に簡単に調べるサンプルを紹介する。
API : QDBRTVFD を使う入り口にでもなれば幸いである。

実行の様子

                     ファィルの CCSID の検索 (RTVCCSID)   
                                                           
選択項目を入力して,実行キーを押してください。             
                                                           
ファイル  . . . . . . . . . . .   SHOHIN         名前      
  ライブラリー  . . . . . . . .     QTRFIL       文字値    
CCSID  . . . . . . . . . .                  数値      

解説

RTVCCSID は実際は対話式で使用することはない。
バッチで CLP などに組み込んで使って CCSID パラメータ (数字(5,0))にCCSIDの
値が戻される。

【 CMD: RTVCCSID 】
0001.00              CMD        PROMPT(' ファィルの CCSID の検索 ')            
0002.00              PARM       KWD(FILE) TYPE(FILE) +                         
0003.00                           PROMPT(' ファイル ')                         
0004.00  FILE:       QUAL       TYPE(*NAME) LEN(10)                            
0005.00              QUAL       TYPE(*CHAR) LEN(10) DFT(*LIBL) +               
0006.00                           PROMPT(' ライブラリー ')                     
0007.00              PARM       KWD(CCSID) TYPE(*DEC) LEN(5 0) RTNVAL(*YES) +  
0008.00                           PROMPT(' CCSID ')                       
【 コンパイル 】
CRTCMD CMD(MYLIB/RTVCCSID) PGM(MYLIB/RTVCCSIDCL) SRCFILE(MYSRCLIB/QCMDSRC)
 ALLOW(*BPGM *IPGM) AUT(*ALL)
【 CLP : RTVCCSIDCL 】
0001.00              PGM        PARM(&FILFILLIB &CCSID)                         
0002.00 /*---------------------------------------------------------*/           
0003.00 /*   RTVCCSID    :    ファィルの CCSID の検索              */           
0004.00 /*---------------------------------------------------------*/           
0005.00              DCL        VAR(&MSG) TYPE(*CHAR) LEN(132)                  
0006.00              DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)                  
0007.00              DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(132)               
0008.00              DCL        VAR(&MSGF) TYPE(*CHAR) LEN(10) +                
0009.00                           VALUE('QCPFMSG   ')                           
0010.00              DCL        VAR(&MSGFLIB) TYPE(*CHAR) LEN(10) +             
0011.00                           VALUE('*LIBL     ')                           
0012.00              DCL        VAR(&TYPE) TYPE(*CHAR) LEN(1)                   
0013.00              DCL        VAR(&FILFILLIB) TYPE(*CHAR) LEN(20)             
0014.00              DCL        VAR(&FILE) TYPE(*CHAR) LEN(10)                  
0015.00              DCL        VAR(&FILLIB) TYPE(*CHAR) LEN(10)                
0016.00              DCL        VAR(&CCSID) TYPE(*DEC) LEN(5 0)                 
0017.00              DCL        VAR(&RCVVAR) TYPE(*CHAR) LEN(512)               
0018.00              DCL        VAR(&RCVLEN) TYPE(*CHAR) LEN(4)                 
0019.00              DCL        VAR(&CCSID1) TYPE(*DEC) LEN(7 0) /*  FILE +     
0020.00                           CCSID       */                                
0021.00              DCL        VAR(&RTNNAM) TYPE(*CHAR) LEN(20) /* RETURNED +  
0022.00                           FILE NAME  */                                 
0023.00              DCL        VAR(&APIERR) TYPE(*CHAR) LEN(116) +             
0024.00                           VALUE(X'000074') /* 2 進数  */                   
0025.00              DCL        VAR(&NULL4) TYPE(*CHAR) LEN(4) +                   
0026.00                           VALUE(X'00000000')                               
0027.00              MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))            
0028.00                                                                            
0029.00              RTVJOBA    TYPE(&TYPE)                                        
0030.00              CHGVAR     VAR(&FILE) VALUE(%SST(&FILFILLIB 01 10))           
0031.00              CHGVAR     VAR(&FILLIB) VALUE(%SST(&FILFILLIB 11 10))         
0032.00              CHGVAR     VAR(%BIN(&RCVLEN)) VALUE(512)                      
0033.00              CALL       PGM(QDBRTVFD) PARM(&RCVVAR &RCVLEN &RTNNAM +       
0034.00                           'FILD0200' &FILFILLIB '*FIRST    ' '0' +         
0035.00                           '*FILETYPE' '*INT' &APIERR)                      
0036.00   /*( API エラー )*/                                                       
0037.00              IF         COND(%SST(&APIERR 5 4) *NE &NULL4) THEN(DO)        
0038.00              CHGVAR     VAR(&MSGID) VALUE(%SST(&APIERR 9 7))               
0039.00              CHGVAR     VAR(&MSGDTA) VALUE(%SST(&APIERR 17 100))           
0040.00              GOTO       SNDMSG                                             
0041.00              ENDDO                                                         
0042.00   /*( 正常に取得成功 )*/                                                   
0043.00              CHGVAR     VAR(&CCSID1) VALUE(%BIN(&RCVVAR 46 2))             
0044.00              CHGVAR     VAR(&CCSID) VALUE(&CCSID1)                         
0045.00              IF         COND(&CCSID *EQ -1) THEN(CHGVAR VAR(&CCSID) +      
0046.00                           VALUE(65535))                                    
0047.00              RETURN                                                        
0048.00                                                                      
0049.00  ERROR:      RCVMSG     MSGTYPE(*LAST) RMV(*NO) MSG(&MSG) +          
0050.00                           MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) +
0051.00                           MSGFLIB(&MSGFLIB)                          
0052.00  SNDMSG:                                                             
0053.00              IF         COND(&TYPE *EQ '0') THEN(DO)                 
0054.00              SNDPGMMSG  MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +         
0055.00                           MSGDTA(&MSGDTA) TOMSGQ(*SYSOPR) +          
0056.00                           MSGTYPE(*COMP)                             
0057.00              ENDDO                                                   
0058.00              ELSE       CMD(DO)                                      
0059.00              SNDPGMMSG  MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +         
0060.00                           MSGDTA(&MSGDTA) TOMSGQ(*TOPGMQ) +          
0061.00                           MSGTYPE(*ESCAPE)                           
0062.00              ENDDO                                                   
0063.00              ENDPGM                                                  
【 コンパイル 】
CRTCLPGM PGM(MYLIB/RTVCCSIDCL) SRCFILE(MYSRCLIB/QCLSRC) AUT(*ALL)

解説
0033.00              CALL       PGM(QDBRTVFD) PARM(&RCVVAR &RCVLEN &RTNNAM +       
0034.00                           'FILD0200' &FILFILLIB '*FIRST    ' '0' +         
0035.00                           '*FILETYPE' '*INT' &APIERR)

が API: QDBRTVFD を使用している部分である。
受取り変数 &RCVVAR は 512 バイトしか定義していなくてこの変数が
512 バイトしかないことを

0032.00              CHGVAR     VAR(%BIN(&RCVLEN)) VALUE(512)

で API に教えている。
QDBRTVFD のすべての情報を戻すには &RCVVAR は 5000 バイトくらいは
必要であるが今回の場合は

0043.00              CHGVAR     VAR(&CCSID1) VALUE(%BIN(&RCVVAR 46 2))             
0044.00              CHGVAR     VAR(&CCSID) VALUE(&CCSID1)

のようにして CCSID だけを取得するだけなのでこれで十分である。
API は受取り変数の長さに応じた結果だけを戻すように設計されているので
必ずしも全部の長さを定義しておく必要はない。
取得した CCSID が -1 であるとは CCSID= 65535 であることを示している。

0045.00              IF         COND(&CCSID *EQ -1) THEN(CHGVAR VAR(&CCSID) +      
0046.00                           VALUE(65535))

CCSID が 65535 であるというのは CCSID がホワイトの無地の状態で
このファイルがおかれたジョブ環境に染まるという状態である。
参考までにある大手特約店では SE が 5250 エミュレータで Ctrlキー + F3キーで
ジョブの実行 CCSID が変わる?!と教えられたと言っていたがとんでもない間違い。
キー・ボード操作だけでジョブの実行 CCSID が変わるのなら危なくて
しようがない。
これはわかりやすくするためのただの都市伝説である。
もうひとつ CCSID: 1399 はユニコードである、というとんでもない都市伝説を
言ったり個人サイトで公示している人もいるがこれも大きな間違い。
ユニコードの CCSID は UTF-8 が 1208, UTF-16 が 1200 とちゃんと CCSID が
存在していてこの CCSID は全世界のコンピュータに共通であり IBM i だけが
異なる CCSID であることはない。

さらにユニコードの半角は 2バイトで全角は 3バイトである。
( UTF-8 の半角は 1バイト)
IBM i の EBCDIC コードが 1399 になると漢字が突然 3バイトになることは
あり得ない。
CCSID: 1399 はユニコードである、という SE がいたら信用してはいけない。