概要
以前の記事では、COBOLからCのプログラムを呼び出したので、今回は逆にCからCOBOLのプログラムを呼び出してみようと思います。
opensource COBOLの呼び出し
そもそもCOBOLの実行方法
opensource COBOLのプログラムはC言語に翻訳された上で、Cとしてコンパイルされています。
この際、SOモジュールとしたプログラムを実行する機能としてcobcrunが提供されています。
今回はこのcobcrunを参考にして、CからCOBOLを呼び出すプログラムを作成しました。
cobcrunの処理
cobcrunの処理としてmainの中は以下のようになっています。
int
main (int argc, char **argv)
{
int pcl_return;
union {
int (*func)();
void *func_void;
} unifunc;
#ifdef HAVE_SETLOCALE
setlocale (LC_ALL, "");
#endif
pcl_return = process_command_line (argc, argv);
if (pcl_return != 99) {
return pcl_return;
}
if (strlen (argv[1]) > 31) {
fprintf (stderr, "Invalid PROGRAM name\n");
return 1;
}
cob_init (argc - 1, &argv[1]);
unifunc.func_void = cob_resolve (argv[1]);
if (unifunc.func_void == NULL) {
cob_call_error ();
}
cob_stop_run ( unifunc.func() );
}
基本的に必要な処理は以下の4点です。
cob_init (argc - 1, &argv[1]);
libcobの初期化を行う関数です。
これをあらかじめ呼び出しておかないとCOBOLの呼び出しがエラーとなります。
unifunc.func_void = cob_resolve (argv[1]);
COBOLのSOファイルを動的にロードしています。
argv[1]
にはCOBOLのプログラムIDを入れます。
unifunc.func()
ロードしたプログラムを実行します。返り値はINTです。
cob_stop_run ( unifunc.func() );
COBOLのSTOPRUNにあたる終了処理です。
内部ではexit
システムコールを呼び出しているため、
プロセスごと終了してしまうので注意が必要です。
COBOLの呼び出し
上記を踏まえて、COBOLを呼び出すプログラムを作成します。
といっても、上記必要な関数を呼び出すだけになります。
#include <stdio.h>
#include <libcob.h>
int
main(int argc, char **argv)
{
int return_code;
union {
int (*func)();
void *func_void;
} unifunc;
cob_init (0, NULL);
unifunc.func_void = cob_resolve (argv[1]);
if (unifunc.func_void == NULL) {
cob_call_error ();
}
return_code = unifunc.func();
cob_stop_run ( return_code );
}
これを、libcobをリンクさせてコンパイルしていきます。(-I, -Lは適宜設定してください)
gcc -I/usr/cobol/include -L/usr/cobol/lib -lcob -o cblcall cblcall.c
あとは、引数にCOBOLプログラム名称を設定して起動すると、COBOLを呼び出すことができます。
HELLO.cblを呼び出してみます。
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
DATA DIVISION.
WORKING-STORAGE SECTION.
PROCEDURE DIVISION.
MAIN-RTN.
DISPLAY "HELLO WORLD!".
MAIN-EXT.
GOBACK.
[user@localhost test]$ ./cblcall HELLO
HELLO WORLD!
問題なく実行できています。
COBOL側でSTOP RUNを記述してしまうと、内部でexit
システムコールが呼び出されてしまうため、
親プログラムに返らず終了してしまうので注意してください。
引数について
COBOLに渡す引数については、以前の記事のCOBOLから受け取る引数とは多少動作がことなります。
COBOLデータ型 | 渡し方 | Cデータ型 | 備考 |
---|---|---|---|
数値型(PIC 9) | 参照渡し | char * | DISPLAY型の数値については、文字列で参照渡しをする必要がある |
文字列型(PIC X) | 参照渡し | char * | サイズを合わせてスペース埋めをする必要がある |
バイナリ型(COMP-X) | 値渡し | short,int,long(COBOLのサイズによる) | ENDIANによって動きが異なる可能性あり |
バイナリ型(COMP-X) | 参照渡し | short *,int *,long *(COBOLのサイズによる) | ENDIANによって動きが異なる可能性あり |
COBOL側はLINKAGEに定義し、PROCEDUREのUSINGに渡し方を記載する形になります。
今回もintとchar *の値を連携してみようと思います。
以下、サンプルになります。
#include <stdio.h>
#include <libcob.h>
int
main(int argc, char **argv)
{
int return_code;
union {
int (*func)();
void *func_void;
} unifunc;
int value1 = 11;
char value2[2] = "11";
char value3[10] = "HELLO! ";
cob_init (0, NULL);
unifunc.func_void = cob_resolve (argv[1]);
if (unifunc.func_void == NULL) {
cob_call_error ();
}
return_code = unifunc.func(value1, value2, value3);
cob_stop_run ( return_code );
}
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO2.
DATA DIVISION.
WORKING-STORAGE SECTION.
LINKAGE SECTION.
01 VALUE1 PIC 9(8) COMP-5.
01 VALUE2 PIC 9(2).
01 VALUE3 PIC X(10).
PROCEDURE DIVISION
USING BY VALUE VALUE1
BY REFERENCE VALUE2
BY REFERENCE VALUE3.
MAIN-RTN.
DISPLAY "VALUE1:" VALUE1.
DISPLAY "VALUE2:" VALUE2.
DISPLAY "VALUE3:" VALUE3.
MAIN-EXT.
GOBACK.
[user@localhost test]$ ./cblcall2 HELLO2
VALUE1:00000011
VALUE2:11
VALUE3:HELLO!
ちょっと複雑にはなっていますが、無事に引数を渡すことができました。
まとめ
COBOLからCを呼び出す場合より、opensource COBOLの内部仕様を確認する必要があり、多少手間はかかりますが、コード自体は単純な形式でCOBOLを呼び出すことができました。
これにより、COBOLで作成していた検索サブルーチンや、バッチ処理などを、Cで作成したプログラムから利用するといったことが可能になり、資産の有効活用ができるかもしれません。