Data structures have always been a useful part of RPG, especially when returning information from a procedure. In CL I can create "Defined Variables", which are the equivalent of a RPG data structure. This becomes useful when I have a CL procedure that is called by RPG procedure, or vice versa. I will explain that in detail in a future post.
I am sure we have all encountered a situation where a data structure is passed to a CL program, and I have seen many programs were the subfields are broken out into individual variables using the Substring command, %SST. While this is easy if the data structure contains only character subfields, it can get messy if there are numeric subfields as I have to determine the start and end positions while considering the packing of the number.
By using Defined Variables, I can define the subfields at the top of the CL source using the Declare Variable command, DCL. Once the "data structure" and subfields are defined I can reference the data straight away just by using the variable name.
In this example I have a RPG program that has a data structure defined thus, I will give example in fixed format at the bottom of this post:
01 dcl-ds TestDs len(20) ; 02 Subf1 char(2) pos(1) ; 03 Subf2 packed(5:2) pos(3) ; 04 Subf3 char(10) ; 05 end-ds ;
The equivalent in CL code, using Defined Variables, would be:
01 DCL VAR(&DATA_STRCT) TYPE(*CHAR) LEN(20) 02 DCL VAR(&SUBFLD1) TYPE(*CHAR) STG(*DEFINED) + LEN(2) DEFVAR(&DATA_STRCT 1) 03 DCL VAR(&SUBFLD2) TYPE(*DEC) STG(*DEFINED) + LEN(5 2) DEFVAR(&DATA_STRCT 3) 04 DCL VAR(&SUBFLD3) TYPE(*CHAR) STG(*DEFINED) + LEN(10) DEFVAR(&DATA_STRCT 6)
Line 1 is the variable that would be passed to this CL program, it is the equivalent of the data structure in the RPG.
The other three lines are the subfield equivalents. Notice that these lines have two additional parameters in the DCL command that I would not used for standalone fields:
- STG(*DEFINED) - Storage: the value for this variable is specified in the variable defined in the DEFVAR parameter.
- DEFVAR(&DATA_STRCT ?) - Defined on variable: specifies the variable that contains this subfield, and its starting position.
Below is the code for the free format RPG program that calls the CL:
01 dcl-pr TESTCL extpgm 02 *n char(20) ; 03 end-pr ; 04 dcl-ds TestDs len(20) ; 05 Subf1 char(2) pos(1) ; 06 Subf2 packed(5:2) pos(3) ; 07 Subf3 char(10) ; 08 end-ds ; 09 Subf1 = 'AB' ; 10 Subf2 = 123.45 ; 11 Subf3 = 'Test data' ; 12 TESTCL(TestDs) ; 13 *inlr = *on ;
If you want to see this with fixed format definitions see the example code here.
Lines 1 – 3 is the prototype definition for the CL program. If you are unfamiliar with this see Use a Procedure to call a program.
The data structure is defined in lines 4 - 8. If you are not familiar with defining data structures in free format see Data Areas in the all free RPG.
I am moving values to the subfields on lines 9 – 11.
On line 12 I am calling the CL program.
The CL code is very simple:
01 PGM PARM(&DATA_STRCT) 02 DCL VAR(&DATA_STRCT) TYPE(*CHAR) LEN(20) 03 DCL VAR(&SUBFLD1) TYPE(*CHAR) STG(*DEFINED) + LEN(2) DEFVAR(&DATA_STRCT 1) 04 DCL VAR(&SUBFLD2) TYPE(*DEC) STG(*DEFINED) + LEN(5 2) DEFVAR(&DATA_STRCT 3) 05 DCL VAR(&SUBFLD3) TYPE(*CHAR) STG(*DEFINED) + LEN(10) DEFVAR(&DATA_STRCT 6) 06 ENDPGM
On line 1 the incoming parameter is given, and defined on line 2. Its subfields are defined on lines 3 – 4.
If I use debug and look at the values of the variables in the CL program I see that these subfields contain the same values as the RPG's data structure subfields:
&DATA_STRCT = 'AB ¬Test data ' &SUBFLD1 = 'AB' &SUBFLD2 = 123.45 &SUBFLD3 = 'Test data '
You can learn more about CL's Declare Variable command, DCL on the IBM website here.
This article was written for IBM i 7.2, and should work for earlier releases too.
Fixed format definitions RPG
01 D TestDs DS 20 02 D Subf1 2 03 D Subf2 5P 2 04 D Subf3 10 /free 05 Subf1 = 'AB' ; 06 Subf2 = 123.45 ; 07 Subf3 = 'Test data' ; /end-free 08 C call 'TESTCL' 09 C parm TestDs /free 10 *inlr = *on ;