Let's look at the rest of the new built-ins for CL.
Last month, in "More Tools for the CL Developer," we looked at the new 7.2 built-ins %char, %dec, %int, and %uint. This month, we'll go over the additional built-ins of %upper, %lower, %size, and %len. But before doing that, I need to make a correction to last month's column.
Though the column was published after IBM announced release 7.2 of the i operating system, it was written well before the announcement. One of the perils in writing about new functions, prior to their general availability, is that last-minute changes can impact what's actually delivered. Specifically, last month's column indicated that prior release support was being provided for the built-ins %char, %dec, &int, and %uint. Unfortunately, this is not the case; use of these built-ins does require that the system be at 7.2. I am, however, at least in good company in regard to this error. If you look at the IBM i 7.2 Knowledge Center Control language topic What's new for IBM i 7.2, you'll find it also indicates that prior release support is provided. You'll need to look fast, though, as the next update to the Knowledge Center will be correcting this. With that out of the way, let's look at the new built-ins.
(Editor's note: Thanks to the magic of electronic—rather than paper—publishing, the article Bruce refers to has been corrected.)
%upper
The first built-in we'll look at, %upper, is defined with two parameters and, as you might guess, uppercases a character string. The first parameter is required and is the character string that is to be uppercased. This parameter must be a CL variable of Type(*Char). The second parameter is optional and identifies the CCSID of the character string to be uppercased. This parameter, if specified, must be a CL variable of Type(*Int), a CL variable of Type(*Dec) with zero decimal positions, or a numeric literal with zero decimal positions. When not specified, the default CCSID to use for uppercasing is the job CCSID.
The %upper built-in returns a character string of the same length as the first parameter, with each lowercase letter in the first parameter replaced by the equivalent uppercase letter. This return value can be used to set the value of a CL variable (for instance, used in the Value parameter of the ChgVar command) or to perform tests (for instance, the Cond parameter of the If or When commands).
As an example, let's say we have a CL program that is passed a parameter declared as the following:
Dcl Var(&Response) Type(*Char) Len(1)
If we wanted to test &Response for "Yes" where "Yes" could be specified as either 'Y' or 'y', then in the past we might have coded something like shown below:
If Cond((&Response *EQ 'Y') *OR (&Response *EQ 'y')) +
Then(Do)
With the %upper built-in, we could simplify this test with the following:
If Cond(%Upper(&Response) *EQ 'Y') +
Then(Do)
Not a big savings with this specific example but, to make an extreme example, if you wanted to test for all possible representations of a classification type such as Confidential (that is, 'confidential', 'CONFIDENTIAL', 'Confidential', 'COnfidential', and so on—there are by the way 4092 more "so on" ways to represent Confidential), then Cond(%Upper(&ClassType) *EQ 'CONFIDENTIAL') might be just the ticket.
%lower
The %lower built-in, as you might expect, is used in the same manner as %upper but returns the lowercase equivalent of the input string. As with %upper, %lower is defined with two parameters. The first parameter is required and is the character string that is to be lowercased. This parameter must be a CL variable of Type(*Char). The second parameter is optional and identifies the CCSID of the character string to be lowercased. This parameter, if specified, must be a CL variable of Type(*Int), a CL variable of Type(*Dec) with zero decimal positions, or a numeric literal with zero decimal positions. When not specified, the default CCSID is the job CCSID.
The %lower built-in returns a character string of the same length as the first parameter with each uppercase letter in the first parameter replaced by the equivalent lowercase letter. This return value can be used to set the value of a CL variable (the Value parameter of a ChgVar command) or to perform tests (the Cond parameter of an If or When command).
To following demonstrates the use of both %lower and %upper within an expression.
Dcl Var(&Name) Type(*Char) Len(5) Value('Bruce')
SndPgmMsg Msg('Oh' *BCat %Lower(&Name) *TCat ',' *BCat +
&Name *TCat ',' *BCat %Upper(&Name) *TCat '...')
The message sent by the SndPgmMsg command is…
Oh bruce, Bruce, BRUCE...
%size
The %size built-in defines one required parameter and returns the number of bytes used to represent the CL variable specified by the parameter. The variable can be of any type, and the built-in can be used anywhere that CL supports an arithmetic expression. As with %upper and %lower, %size can be used to set the value of a CL variable (the Value parameter of a ChgVar command) or to perform tests (the Cond parameter of an If or When command).
Similar to how the %char built-in was my "favorite" of last month's built-ins, %size is my favorite for this month. The reason, which I realize many of you may not share, is that I tend to use a lot of system APIs in my CL programs, and system APIs have a tendency to want to know how "big" something is. An API to retrieve information, for instance, often wants to know how big of a receiver variable I have allocated to put the retrieved information into. As an example, if I wanted to retrieve IPL attribute information using the Retrieve IPL Attributes (QWCRIPLA) API and was interested only in the keylock position, then I might code a structure and length field to call the API as shown below:
Dcl Var(&RcvVar) Type(*Char) Len(10)
Dcl Var(&BytRtn) Type(*Int) Len(4) +
Stg(*Defined) DefVar(&RcvVar 1)
Dcl Var(&BytAvl) Type(*Int) Len(4) +
Stg(*Defined) DefVar(&RcvVar 5)
Dcl Var(&KeyLockPos) Type(*Char) Len(1) +
Stg(*Defined) DefVar(&RcvVar 10)
Dcl Var(&LenRcvVar) Type(*Int) Len(4) Value(10)
Dcl Var(&ErrCde) Type(*Int) Len(4) Value(0)
Call Pgm(QWCRIPLA) Parm(&RcvVar &LenRcvVar IPLA0100 &ErrCde)
Now times have changed, and I want to also know if TCP/IP is started as part of the IPL. In the past, if I wanted to increase the size of my receiver variable in order to access additional information, I needed to remember to make two changes: the declared size of the variable &RcvVar and the value assigned to the variable &LenRcvVar. Using the %size built-in removes the need for me to remember to do this second step. What I can use instead is this:
Dcl Var(&RcvVar) Type(*Char) Len(22)
Dcl Var(&BytRtn) Type(*Int) Len(4) +
Stg(*Defined) DefVar(&RcvVar 1)
Dcl Var(&BytAvl) Type(*Int) Len(4) +
Stg(*Defined) DefVar(&RcvVar 5)
Dcl Var(&KeyLockPos) Type(*Char) Len(1) +
Stg(*Defined) DefVar(&RcvVar 10)
Dcl Var(&StartTCP) Type(*Char) Len(1) +
Stg(*Defined) DefVar(&RcvVar 22)
Dcl Var(&LenRcvVar) Type(*Int) Len(4)
Dcl Var(&ErrCde) Type(*Int) Len(4) Value(0)
ChgVar Var(&LenRcvVar) Value(%Size(&RcvVar))
Call Pgm(QWCRIPLA) Parm(&RcvVar &LenRcvVar IPLA0100 &ErrCde)
By using %size as in ChgVar Var(&LenRcvVar) Value(%Size(&RcvVar)), I am now having the system determine the current size of my &RcvVar, rather than having to do it myself.
%len
The last built-in we'll look at today is %len. The %len built-in defines one required parameter and returns the number of digits or characters of the CL numeric or character variable specified by the parameter. The variable can be of type *Char, *Dec, *Int, or *UInt, and the built-in can be used anywhere that CL supports an arithmetic expression. As with the other built-ins reviewed today, %len can be used to set the value of a CL variable (the Value parameter of a ChgVar command) or to perform tests (the Cond parameter of an If or When command).
For numeric variables, the value returned is the precision of the variable. For instance, if a variable of Type(*Dec) is declared with Len(10 3), then the %len built-in will return a precision of 10, not the number of digits to the left of the decimal point (7) or to the right of the decimal point (3). For character variables, the value returned is the number of characters the variable can hold.
The following demonstrates the use of both the %size and %len built-ins (along with %char from last month's column) with a numeric CL variable of type integer.
Dcl Var(&RcvVar) Type(*Char) Len(22)
Dcl Var(&BytRtn) Type(*Int) Len(4) +
Stg(*Defined) DefVar(&RcvVar 1)
Dcl Var(&BytAvl) Type(*Int) Len(4) +
Stg(*Defined) DefVar(&RcvVar 5)
Dcl Var(&Bytes) Type(*Int) Len(4)
Dcl Var(&Digits) Type(*Int) Len(4)
ChgVar Var(&Bytes) Value(%Size(&BytAvl))
ChgVar Var(&Digits) Value(%Len(&BytAvl))
SndPgmMsg Msg('BytAvl contains up to' *BCat +
%Char(&Digits) *BCat +
'digits in' *BCat +
%Char(&Bytes) *BCat +
'bytes')
The message displayed by the SndPgmMsg command is this:
BytAvl contains up to 10 digits in 4 bytes
A Note About RPG and CL
Before we close, some caveats for those of you who are bilingual in terms of developing in both RPG and CL. While RPG also provides a built-in named %len, the RPG and CL %len built-ins do not provide the same function. For RPG, %len allows you to get or set the length of variable-length character variables (or get the maximum length possible for variable-length character variables), which is decidedly different from the CL %len built-in introduced above. And don't mistakenly try to use the %upper or %lower built-ins in your RPG programs; they're not there.
This concludes the introduction to the new 7.2 CL built-ins. My hope is that you will keep these productivity enhancements in mind as you are writing new, or maintaining existing, CL programs. I know I will.
CL Questions?
Wondering how to accomplish a function in CL? Send your CL-related questions to me at
LATEST COMMENTS
MC Press Online