With every new release I go through all the "What's new for this release" section of IBM's KnowledgeCenter. For IBM i 7.4 and the CL programming language there is only one addition this release: %PARMS built in function. It appears to be identical to the %PARMS built in function in RPG. It is the way to determine how many parameters have been passed to a program or procedure, and from that stop the program from erroring if too few parameters are passed.
In the past I wrote about coping with to few parameters being passed to a CL program, but the new BiF is a lot neater and easier for someone else to understand.
As I said above %PARMS is available in RPG:
01 **free
02 ctl-opt main(Main) option(*nodebugio:*srcstmt) ;
03 dcl-pr Main extpgm('TESTRPG') ;
04 *n char(1) ;
05 *n char(1) ;
06 *n char(1) ;
07 end-pr ;
08 dcl-s P1 char(1) inz('*') ;
09 dcl-s P2 like(P1) inz('*') ;
10 dcl-s P3 like(P1) inz('*') ;
11 dcl-proc Main ;
12 dcl-pi *n ;
13 inP1 char(1) ;
14 inP2 char(1) ;
15 inP3 char(1) ;
16 end-pi ;
17 if (%parms = 3) ;
18 P3 = inP3 ;
19 endif ;
20 if (%parms >= 2) ;
21 P2 = inP2 ;
22 endif ;
23 if (%parms >= 1) ;
24 P1 = inP1 ;
25 endif ;
26 dsply ('<' + P1 + '> <' + P2 + '> <' + P3 + '>') ;
27 end-proc ;
|
Lines 3 – 7: As I am using a Main procedure, see line 2, I define the parameters passed to this program using the declare procedure statement. Three parameters are passed to this program, each one is a single character.
Lines 8 – 10: These three variables will receive the values of the passed parameters. Notice that they are all initialized with the value '*'.
Lines 12 - 16: Procedure interface defining and giving names to the variables passed to this program.
Lines 17 – 19: If three parameters are passed to this program then the value in the input parameter inP3 is moved to the program variable P3.
Lines 20 – 22: If two or more parameters are passed P2 is updated with the value from inP2.
Lines 23 – 25: If one or more parameters are passed P1 is updated with the value from inP1.
Line 26: I am using the DSPLY operation code so that I can see what the parameters P1, P2, and P3 contain.
Let me now call this program with various number of parameters.
01 CALL TESTRPG
DSPLY <*> <*> <*>
02 CALL TESTRPG '1'
DSPLY <1> <*> <*>
03 CALL TESTRPG ('1' '2')
DSPLY <1> <2> <*>
04 CALL TESTRPG ('1' '2' '3')
DSPLY <1> <2> <3>
|
Line 1: I have passed no parameters, therefore, P1, P2, and P3 contain the value I initialized them when I defined them.
Line 2: As only one parameter is passed, only P1 is changed.
Line 3: Two parameters are passed, and P1 and P2 are changed.
Line 4: Three parameters are passed, and all the program defined variables have been changed.
Let me now do the equivalent in CL:
01 PGM PARM(&IN_P1 &IN_P2 &IN_P3)
02 DCL VAR(&IN_P1) TYPE(*CHAR) LEN(1)
03 DCL VAR(&IN_P2) TYPE(*CHAR) LEN(1)
04 DCL VAR(&IN_P3) TYPE(*CHAR) LEN(1)
05 DCL VAR(&P1) TYPE(*CHAR) LEN(1) VALUE('*')
06 DCL VAR(&P2) TYPE(*CHAR) LEN(1) VALUE('*')
07 DCL VAR(&P3) TYPE(*CHAR) LEN(1) VALUE('*')
08 IF COND(%PARMS() = 3) THEN(CHGVAR VAR(&P3) VALUE(&IN_P3))
09 IF COND(%PARMS() >= 2) THEN(CHGVAR VAR(&P2) VALUE(&IN_P2))
10 IF COND(%PARMS() >= 1) THEN(CHGVAR VAR(&P1) VALUE(&IN_P1))
11 SNDPGMMSG MSG('<' || &P1 || '> <' || &P2 || '> <' || +
&P3 || '>')
12 ENDPGM
|
Line 1: The parameters that can be received by this CL program.
Lines 2 – 4: Definitions of the passed parameters.
Lines 5 – 7: Definitions of the program's variables, all initialized with '*'.
Line 8: If three parameters were passed to this program move the value in &IN_P3 to &P3.
Line 9: If two or more parameters were passed to this program move the value in &IN_P2 to &P2.
Line 10: And finally is one or more parameters were passed move the vale in &IN_P1 to &P1.
Line 11: As I cannot use RPG's display operation code, I am using the Send Program Message command, SNDPGMMSG to send a message to the program's message queue instead.
What happens when I call this CL program?
01 CALL TESTCL
<*> <*> <*>
02 CALL TESTCL '1'
<1> <*> <*>
03 CALL TESTCL ('1' '2')
<1> <2> <*>
04 CALL TESTCL ('1' '2' '3')
<1> <2> <3>
|
The results are identical to those for the RPG program. If I pass less than three parameters the "extra" program variables still contain '*'.
One thing I did find bizarre in the documentation was it said that if I compiled this to earlier releases, IBM i 7.3 and 7.2, I could copy the object to a partition with one of those releases and the program would still work!
Being a person who likes to test these kind of things I..
Created the program with the target release of IBM i 7.2:
CRTBNDCL PGM(MYLIB/TESTCL) SRCFILE(DEVSRC) TGTRLS(V7R2M0) |
Saved for target release 7.2:
SAVOBJ OBJ(TESTCL) LIB(MYLIB) DEV(*SAVF) SAVF(MYSAVF) TGTRLS(V7R2M0) |
Restored the program onto the 7.2 partition.
The documentation is correct, this program does work in a partition running on 7.2!
CALL TESTCL <*> <*> <*> |
You can learn more about this from the IBM website:
This article was written for IBM i 7.4 and 7.3 TR6.
Plus, you can check if more parms were passed than expected. You can trap that and handle accordingly (like "Hey, you passed 4 parms, we only need 3!". And it works on 7.3 w/o issues ( I don't know our level of 7.3 ).
ReplyDeleteHi Simon.
ReplyDeleteAnother great post :-)
I have a little comment to the rpg example :
I prefer to use %ParmNum instead of using the parms number as a number.
So i would change : " if (%parms = 3) ; " to " if(%Parms() >= %ParmNum(inP3));" that way it wouldnt fail even if a new parameter is put in before inp3 :-)
Best regards
Jan
Hi Jan
ReplyDeleteOn top of your statement I also prefer the parameters to be defined with options(*nopass) or probably options(*nopass:*omit) if more parameters could be omitted and or not passed in any sequence
Kr
Mathy Paesen
Hi :-)
ReplyDeleteTotally agree :-)
And then change the code like this :
if (%Parms() >= %ParmNum(inP3) and %Addr(inP3) <> *Null);
Best regards
When I saw the article and skimmed through the text, I wanted to add a comment about an alternative I had came across before. It was the "MCH3601 method". Having read your text thoroughly, I realized that I got this knowledge from another rpgpgm article by you. :-) So thanks again for sharing your wisdom.
ReplyDelete