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 Typed Call Prototype Usage
program-id. p is external. linkage section. 01 picx pic x(10) typedef. entry "c" using by reference picx. entry "d" using by reference any. end program. program-id. "b". 01 p1 pointer picx. 01 pic9 pic 9(9) comp-5 typedef. 01 p2 pointer pic9. 01 p3 pointer. 01 x1 pic x(100) value "PASS". call "c" using by value p1 *> call "c" using by value p2 *> call "c" using by value p3 call "d" using by value p1 call "d" using by value p2 call "d" using by value p3 goback.
Example 1
call "c" using by value p1
The preceding CALL statement would be valid as the pointer is of the correct type.
Example 2
call "c" using by value p2
The preceding CALL statement would generate an error since the pointer type is numeric, but the parameter is alphanumeric.
Example 3
call "c" using by value p3
The preceding CALL statement would generate an error since the pointer is untyped.
Example 4
call "d" using by value p1
The preceding CALL statement would be valid as the parameter can be any specified type.
Example 5
call "d" using by value p2
The preceding CALL statement would be valid as the parameter can be any specified type.
Example 6
call "d" using by value p3
The preceding CALL statement would be valid as the parameter can be any specified type.
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 % -------------------------------------------------------------