LoginSignup
3
0

More than 3 years have passed since last update.

Cプログラムからopensource COBOLの呼び出しをした

Posted at

概要

以前の記事では、COBOLからCのプログラムを呼び出したので、今回は逆にCからCOBOLのプログラムを呼び出してみようと思います。

opensource COBOLの呼び出し

そもそもCOBOLの実行方法

opensource COBOLのプログラムはC言語に翻訳された上で、Cとしてコンパイルされています。
この際、SOモジュールとしたプログラムを実行する機能としてcobcrunが提供されています。
今回はこのcobcrunを参考にして、CからCOBOLを呼び出すプログラムを作成しました。

cobcrunの処理

cobcrunの処理としてmainの中は以下のようになっています。

cobcrun.c
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を呼び出すプログラムを作成します。
といっても、上記必要な関数を呼び出すだけになります。

cblcall.c
#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を呼び出してみます。

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 *の値を連携してみようと思います。
以下、サンプルになります。

cblcall2.c
#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 );
}
HELLO2
       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で作成したプログラムから利用するといったことが可能になり、資産の有効活用ができるかもしれません。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0