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
|
C
|
説明
|
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+")
|
レコードの読取りおよび書込み
すべてのデータはファイルの終りに書き込まれます。
|
|