The following program demonstrates the use of call prototypes. Assume that you have defined the following call prototype:
identification division.
program-id. callsub is external.
environment division.
configuration section.
special-names.
call-convention 3 is some-language.
data division.
linkage section.
01 x1 pic 9(4) comp-5.
01 x2 pic xx.
01 x3 pic 9(8).
01 x7 pic x.
procedure division some-language using by value x1
by reference x2
by reference x3.
entry "callsub2" using x2 delimited
any
x1.
entry "printf" using x7 delimited
any repeated.
end program callsub.
If you had the following "real" source coded in the same source file as the previous call prototype:
identification division.
program-id. prog-1.
data division.
working-storage section.
01 x1 pic 9(4) comp-5.
01 x2.
05 pic 9(4) comp-5.
05 pic x(20).
01 x3 pic 9(8).
01 x4 pic 9(9) comp-5.
01 x5 pic x.
01 x6 pic x(20).
procedure division.
mainline.
call "callsub" using x1 x2 x3
the preceding CALL statement would be equivalent to using:
by value x1
by reference x2
by reference x3
The following examples show the results of different call statements:
Example 1
call "callsub" using x1 x2
The preceding CALL statement would generate an error since the number of parameters is wrong.
Example 2
call other-language "callsub" using x1 x2 x3
The preceding CALL statement would generate an error since the call-convention is wrong.
Example 3
call "callsub" using by reference x1 x2 x3
The preceding CALL statement would generate an error since x1 should be passed by value.
Example 4
call "callsub" using 99 x2 x3
The preceding CALL statement would be equivalent to a call using:
by value 99 size 2
by reference x2
by reference x3
Example 5
call "callsub" using x4 x2 x3
The preceding CALL statement would generate an error since x4 has the wrong length.
Example 6
call "callsub" using x1 x5 x3
The preceding CALL statement would generate an error since x5 is too small.
Example 7
call "printf" using "A long %1\n" x4
In the preceding CALL statement x4 is a parameter covered by ANY REPEATED.
Example 8
call "callsub2" using "Hello" x2 x1
The preceding CALL statement is equivalent to:
move "Hello" & x"00" to temp
call "callsub2" using temp x2 x1
Example 9
call "callsub2" using x6 x2 x1
The preceding CALL statement is equivalent to:
move x6 to temp
move x"00" to temp (21:1)
call "callsub2" using temp x2 x1
Example 10
call "callsub2" using x6 x2 x1 x4
The preceding CALL statement would generate an error as there are too many parameters being passed.
Example of Call Prototype Usage
If a COBOL application programmer wants to call a C function from within his COBOL application the following need to be done:
The use of COBOL typedefs and COBOL call prototypes may be used to automate the above process. This includes the automatic conversion of text strings into null terminated C strings. The following is an example of how all this may be done.
Suppose I have a C function that I want to call. Let us call it my_C_function. The following is a segment of C code that shows this function:
sample.c
-------------------------------------------------------------
/*** start of source module sample.c ***/
/*------------------------*/
/* Include Header Files */
/*------------------------*/
#include <stdio.h>
#include "sample.h"
/*-------------------*/
/* Sample Function */
/*-------------------*/
int my_C_function (parm_1, parm_2, parm_3)
num_type parm_1;
unsigned char *parm_2;
complex_type *parm_3;
{
int rtn_code = 0;
printf(" my-C_function: invoked\n");
printf(" my-C_function: parm_1 = %d\n", parm_1);
if (parm_2 == NULL) {
printf(" my_C_function: parm_2 = IS NULL\n", parm_2);
rtn_code = -1;
} else {
printf(" my_C_function: parm_2 = %s\n", parm_2);
}
if (parm_3 == NULL ) {
printf(" my_C_function: parm_3 = IS NULL\n", parm_3);
rtn_code = -1;
} else {
printf(" my_C_function: parm_3\n");
printf(" (num1) = %d\n", parm_3->num1);
printf(" (num2) = %d\n", parm_3->num2);
}
printf(" my_C_function: completed\n");
return(rtn_code);
}
/*** end of source module sample.c ***/
-------------------------------------------------------------
In this example we have three parameters for the C function:
There is a header file that contains the C typedef definitions and also the C function prototype. It is as follows:
sample.h
-------------------------------------------------------------
/*** start of source module sample.h ***/
#ifndef SAMPLE
#define SAMPLE
/*------------*/
/* Typedefs */
/*------------*/
typedef int num_type;
typedef struct {
int num1;
long num2;
} complex_type;
/*----------------------*/
/* Function Prototype */
/*----------------------*/
extern int my_C_function (
num_type parm_1,
unsigned char *parm_2,
complex_type *parm_3
);
#endif /* SAMPLE */
/*** end of source module sample.h ***/
-------------------------------------------------------------
The first step is to convert the C typedefs and function prototypes into COBOL typedefs and COBOL call prototypes.
sample.cpy
-------------------------------------------------------------
program-id. "c_typedefs" is external.
77 char pic s9(2) comp-5 is typedef.
77 uns-char pic 9(2) comp-5 is typedef.
77 short pic s9(4) comp-5 is typedef.
77 uns-short pic 9(4) comp-5 is typedef.
77 int pic s9(9) comp-5 is typedef.
77 uns-int pic 9(9) comp-5 is typedef.
77 long pic s9(9) comp-5 is typedef.
77 uns-long pic 9(9) comp-5 is typedef.
77 d-l-float comp-2 is typedef.
77 d-float comp-2 is typedef.
77 float comp-1 is typedef.
77 proc-pointer procedure-pointer is typedef.
77 data-pointer pointer is typedef.
77 void pic 9(2) comp-5 is typedef.
01 num-type is typedef usage int.
01 complex-type is typedef.
02 num1 usage int.
02 num2 usage long.
entry "my_C_function" using
by value int
by reference uns-char
by reference complex-type
returning int
.
end program "c-typedefs".
-------------------------------------------------------------
In the above we have:
The following changes should be made to this file with a text editor.
The result of the above editing is the following:
sample.cpy
-------------------------------------------------------------
program-id. "c_typedefs" is external.
77 uns-char pic x is typedef.
77 int pic s9(9) comp-5 is typedef.
77 long pic s9(9) comp-5 is typedef.
77 data-pointer pointer is typedef.
01 num-type is typedef usage int.
01 complex-type is typedef.
02 num1 usage int.
02 num2 usage long.
entry "my_C_function" using
by value int
by reference uns-char delimited
by reference complex-type
returning int
.
end program "c_typedefs".
-------------------------------------------------------------
The following is an example of the COBOL application that makes a call to the my_C_function function.
-------------------------------------------------------------
copy 'sample.cpy'.
identification division.
program-id. prog.
working-storage section.
01 ws-parm-1 usage num-type.
01 ws-parm-2 pic x(50)
value "This is a PIC X string from COBOL".
01 ws-parm-3 usage complex-type.
01 ws-return-code usage int.
procedure division.
main-code section.
display "prog: started"
move 123 to ws-parm-1
move 1 to num1 IN ws-parm-3
move 2 to num2 IN ws-parm -3
display " "
display "prog: call 'my_C_function' with ALL parameters"
call "my_C_function" using ws-parm-1
ws-parm-2
ws-parm-3
returning ws-return-code
end-call
display "prog: 'my_C_function' return code = "
ws-return-code
display " "
display "prog: call 'my_C_function' with NULL parameters"
call "my_C_function" using 0
OMITTED
OMITTED
returning ws-return-code
end-call
display "prog: 'my_C_function' return code = "
ws-return-code
display " "
display "prog: completed"
exit program
stop run.
-------------------------------------------------------------
In the above example the following has been coded:
Typedefs and prototypes are defined as complete external programs. They are placed before real source programs in a similar way to multi-program source files.
This is required because it is not possible to just go BY VALUE 0 which would be flagged as invalid because BY REFERENCE is mandatory for that parameter. OMITTED will pass a NULL instead of a pointer to the parameter being passed to the C function.
The following is the output that results when the specific example above is run:
-------------------------------------------------------------
%prog
prog: started
prog: call 'my_C_function' with ALL parameters
my_C_function: invoked
my_C_function: parm_1 = 123
my_C_function: parm_2 = This is a COBOL PIC X string
my_C_function: parm_3
(num1) = 1
(num2) = 2
my_C_function: completed
prog: 'my_C_function' return code = +0000000000
prog: call 'my_C_function' with NULL parameters
my_C_function: invoked
my_C_function: parm_1 = 0
my_C_function: parm_2 = IS NULL
my_C_function: parm_3 = IS NULL
my_C_function: completed
prog: 'my_C_function' return code = -0000000001
prog: completed
%
-------------------------------------------------------------