Length of CL Variables

Article ID: 58921

Q: Is there an easy way to calculate the length of a string in CL, so I don't have to hard-code it? Can I calculate the length both with and without the trailing blanks?

A: There was actually a really good discussion about this subject in the System iNetwork forums this week. In this article, I include the answer that I thought was the best one, and I explain how the code works. I also provide a link to the original thread in the forums so you can read it yourself.

I felt the best answer in the thread came from the user named DéesseT. Some very short and simple CL programs can be used to create commands on your system for calculating the length of strings. Once the commands are compiled, you can use them over and over again, as if they were built in to the language.

The first one is called RTVDTALEN and calculates the length of the data—which is to say, the length of a variable after trailing blanks have been stripped:

Member RTVDTALEN, file QCMDSRC:

             CMD        'Retrieve length of data'

             PARM       Var                          +
                        *X                           +
                        MIN(1)                       +
                        EXPR(*YES)                   +
                        VARY(*YES *INT2)             +
                        PROMPT('CL variable name')

             PARM       DtaLen                       +
                        *INT2                        +
                        RTNVAL(*YES)                 +
                        MIN(1)                       +
                        PROMPT('Variable for DTALEN     (INT2)')

Member RTVDTALEN, file QCLSRC:

             PGM        (&Var &DtaLen)

             DCL        &Var        *INT     2    /* CL variable name   */
             DCL        &DtaLen     *INT     2    /* Data length        */

             CHGVAR     &DtaLen     &Var

             ENDPGM

This code works by taking advantage of the VARY(*YES) option specified for the first parameter of the command. Here's what it says about this parameter in the help text for the PARM command:

                        Varying length (VARY) - Help                        
                                                                            
  Specifies whether the value that is passed to the command processing      
  program is preceded by a length value that indicates the number of        
  characters entered for the command parameter.                             
                                                                            
      Note:  The length value is the actual number of characters entered    
      for the command parameter, with trailing blanks removed.  The length  
      value passed may be different than the defined parameter length or    
      the declared variable length.  The length of the field containing     
      the character string data is determined by the defined length for     
      the parameter or the declared LEN for CL program variables.  The      
      length value defines how many characters in the character string      
      data field were actually entered for the command parameter.           

So the first two bytes of the parameter passed to the CPP will be automatically populated with the length of the string with the trailing blanks removed! That's why the CPP for the command is so simple—it needs to read only the first two bytes of the first parameter (to get the length) and copy it to the returned length parameter. Clever!

Once you've compiled this command and placed it in your library list, you can find out the length of any character string in CL as follows:

  PGM
        DCL VAR(&TEST) TYPE(*CHAR) LEN(100)
        DCL VAR(&LEN)  TYPE(*INT) LEN(2)

        CHGVAR VAR(&TEST) VALUE('this is 9')
        RTVDTALEN VAR(&TEST) DTALEN(&LEN)
  ENDPGM

To calculate the maximum length of a string, DéesseT provided another command that's very similar:

Member RTVVARSIZ, file QCMDSRC:

             CMD        'Retrieve size of CL variable'

             PARM       Var                        +
                        *X                         +
                        1                          +
                        RTNVAL(*YES)               +
                        MIN(1)                     +
                        VARY(*YES *INT2)           +
                        PROMPT('CL variable name')

             PARM       Size                       +
                        *INT2                      +
                        RTNVAL(*YES)               +
                        MIN(1)                     +
                        PROMPT('Variable for SIZE       (INT2)')

Member RTVVARSIZ, file QCLSRC:

             PGM        (&Var &Size)

             DCL        &Var        *INT     2    /* CL variable name     */
             DCL        &Size       *INT     2    /* Size of CL variable  */

             CHGVAR     &Size       &Var

             ENDPGM

The primary difference between this example and the previous one is that the first parameter is defined with RTNVAL(*YES). That makes a big difference, because when you specify RTNVAL(*YES), the CL program expects you to output data to that variable. It therefore sets the length equal to the maximum size of data that you can output (so you know how much space you have to work with).

Therefore, by using RTNVAL(*YES), you can calculate the maximum length of the character string instead of the trimmed length. Aside from that, it works the same as the previous example. You use it the same way, too:

  PGM
        DCL VAR(&TEST) TYPE(*CHAR) LEN(100)
        DCL VAR(&LEN)  TYPE(*INT) LEN(2)

        CHGVAR VAR(&TEST) VALUE('this is 9')
        RTVVARSIZ VAR(&TEST) SIZE(&LEN)
  ENDPGM

I thought this was a pretty clever way to do it. You can read the full thread in the System iNetwork forums.

(Added March 12, 2010)

To compile the utilities in this article, please run the following commands:

    CRTCLPGM PGM(RTVDTALEN) SRCFILE(QCLSRC)

    CRTCMD   CMD(RTVDTALEN) PGM(RTVDTALEN) SRCFILE(QCMDSRC) 
             ALLOW(*IPGM *BPGM *IMOD *BMOD)

    CRTCLPGM PGM(RTVVARSIZ) SRCFILE(QCLSRC)

    CRTCMD   CMD(RTVVARSIZ) PGM(RTVVARSIZ) SRCFILE(QCMDSRC) 
             ALLOW(*IPGM *BPGM *IMOD *BMOD)
Doesn't work for me - no error messages, but returns the length of the VAR, ie no truncation of blanks. VAR = 1000, content 'ABCDEF' retuns a length of 1000.

Folks, please make sure you are specifying the ALLOW parameter properly when you compile the commands. For example:

CRTCMD CMD(RTVDTALEN) PGM(RTVDTALEN) ALLOW(*BPGM *IPGM *BMOD *IMOD)

Hmm... I should add the compile instructions to the article.

ppriolo you are not alone. I get the same error as ppriolo is getting above.
the CMD RTVDTALEN won't compile. I get the error: CPD0281 111 30 RTNVAL(*YES) valid only in CL programs or REXX procedures. Any ideas what I'm doing wrong?

ProVIP Sponsors

ProVIP Sponsors