第5章  内部/外部記述
RPGプログラマーの為のC言語講座

RPGのI/O環境に一番近い、ILE−Cの拡張関数を使用した場合を見てみましょう

他のプラットフォームでCをばりばり書いていた方も、以外とつまずくところではないでしょうか?

例によってまずRPGから見てみましょう。

最初のRPGは、内部記述のFILEに1レコード出力する物です。

DDS定義は省略して、ソースファイルを使用します。

CRTSRCPF FILE(CLAB/CLAB1P) MBR(CLAB1P) IGCDTA(*YES)を実行してください。

内部記述ファイルI/O FILE1R

     H            Y/                                    1             
     H*------------------------------------------------------------*  
     H* PROGRAM-ID    :    FILE1R                                  *  
     H* REMARKS       :    内部記述ファイルI/O             *  
     H* AUTHOR        :    Y.IDE                                   *  
     H* DATE-WRITEN   :    98/08/22                                *  
     H* VERSION       :    01.00 ORIGINAL                          *  
     H*------------------------------------------------------------*
     FCLAB1P  O   F      92            DISK                      A    
     C*                                                               
     C                     MOVE '000100'  ASEQ    6                   
     C                     MOVE '999999'  ADAT    6                   
     C                     MOVE *ALL'A'   ASTR   80                   
     C                     EXCPTE#OUT                                 
     C                     SETON                     LR               
     C                     RETRN                                      
     O*------------------------------------------------------------*
     OCLAB1P  EADD             E#OUT                                 
     O                         ASEQ       6                          
     O                         ADAT      12                          
     O                         ASTR      92

特に説明は不要だとは思いますが、F仕様書には
出力専用にオープンし、FILEは内部記述でレコード長は92のDISKファイルにレコードを追加する

と定義してます

さっそく、Cで書いて見ましょう!

ファイルI/O FILE1C

/*---------------------------------------------------------------*/   
/* PROGRAM-ID  : FILE1C                                          */   
/* REMARKS     : ファイルI/O                                */   
/* AUTHOR      : Y.Ide                                           */   
/* DATE-WRITEN : 98/08/22                                        */   
/* VERSION     : 01.00 ORIGINAL                                  */   
/*---------------------------------------------------------------*/
/*  標準のCでは、ファイルはストリームファイルとして             */   
/*  扱われます。                                                 */   
/*  AS/400のILE−Cでは、ファイルをレコードとして扱う   */   
/*  ための言語拡張がなされています。                             */   
                                                                      
#include <stdio.h>                                                    
#include <stdlib.h>                                                   
#include <recio.h>                                                    
                                                                      
typedef struct {                                                      
   char srcseq[6];                                                    
   char srcdat[6];                                                    
   char srcdta[80];
 } SRC;                                                       
                                                              
 int main(void)                                               
 {                                                            
   _RFILE      *fp;                                           
   SRC         src;                                           
                                                              
     if (( fp = _Ropen ( "CLAB/CLAB1P", "ar" )) == NULL )     
     {                                                        
         printf ( "OPEN ERROR\n" );                           
         exit ( 1 );                                          
     }                                                        
                                                              
      memcpy(src.srcseq,"000100",6);                          
      memcpy(src.srcdat,"999999",6);                          
      memset(src.srcdta,'A',80);                              
                                                              
      _Rwrite(fp, &src, 92);                                  
                                                              
     _Rclose ( fp );

     return(0); 
 }                                                            

_Ropen("CLAB/CLAB1P", "ar")でファイルを出力用にオープンします。

    RPGではプログラム起動時の初期設定の中で、ファイルのオープンも行います。

    マニュアル/メッセージなどでは、「暗黙のオープン」などと書かれています。

    「暗黙のオープン」なんてなんだかすごい用語ですが、 要はF仕様書に定義してあるファイルは、デフォルトで初期設定時にオープンしますよってことです。

次のRPGは、外部記述のFILEに1レコード出力する物です。

