IFS

9. RPG による IFS 開発 (2)

■ RPG で IFS ストリーム・ファイルをオープンして読み取る

ストリーム・ファイル は一般的に固定長ではないし DB2/400 のようなレコード形式も
持っていない。
ただ最初から最後まで一本の線のように繋がっているファイルである。
RPG によってストリーム・ファイルを読み取るにはどのようにすれば良いのだろうか ?
これは原理的には C言語でストリーム・ファイルを読み取るのでも同じことである。

1.ストリーム・ファイルを読取り専用としてオープンする。
2. ストリーム・ファイルの属性を取得して容量が何バイトあるかを調べる。
3. 容量分だけの動的なメモリを作成する。
4. 作成したメモリにファイルを読み込む。
5. ファイルをクローズする。
6. (メモリを使用する)
7. メモリを解放する。

というような手順で行うのである。つまり容量分だけの動的なメモリを確保して
そのメモリに読み込んで使い終わったらメモリを解放するというものである。

【 サンプル:TESTRED 】
-------------------------------------------------------------------------------------------
0001.00 H DATEDIT(*YMD/)  BNDDIR('QC2LE')                                                
0002.00 F********** IFS の読み取り ********************************************          
0003.00 F*                                                                               
0004.00 F* COMIPLE:                                                                      
0005.00 F*    CRTRPGMOD QTEMP/TESTRED SRCFILE(MYSRCLIB/QRPGLESRC) AUT*ALL)               
0006.00 F*    CRTPGM    MYLIB/TESTRED MODULE(QTEMP/TESTRED) ACTGRP(*NEW) AUT(*ALL)       
0007.00 F*                                                                               
0008.00 F**********************************************************************          
0009.00 D FD              S             10I 0                                            
0010.00                                                                                  
0011.00 D OPEN_           PR            10I 0 EXTPROC('open')                            
0012.00 D  PATH                           *   VALUE                                      
0013.00 D  FLAG                         10I 0 VALUE                                      
0014.00 D  MODE                         10I 0 VALUE OPTIONS(*NOPASS)                     
0015.00 D  CODEPAGE                     10I 0 VALUE OPTIONS(*NOPASS)                     
0016.00 D  TOPAGE                       10I 0 VALUE OPTIONS(*NOPASS)                     
0017.00                                                                                  
0018.00 D READ_           PR            10I 0 EXTPROC('read')                            
0019.00 D  FILEID                       10I 0 VALUE                                      
0020.00 D  BUFF                           *   VALUE                                      
0021.00 D  LEN_                         10I 0 VALUE                                      
0022.00                                                                                  
0023.00 D CLOSE_          PR                  EXTPROC('close')                           
0024.00 D  FILEID                       10I 0 VALUE                                 
0025.00                                                                             
0026.00 D LSTAT_          PR            10I 0 EXTPROC('lstat')                      
0027.00 D  PATH                           *   VALUE                                 
0028.00 D  INFO                           *   VALUE                                 
0029.00                                                                             
0030.00 D INFO            DS           128    QUALIFIED                             
0031.00 D   ALLOCSIZE                    5U 0 OVERLAY(INFO:47)                      
0032.00                                                                             
0033.00 D INFO_P          S               *   INZ(%ADDR(INFO))                      
0034.00 D TRUE            S             10I 0 INZ(0)                                
0035.00 D FALSE           S             10I 0 INZ(-1)                               
0036.00 D PERROR_         PR                  EXTPROC('perror')                     
0037.00 D  STR                            *   VALUE                                 
0038.00                                                                             
0039.00 D O_RDONLY        S             10I 0 INZ(1)                                
0040.00 D PATH            S             14A   INZ('/A001/TEST.TXT')                 
0041.00 D TMPLEN          S             10I 0                                       
0042.00 D BYTE_RED        S             10I 0                                       
0043.00 D RES             S             10I 0                                       
0044.00 D MSG             S             80A   INZ(' オープン・エラーです ')         
0045.00 D ATTR            S             80A   INZ(' 属性が取得できません ')         
0046.00 D SUCCESS         S             16A   INZ(' 読取り成功です ')               
0047.00 D TMPBUF          S               *                                         
0048.00 D ANS             S              1A                                           
0049.00                                                                               
0050.00  /FREE                                                                        
0051.00     FD = OPEN_(%ADDR(PATH): O_RDONLY); // ファイルをオープンする              
0052.00     IF (FD < 0);                                                              
0053.00        PERROR_(%ADDR(MSG));                                                   
0054.00        RETURN;                                                                
0055.00     ELSE;                                                                     
0056.00        RES = LSTAT_(%ADDR(PATH): INFO_P);// 属性を取得                        
0057.00        IF (RES = FALSE);                                                      
0058.00          PERROR_(%ADDR(ATTR));                                                
0059.00          CLOSE_(FD);                                                          
0060.00          RETURN;                                                              
0061.00        ENDIF;                                                                 
0062.00        TMPLEN = INFO.ALLOCSIZE;// 割振り長を取得                              
0063.00        IF ( TMPLEN > 0 );                                                     
0064.00          PERROR_(%ADDR(SUCCESS));                                             
0065.00          RETURN;                                                              
0066.00        ELSE;                                                                  
0067.00          TMPBUF = %ALLOC(TMPLEN);// 動的にメモリを確保                        
0068.00          BYTE_RED = READ_(FD: TMPBUF: TMPLEN); // READ 読取り                 
0069.00          DSPLY SUCCESS '' ANS;                                                
0070.00          DEALLOC  TMPBUF;        // 確保したメモリを解放                      
0071.00        ENDIF;                                                                 
0072.00     ENDIF;       
0073.00     CLOSE_(FD);  
0074.00     *INLR = *ON; 
0075.00  /END-FREE         
-------------------------------------------------------------------------------------------
【 解説 】

