「COBOL 処理パターン 外部サブプログラム呼ぶ」 のサブプログラムをC言語で作成してみる。
入出力構成図
ソースコード
メインプログラム
顧客マスタテーブルの有効件数を数値項目(COMP-X)として定義する。これを引数にして Cプログラムに渡すと、数値項目の桁数によりC側での整数の大きさ(1バイト、2バイト、4バイト、8バイト)が自動的に決まる。
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIN01.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
*入力ファイル 行順編成ファイル(テキストファイル)
SELECT F1 ASSIGN TO "./R002.txt"
ORGANIZATION IS LINE SEQUENTIAL
ACCESS MODE IS SEQUENTIAL.
*出力ファイル 行順編成ファイル(テキストファイル)
SELECT F2 ASSIGN TO "./R003.txt"
ORGANIZATION IS LINE SEQUENTIAL
ACCESS MODE IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
* 入力ファイル
FD F1.
01 F1R.
05 CUST-CODE PIC 9(04).
05 SALES PIC 9(10).
* 出力ファイル
FD F2.
01 F2R.
05 CUST-CODE PIC 9(04).
05 SALES PIC 9(10).
05 CUST-NAME PIC X(20).
WORKING-STORAGE SECTION.
01 END-FLG PIC 9(01).
01 I PIC 9(02).
01 RETURN-VALUE PIC 9(03).
* 顧客マスターテーブル有効件数(8バイト)
01 CUST-COUNT PIC 9(18) COMP-X VALUE 0.
* 顧客マスターテーブル
01 CUST-TABLE.
05 CUSTOMER OCCURS 10 TIMES.
10 CUST-CODE PIC 9(04).
10 CUST-NAME PIC X(20).
PROCEDURE DIVISION.
******************************************************************
* 主処理
******************************************************************
PERFORM INIT-RTN
PERFORM LOOP-RTN UNTIL END-FLG NOT = 0
PERFORM END-RTN
STOP RUN.
******************************************************************
* 前処理
******************************************************************
INIT-RTN.
* 変数の初期化
INITIALIZE END-FLG
* ファイルオープン
OPEN INPUT F1
OPEN OUTPUT F2
* サブルーチンCALL
CALL "read_table" USING BY REFERENCE CUST-COUNT
BY REFERENCE CUST-TABLE
GIVING RETURN-VALUE
DISPLAY CUST-COUNT;
PERFORM VARYING I FROM 1 BY 1 UNTIL I > CUST-COUNT
DISPLAY CUST-CODE OF CUSTOMER(I) " "
CUST-NAME OF CUSTOMER(I)
END-PERFORM
* 1件目のレコードの入力
PERFORM READ-RTN.
INIT-RTN-EX.
EXIT.
******************************************************************
* 繰り返し処理
******************************************************************
LOOP-RTN.
* 出力レコードの編集
INITIALIZE F2R
MOVE CUST-CODE OF F1R TO CUST-CODE OF F2R
MOVE SALES OF F1R TO SALES OF F2R
MOVE SALES OF F1R TO SALES OF F2R
* 顧客マスターの検索
PERFORM VARYING I FROM 1 BY 1 UNTIL I > CUST-COUNT
IF CUST-CODE OF F1R = CUST-CODE OF CUSTOMER(I)
MOVE CUST-NAME OF CUSTOMER(I) TO CUST-NAME OF F2R
MOVE 99 TO I
END-IF
END-PERFORM
* レコードの出力
WRITE F2R
* 次のレコードの読み込み
PERFORM READ-RTN.
LOOP-RTN-EX.
EXIT.
******************************************************************
* 後処理
******************************************************************
END-RTN.
CLOSE F1 F2.
END-RTN-EX.
EXIT.
******************************************************************
* 入力処理
******************************************************************
READ-RTN.
READ F1
AT END
ADD 1 TO END-FLG
END-READ.
READ-RTN-EX.
EXIT.
サブプログラム
エンディアンの変換が必要
COBOL側はBig Endianだが、C言語側はLittle Endianになっている。引数の数値項目を整数値(COMP-X)とした場合、受け渡しのつどエンディアンの変換を行う必要がある。
エンディアンの変更は、単純なバイトスワップで良い。GNU Cライブラリに byteswap.hにマクロが定義されているのだが、OSXのライブラリにはなぜかないので、自身でマクロを実装している。
//------------------------------------------------------------------------------
// sublib.c
//------------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#define BUFFER_LEN 64
#define CODE_LEN 4
#define NAME_LEN 20
//バイトスワップ(As Mac OS X does not have byteswap.h)
//2バイト
#define bswap_16(value) \
((((value) & 0xff) << 8) | ((value) >> 8))
//4バイト
#define bswap_32(value) \
(((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \
(uint32_t)bswap_16((uint16_t)((value) >> 16)))
//8バイト
#define bswap_64(value) \
(((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) << 32) | \
(uint64_t)bswap_32((uint32_t)((value) >> 32)))
//顧客マスター構造体
struct _customer{
char code[CODE_LEN];
char name[NAME_LEN];
};
typedef struct _customer customer_t;
//COBOLインタフェース関数
int read_table(uint64_t *cust_count, char *cust_table){
/* endianの判定
int x=1; // 0x00000001
if (*(char*)&x) {
printf("little endian\n");
// little endian. memory image 01 00 00 00
}else{
printf("big endian\n");
// big endian. memory image 00 00 00 01
}
*/
//顧客マスターテーブル
customer_t custTable[10];
//ゼロクリア
for(int i=0; i<10; i++){
custTable[i] = (customer_t){0};
}
//顧客マスターファイルの読み込み
const char *file = "./M001.txt";
FILE *fp;
fp = fopen(file, "r");
char line[BUFFER_LEN];
unsigned short count = 0;
while(fgets(line, BUFFER_LEN, fp) != NULL){
//改行コードの削除
char *p = strchr(line, '\n');
if (p != NULL){
*p = '\0';
}
//顧客コード
strncpy(custTable[count].code, line, CODE_LEN);
//顧客名
int nlength = strlen(line)-CODE_LEN;
strncpy(custTable[count].name, line+CODE_LEN, nlength);
for (int i = nlength; i < NAME_LEN; i++){
custTable[count].name[i] = '\0';
}
count++;
}
*cust_count = count; //顧客マスターテーブル有効件数(8バイト)
*cust_count = bswap_64(*cust_count); //little endian -> big endian
printf("%d\n", count);
memcpy(cust_table, (char*)custTable, sizeof custTable);
return 0;
}
関連記事
COBOL 処理パターン 多段階集計
COBOL 処理パターン マッチング
COBOL 処理パターン テーブル展開
COBOL 処理パターン 外部サブプログラム呼ぶ