外部記述ファイルI/O FILE2R

     H            Y/                                    1              
     H*------------------------------------------------------------*   
     H* PROGRAM-ID    :    FILE2R                                  *   
     H* REMARKS       :    外部記述ファイルI/O             *   
     H* AUTHOR        :    Y.IDE                                   *   
     H* DATE-WRITEN   :    98/08/22                                *   
     H* VERSION       :    01.00 ORIGINAL                          *   
     H*------------------------------------------------------------*
     FCLAB1P  O   E                    DISK                      A
     F            CLAB1P                            KRENAMECLAB1R      
     C*                                                                
     C                     MOVE '000100'  SRCSEQ                       
     C                     MOVE '999999'  SRCDAT                       
     C                     MOVE *ALL'A'   SRCDTA                       
     C                     WRITECLAB1R                                 
     C                     SETON                     LR                
     C                     RETRN                                       

外部定義なので、F仕様書の定義内容は、FからEに変わり、レコード長の指定もありません。

外部記述なので、O仕様書でフィールド定義する必要もありません。

外部記述した場合は、コンパイラーがFILEのDDSから、フィールド定義情報を取り出し、

RPGのソースコードに展開します。

コンパイルリストを参照すれば、展開された内容を見ることができます。

上記のPGMのコンパイルリストは以下の様になるでしょう

......
  800  H*--------------------------------------------------------*  
  900  FCLAB1P  O   E                    DISK                      A    
 1000  F            CLAB1P                            KRENAMECLAB1R     
 1100  C*                                                               
           レコード様式 :   ライブラリー CLAB ファイル CLAB1P
                  外部様式 CLAB1P RPG 名 CLAB1R
 1200  C                     MOVE '000100'  SRCSEQ
 1300  C                     MOVE '999999'  SRCDAT
 1400  C                     MOVE *ALL'A'   SRCDTA
 1500  C                     WRITECLAB1R
 1600  C                     SETON                     LR
 1700  C                     RETRN
A000000   OUTPUT  レコード CLAB1R ファイル CLAB1P 様式 CLAB1P のフィールド
A000001                            SRCSEQ     6  ZONE  6,2
A000002                            SRCDAT    12  ZONE  6,0
A000003                            SRCDTA    92  CHAR   80  
           * * * * *      原 始 の 終 り       * * * * *

出力フィールドがPGM内に展開されています

Cでは、外部記述に対応するため、コンパイラーが、以下のような方法を使用します。

コンパイラーは、コンパイルのプリプロセス(事前準備)のステップで、DDSからフィールド 定義情報を取り出し、Cの構造体として展開し、展開後のソースをインクルードしてプログラムで 使用できるようにします。

ファイルI/O FILE2C

 /*---------------------------------------------------------------*/  
 /* PROGRAM-ID  : FILE2C                                          */  
 /* REMARKS     : ファイルI/O                                */  
 /* AUTHOR      : Y.Ide                                           */  
 /* DATE-WRITEN : 98/08/22                                        */  
 /* VERSION     : 01.00 ORIGINAL                                  */  
 /*---------------------------------------------------------------*/
 /*  DDS定義のフィールド情報をincludeして使用できます   */

 #include <stdio.h>                                                   
 #include <stdlib.h>                                                  
 #include <recio.h>                                                   

 #pragma mapinc("SRC","CLAB1P(*all)","both","z")                      
 #include "SRC"                                                       

 int main(void)
 {                 
   _RFILE                            *fp;                             
   CLAB_CLAB1P_CLAB1P_both_t         src;                             
                                                         
    if (( fp = _Ropen ( "CLAB/CLAB1P", "ar" )) == NULL ) 
    {                                                    
        printf ( "OPEN ERROR\n" );                       
        exit ( 1 );                                      
    }                                                    
                                                         
     memcpy(src.SRCSEQ,"000100",6);                      
     memcpy(src.SRCDAT,"999999",6);                      
     memset(src.SRCDTA,'A',80);                          
                                                         
     _Rwrite(fp, &src, 92);                              
                                                         
    _Rclose ( fp );                                      
                                                         
     return(0);                                          
}

CRTBNDCコマンドに、*SHOWUSRオプションで、コンパイルしてください