先に紹介した open, close 関数に加えて、ここでは lstat, read 関数が新しく使用されている。

0018.00 D READ_           PR            10I 0 EXTPROC('read')                            
0019.00 D  FILEID                       10I 0 VALUE                                      
0020.00 D  BUFF                           *   VALUE                                      
0021.00 D  LEN_                         10I 0 VALUE  
  :
0026.00 D LSTAT_          PR            10I 0 EXTPROC('lstat')                      
0027.00 D  PATH                           *   VALUE                                 
0028.00 D  INFO                           *   VALUE   
● lstat 関数

lstat とはファイルの詳細な情報を取得する関数であり、
lstat 関数は システム API 解説書の中では

------- 構文 ---------------------------------------------------------------
#include <sys/stat.h>

int lstat(const char* path, struct stat *buf);
【 パラメータ 】

path (入力)

オープンするファイルの NULL 終了パス名を指すポインター。

buf

情報を書き込む区域を示すポインター。

として定義されている。つまり IFS のパス名を与えるとファイル情報の構造体 buf
戻り値として取得できることを示している。
lstat 関数によってこの IFSストリーム・ファイルが IFS 上で割り振られている長さ: INFO.ALLOCSIZE
取得することができる。
IFS ストリーム・ファイルのデータは、ひとつの変数の中に読み込むのであるが、
どれだけの長さか最初は不明であり、オープンしただけではわからない。
そこで lstat 関数によってファイルの詳細情報として、割り振られている長さ: INFO.ALLOCSIZE
取得するのである。

次にこの TMPLEN = INFO.ALLOCSIZE の長さの分だけの変数を

0067.00          TMPBUF = %ALLOC(TMPLEN);//動的にメモリを確保

によって動的なメモリを確保する。

変数 : TMPBUF は最初は

0047.00 D TMPBUF          S               *

として定義されているだけの単なるポインターであるが %ALLOC によって長さも定義されるので
以降は変数扱いすることができる。

次にこの長さ TMPLEN を使って read 関数によってデータを読み取るのである。

● read 関数

read 関数は システム API 解説書の中では

------- 構文 ---------------------------------------------------------------
#include <unistd.h>

ssize_t = read(int fildes, void* buf, size_t nbyte);
【 パラメータ 】

fildes (入力)

読み取られる記述子

buf (出力)

読み取られるバイト数が置かれるバッファーを示すポインター

nbyte (入力)

読み取られるバイト数

戻り値

value   read() が正常に実行されて読み取られたバイト数

-1      read() の実行でエラーがあった

として定義されている。
実際の使用では、

0068.00          BYTE_RED = READ_(FD: TMPBUF: TMPLEN); // READ 読取り

のようにして TMPBUF の中に IFSストリーム・ファイル全体が収められ、読み取られた長さは
BYTE_RED バイトであることになる。
最後には

0070.00          DEALLOC  TMPBUF;        // 確保したメモリを解放 

のようにして DEALLOC 命令によって動的に確保したメモリを解放することを忘れてはいけない。

このサンプル: TESTRED は、どのようなツールも使わずに極めてシンプルな手法による
IFS ストリーム・ファイルを読み取る方法を示している。
システム API の構文を紹介したのは C言語の関数の構文が RPG で、どのようにプロトタイプとして
定義されているかを学習して欲しかったからである。
RPG プログラマーが C 関数を自由に使いこなせるようになれば実行可能な世界がかなり広がることになる。