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 ; |
Nice Article -- Thanks
ReplyDeleteSimon, Do you have plans to write an article on subroutines in CL?
ReplyDeleteYes, there already is a post about Subroutines in CL.
DeleteCould you please share us subroutines in CL articles
DeleteIf you had used the search function you would have found I have already written about CL subroutines.
DeleteLearned something new
ReplyDeletewhat compiler version is this possible in. Still on 5.3 at work...
ReplyDeleteI can find reference to this for releases V5R4 - 7.2 in IBM's documentation web sites.
DeleteAnonymous,
DeleteMissed it by .1 :-) Support for *BASED variables arrived in V5R4.
- DrFranken
Great as usual - J
ReplyDeleteNice article very helpful !!
ReplyDeleteBut can we handle multi occurance or array Data structure also in CL ?
No, single occurrence only.
DeleteIt's very useful.
ReplyDeleteI'll apply this technic to my cl program.
Thanks for providing good information.
Hi Simon,
ReplyDeleteVery helpful article!!
Do we have any method to declare the CL variable with LIKE key word. Can we declare External DS structure in CL. Thanks,
Srinidhi
Declaring CL variables with the LIKE keyword is not possible in the current releases of IBM i.
DeleteDeclaring external DS in CL is also not possible.
Both would be nice additions to the CL language. I think you should submit these as a RFE at IBM's website here.
Really nice. Thank you Simon.
ReplyDeleteRegards
Carlos
Very usefull and cool. I use a lot of APIs in my programs this will simplify my work in a big way. Thanks.
ReplyDeleteToo good information, I never tried this option earlier.
ReplyDelete