コンパイルリストは以下の様になるでしょう

   *...+....1....+....2....+....3....+....4....+....5....+....6....+....
  |/*---------------------------------------------------------------*/  
  |/* PROGRAM-ID  : FILE1C                                          */  
  |/* REMARKS     : ファイルI/O                                */  
  |/* AUTHOR      : Y.Ide                                           */  
  |/* DATE-WRITEN : 98/08/22                                        */  
  |/* VERSION     : 01.00 ORIGINAL                                  */  
  |/*---------------------------------------------------------------*/  
  |/*  DDS定義のフィールド情報をincludeして使用できます   */  
  |                                                                     
  |#include <stdio.h>                                                   
  |#include <stdlib.h>                                                  
  |#include <recio.h>                                                   
  |                                                                     
  |#pragma mapinc("SRC","CLAB1P(*all)","both","z") 
  |#include "SRC" 
  |/* ----------------------------------------------
  |/* PHYSICAL FILE: CLAB/CLAB1P                    
  |/* FILE CREATION DATE: 98/08/22                   
  |/* RECORD FORMAT: CLAB1P                            
  |/* FORMAT LEVEL IDENTIFIER: 1EF087AE71485
  |/* ----------------------------------------------
  |typedef struct {
  |   char SRCSEQ[6];      /*  ZONED SPECIFIED IN DDS
  |                                     /*  REPLACED BY CHARACTER TYPE
  |   char SRCDAT[6];       /*  ZONED SPECIFIED IN DDS
  |                                     /*  REPLACED BY CHARACTER TYPE
  |   char SRCDTA[80];
  |}CLAB_CLAB1P_CLAB1P_both_t;  
  |
  |int main(void).....

DDS定義情報が、対応するCのデータ型に変更され、構造体にまとめられてます。

DDS定義とCのデータ型の対応を調べる為、すべてのフィールドタイプを定義した、 下記の物理ファイルを作成しましょう。

CLAB2P
        *****************  データの始め  ******************************
0001.00      A          R CLAB2R                                       
0002.00      A            KEY            1A         COLHDG('A FLD')    
0003.00      A            P01           10P 2       COLHDG('P FILD')   
0004.00      A            S01           10S 0       COLHDG('S FLD')    
0005.00      A            B01            9B 0       COLHDG('B FLD')    
0006.00      A            B02            4B 0       COLHDG('B FLD')    
0007.00      A            F01            9F         COLHDG('F FLD')    
0008.00      A            L01             L         COLHDG('L FLD')    
0009.00      A            T01             T         COLHDG('T FLD')    
0010.00      A            Z01             Z         COLHDG('Z FLD')    
0011.00      A            A01           10A         COLHDG('A FLD')    
0012.00      A            H01           10H         COLHDG('H FLD')    
0013.00      A            J01           20J         COLHDG('J FLD')    
0014.00      A            E01           20E         COLHDG('E FLD')    
0015.00      A            O01           20O         COLHDG('O FLD')    
0016.00      A            G01           20G         COLHDG('G FLD')    
        *****************  データの終り  **********************************

CLAB2PをインクルードするCのプログラム FILE3C

/*--------------------------------------------------------------*/  
/* PROGRAM-ID  : FILE3C                                         */  
/* REMARKS     : いろんなフィールドタイプをインクルード         */  
/* AUTHOR      : Y.Ide                                          */  
/* DATE-WRITEN : 98/08/22                                       */  
/* VERSION     : 01.00 ORIGINAL                                 */  
/*--------------------------------------------------------------*/  
/* CRTBNDC PGM(FILE3C) OUTPUT(*PRINT) OPTION(*SHOWUSR)  で      */  
/*  コンパイルしてください                                      */ 

 #include <stdio.h>                                                  
 #include <stdlib.h>                                                 
 #include <recio.h>                                                  

 #include <decimal.h>  
