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