Wednesday, August 28, 2019

Parms built in function added to CL

using bif parms to find number of parameters passed

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.

5 comments:

  1. 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 ).

    ReplyDelete
  2. Hi Simon.
    Another 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


    ReplyDelete
  3. Hi Jan

    On 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

    ReplyDelete
  4. Hi :-)
    Totally agree :-)

    And then change the code like this :
    if (%Parms() >= %ParmNum(inP3) and %Addr(inP3) <> *Null);
    Best regards

    ReplyDelete
  5. 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

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.