/*PACKのデータ型の定義に必要*/
/*定義し忘れると、原因に気がつきにくいコンパイルエラーになります。*/
                                                                     
 #pragma mapinc("REC","CLAB/CLAB2P(CLAB2R)","both","d z")
 #include "REC"                                               
                                                                     
 int main(void)                                                      
 {                                                                   
   _RFILE                            *fp;              
   CLAB_CLAB2P_CLAB2R_both_t         rec;              
                                                       
     if (( fp = _Ropen ( "CLAB2P", "ar" )) == NULL )   
     {                                                 
         printf ( "OPEN ERRORn" );                    
         exit ( 1 );                                   
     }                                                 
                                                       
     _Rclose ( fp );                                   
                                                       
      return(0);                                       
 }

CRTCBND FILE3C *PRINT *SHOWUSRでコンパイルして、コンパイルリストで確認して見てください。
コンパイルリストは以下の様になるでしょう

コンパイルリスト(関連部分の抜粋)

 ..+....2....+....3....+....4....+....5....+....6....+....7....+....8....+..  
 |#pragma mapinc("REC","CLAB/CLAB2P(CLAB2R)","both","d z")                    
 |#include "REC"                                                              
 |/* -----------------------------------------------------------------------  
 |/* PHYSICAL FILE: CLAB/CLAB2P                                               
 |/* FILE CREATION DATE: 98/08/22                                             
 |/* RECORD FORMAT: CLAB2R                                                    
 |/* FORMAT LEVEL IDENTIFIER: 2F9E57F385921                                   
 |/* -----------------------------------------------------------------------  
 |typedef struct {                                                            
 |   char KEY[1];                         /*  A FLD                           
 |   decimal(10, 2) P01;                  /*  P FILD                          
 |                                        /*  PACKED SPECIFIED IN DDS         
 |   char S01[10];                        /*  S FLD                           
 |                                        /*  ZONED SPECIFIED IN DDS          
 |                                        /*  REPLACED BY CHARACTER TYPE      
 |   int B01;                             /*  B FLD                     
 |   short int B02;                       /*  B FLD            
 |   float F01;                           /*  F FLD            
 |   char L01[10];                        /*  L FLD            
 |                                        /*  DATE FIELD       
 |                                        /*  DATFMT(*ISO)     
 |   char T01[8];                         /*  T FLD            
 |                                        /*  TIME FIELD       
 |                                        /*  TIMFMT(*ISO)     
 |   char Z01[26];                        /*  Z FLD            
 |                                        /*  TIMESTAMP FIELD  
 |   char A01[10];                        /*  A FLD            
 |   char H01[10];                        /*  H FLD            
 |   char J01[20];                        /*  J FLD            
 |   char E01[20];                        /*  E FLD            
 |   char O01[20];                        /*  O FLD            
 |   wchar_t G01[20];                     /*  G FLD
 |                                        /*  DDS - G DATA TYPE        
 |                                        /*  MAPS TO WIDE CHARACTER   
 |}CLAB_CLAB2P_CLAB2R_both_t;                                          
 |                                                                          

DDS定義とCのデータ型の対応表
DDS
C構造体
ゾーン十進数 Z
文字フィールド A O J E
潜在フィールド H
日時関連 L T Z
文字配列 char xxx[9];
パック十進数 P パックデータ型 decimal(9, 9)XXX
バイナリー B int xxx, short int xxx
浮動小数 F float xxx
グラフィックデータタイプ G ワイドデータ型 wchar_t xxx[9]

RPGとCのファイルオープンモードの対応表

RPG
説明
FCLAB1P IF DISK _Ropen("CLAB1P","rr") レコードの読取り専用
CLRPFMした上で、
FCLAB1P O DISK A
_Ropen("CLAB1P","wr") レコードの書込み専用
ファイルにデータがある場合には消去されます。
FCLAB1P O DISK A _Ropen("CLAB1P","ar") ファイルの終りへのレコードの書込み (追加)
FCLAB1P U DISK A _Ropen("CLAB1P","rr+") レコードの読取り、書込み、更新
CLRPFMした上で、
FCLAB1P U DISK A
_Ropen("CLAB1P","wr+") レコードの読取り、書込み、更新
ファイルにデータがある場合には消去されます。
FCLAB1P I DISK A _Ropen("CLAB1P","ar+") レコードの読取りおよび書込み
すべてのデータはファイルの終りに書き込まれます。