Pages

Wednesday, November 20, 2024

Using expression in CL call parameters

Starting in IBM i 7.4 it is possible to use CL Built in Functions, BiF, in the parameters of CL's Call command. This becomes even easier when I use the additional parameters in the Parameter parameters of the CALL command.

Those of you who have seen example of my RPG code have seen examples where I have used BiFs in its Call operation code parameters. When I learned that there was now similar functionality in CL I became very curious what could I do with it.

I chosen a number of scenarios to write examples for, as these are things I have done many times with RPG's Call operation code.

  1. Remove leading blanks from a string when passed to another program.
  2. Convert character to numeric.
  3. Pass the length of a variable passed to the same program.
  4. Substring part of a larger string and passed that to the called program.

I am sure there are other scenarios that have sprung to your mind. These were just the ones that came to mine.

In all of the examples the calling program calls a CL program called TESTCL, which just produces a program dump. I can then look in the program dump's spool file, QPPGMDMP, to see how the passed value was interpreted by the called program.

My first scenario was to remove the leading blank characters from a string before I pass it to the called program.

01  DCL        VAR(&CHAR) TYPE(*CHAR) LEN(30)

02  CHGVAR     VAR(&CHAR) VALUE('          Text starts here')

03  CALL       PGM(TESTCL) PARM((%TRIML(&CHAR)))

The Calling program just has these three lines:

Line 1: Define the variable that will contain the string.

Line 2: Populate the variable with a string, with leading blank characters.

Line 3: Call TESTCL, using just one parameter. Within the definition of that parameter I have used the Trim leftmost characters BiF, %TRIML, to remove the leading blank characters.

The called program's source code looks like:

01  PGM        PARM(&PARM_IN)

02  DCL        VAR(&PARM_IN) TYPE(*CHAR) LEN(30)

03  DMPCLPGM

Line 1: This program accepts one parameter from any program that calls it.

Line 2: Definition for this one parameter. This happens to be the same as the variable that is used as the parameter when this program is called.

Line 3: Generate the program dump.

When I look near the bottom of the spool file I can see the value in the &PARM_IN variable is what I expected.

Variable       Type      Length    Value                      
                                    *....+....1....+....2....+ 
&PARM_IN       *CHAR           30  'Text starts here         '
                           +26     '     '

In my next example I want to convert a character representation of a number to a decimal value, and then pass it to the called program.

01  DCL        VAR(&CHAR) TYPE(*CHAR) LEN(6)

02  CHGVAR     VAR(&CHAR) VALUE('123.45')

03  CALL       PGM(TESTCL) PARM(%DEC(&CHAR 5 2))

Line 1: I define the character variable to be six character long.

Line 2: I move a value to it.

Line 3: When I call TESTCL I use the Convert to decimal BiF, %DEC, to convert the value in &CHAR to a decimal value. The character variable has to be six characters to accommodate the decimal place. The decimal value assumes the decimal, therefore, it is only five characters.

01  PGM        PARM(&PARM_IN)

02  DCL        VAR(&PARM_IN) TYPE(*DEC) LEN(5 2)

03  DMPCLPGM

This version of the called program, TESTCL, is as simple as the previous with just three lines of code.

Line 1: One parameter is passed to this program.

Line 2: The variable that is used for the parameter is defined as decimal date type, five long with two decimal places.

Line 3: I dump this program.

Looking in the program dump spool file the result contained in the variable was not as I expected.

Variable       Type      Length    Value                      
                                    *....+....1....+....2....+ 
&PARM_IN       *DEC           5 2   0

This must be due to the assumptions that the CL compiler makes with the parameter in the calling program. I am assuming as the variable is character, even though I have used the %DEC BiF, it is passed as character.

Fortunately with the enhancement to the Call command I can define the parameter as decimal within the command. This means the line 3 in the calling program becomes:

03  CALL       PGM(TESTCL) PARM((%DEC(&CHAR 5 2) (*DEC 5 2)))

Line 3: The (*DEC 5 2) means that the parameter is passed as decimal, five long, with two decimal places.

Making this change means that the value in the parameter variable is shown in the program dump as:

Variable       Type      Length    Value                      
                                    *....+....1....+....2....+ 
&PARM_IN       *DEC           5 2   123.45

Next example I want to pass two variables to the called program: a variable and its length:

01  DCL        VAR(&CHAR) TYPE(*CHAR) LEN(15)

02  CHGVAR     VAR(&CHAR) VALUE('Something')

03  CALL       PGM(TESTCL) +
04               PARM((&CHAR) +
05                    (%LEN(&CHAR) (*DEC 3 0)))

Line 1: Definition for the variable.

Line 2: Putting a value in it.

Line 3 5: Calling TESTCL with two parameters. The first is the variable, the second uses the Length BiF, %LEN, to return the length of the variable, not the string contained within.

01  PGM        PARM(&CHAR &PARM_IN)

02  DCL        VAR(&CHAR) TYPE(*CHAR) LEN(15)
03  DCL        VAR(&PARM_IN) TYPE(*DEC) LEN(3 0) 

04  DMPCLPGM   

Line 1: Two parameters are passed to this program, see lines 3 - 5 of the calling program.

Lines 2 and 3: Definitions of the variables that will hold these passed parameters' values.

Line 3: Dump the program.

The dump's spool file contains the variables, and shows they contain the values I expected.

Variable       Type      Length    Value                      
                                    *....+....1....+....2....+ 
&CHAR          *CHAR           15   'Something      '
&PARM_IN       *DEC           3 0    15

I wanted to see if I could get the length of the string, not the variable, as the second parameter.

03  CALL       PGM(TESTCL) +
04               PARM((&CHAR) +
05                    (%LEN(%TRIM(&CHAR)) (*DEC 3 0)))

I replaced lines 3 5 in the calling with the above. The change is in line 5, where I nest the %TRIM BiF within the %LEN. When I compiled this changed program it errored with the following:

   500-              CALL       PGM(TESTCL) +
   600                            PARM((&CHAR) +
   700                                 (%LEN(%TRIM(&CHAR)) (*DEC 3 0)))
 * CPD0181 30  Argument for built-in function %LEN not valid.

It is a shame I cannot nest BiFs within one another in a passed parameter.

In the last scenario I want to use the Substring BiF. Rather than use the %SUBSTRING, I will be using %SST which is a synonym of the other.

01  DCL        VAR(&CHAR) TYPE(*CHAR) LEN(26)

02  CHGVAR     VAR(&CHAR) VALUE('ABCDEFGHIJKLMNOPQRSTUVWXYZ')

03  CALL       PGM(TESTCL) PARM((%SST(&CHAR 5 5) (*CHAR 5)))

Line 1: The variable is character and 26 long.

Line 2: Load it with all the letters of the alphabet.

Line 3: I am substring five characters, starting in the fifth position of the string.

The called program is very similar to the others I have shown.

01  PGM        PARM(&PARM_IN)

02  DCL        VAR(&PARM_IN) TYPE(*CHAR) LEN(5)

03  DMPCLPGM   

Line 2: The passed parameter is a five long character variable.

The dump's spool file shows what I would expect.

Variable       Type      Length    Value                      
                                    *....+....1....+....2....+ 
&PARM_IN       *CHAR            5   'EFGHI'

I consider this a good improvement to the CL language. My only wish is that I could next BiFs within one another.

 

This article was written for IBM i 7.5, and should work for some earlier releases too.

No comments:

Post a Comment

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.