In
the last two releases, IBM has made huge and unprecedented changes in the CL
programming language. Until V5R3 and V5R4, CL seemed about as dormant as DOS!
But now, we can all thank IBM for beefing up this language and providing us with
many great features. These enhancements improve CL's ability to interoperate
with other languages and generally make CL easier and more productive to work
with.
These are some of the enhancements:
- Support for integer and unsigned integer data types
- Support for pointer data types
- Select
- DoUntil loop
- DoWhile loop
- DoFor loop
- Subroutines
- Support for processing up to five files
Integers and Unsigned Integers
These new data types provide an efficient method of
storing certain numeric data. Obviously, if the data contains decimal values,
then these two data types are inappropriate, but otherwise, they provide an even
more compact form than the traditional packed (*DEC) format. The following chart
illustrates the maximum values expressed by the *INT, *UINT, and *DEC formats
(for comparison).
Relative Data Type Size and Maximum
Values
|
|||
|
Data Type
|
Size in Bytes
|
Maximum Value
|
Integer
|
*INT
|
2
|
32,000
|
Unsigned Integer
|
*UINT
|
2
|
64,000
|
Packed
|
*DEC
|
2
|
999
|
Integer
|
*INT
|
4
|
2 Billion
|
Unsigned Integer
|
*UINT
|
4
|
4 Billion
|
Packed
|
*DEC
|
4
|
99,999
|
The code statements below
show the definition of the new integer data types with the traditional DCL
statement.
DCL &INT2 *INT 4 VALUE(-100000)
DCL &INT3 *UINT 2 VALUE(1000)
DCL &INT4 *UINT 4 VALUE(100000)
A simple example of when to use one of these is any time that you need a
"counter" or "index" variable. In the example shown below in Figure 1, the
program receives a file name as a parameter; it attempts to create an achieved
copy of the object and then deletes the original. If it fails to get a lock, it
retries up to three times before giving up.
|
Figure 1: Archive and delete the selected file.
Pointers
Pointers are fairly new for most RPG programmers, but
they have been around for a long time and are commonly used in other languages,
such as C. Unlike most other data types, pointers do not contain data. Instead,
they contain the memory address for a piece of data. Each pointer is 16 bytes
long, which corresponds to the size of a memory address.
These
sophisticated variables might seem out of place in CL programs, which are
typically fairly simple programs. However, for greater interoperability with
other languages and APIs, pointers provide much-needed flexibility.
The
example shown in Figure 2 illustrates how to use pointers to scan through a
large text field holding the current user portion of the library list and
searching for a specific library.
|
Figure 2: Search the library list.
The field &PTR is
defined as a *PTR data type and is initialized with the address of &LIBL.
The variable &LIB is "based" on &PTR. This means that it does not have
its own location in storage (memory). Rather, it moves to the location given in
&PTR. When this program loads, &LIB initially overlays the first 10
bytes of &LIBL. Each time the program loops, the pointer moves 11 characters
farther down the LIBL field. The offset function (%OFS) allows the CL program to
easily adjust the location of the pointer by simply adding or subtracting a
number of bytes. The program uses an increment of 11 because there is one byte
of blank data between each library name in the list, and each library name is 10
characters long, so the total is 11.
SELECT Statement
The SELECT statement is nothing more than a
specialized "IF" structure. It defines a set of mutually exclusive tests. Each
test has a corresponding command to execute upon a successful test. As soon as
that command is complete, control passes to the statement after the ENDSELECT.
So while this does not present any truly new ability, it does provide a
much easier to read and understand logical control for CL programs. Figure 3
illustrates the use of the select statement by sending users to a different menu
based upon their user class.
|
Figure 3 : Send the user to the correct menu.
DOUNTIL Statement
The DOUNTIL command provides a nice, easy-to-use
tool for looping until some event happens. The example in Figure 4 shows how to
use DOUNTIL to force a program to loop continuously until the job, subsystem, or
the system itself is shut down.
|
Figure 4: Loop through Pgm1, Pgm2, and Pgm3 until EOJ.
It's
important to note that DOUNTIL does not test the value of &ENDJOB until
after the code inside the loop has processed once. The test is performed when
control of the program reaches the ENDDO for the loop.
DOWHILE Statement
If DOUNTIL's test at the end of the loop bugs you,
you could use DOWHILE instead. It is similar in function. However, it loops
while the condition is true and exits the loop when it is not true. And the test
is performed at the beginning of the loop, so there is no guarantee that the
code inside the loop will ever execute.
|
Figure 5: Loop through Pgm1, Pgm2, and Pgm3 until EOJ.
DOFOR Statement
If you have a loop that executes a specific number
of times, DOFOR will come in handy. Figure 6 illustrates a modified version of
the program shown in Figure 1. This version uses DOFOR to control how many times
the delete retries.
|
Figure 6: Archive and delete the selected file.
Subroutines
OK, is it just me, or is it incredible that IBM has
added subroutine support to CL programs? While it's true that a lot of CL
programs are far too simple to benefit from subroutines, they're still very
useful in plenty of places. Figure 7 shows the code for a program that calls
several programs and monitors for errors in each one. A subroutine provides
common error-handling for the program.
|
Figure 7: Provide error-handling.
Notice that the calls to
PGM1, PGM2, and PGM3 are all wrapped up in a Do loop. That loop allows the retry
function of the error-handling subroutine to work. If an error occurs and the
user takes an "R" to retry, &X is set to 0 and the loop will continue
calling the program again. If no error occurs or if a different option is taken,
&X will be unchanged, ending the loop.
Multiple Files
Another great addition to CL is the ability to
handle more than one file in a single program. Sure, the CL language is not
intended for intensive I/O-handling programs; however, sometimes it's convenient
to read two or more files in the same program. Figure 8 shows a CL program that
searches a list of libraries for source physical files and then performs a
FNDSTRPDM command against each of these files, looking for a specified
string.
|
Figure 8: Read data from multiple files.
Each of the declare
files have an OPNID parameter (LIBS and FILES, respectively) that provides a
unique identifier for the files. The RCV command should reference the
appropriate file ID to ensure reading the next record from the appropriate file.
Each of the fields from the files must also use the open ID as a prefix to the
field name, such as &FILES_ATFILE. The field name is ATFILE, and the open ID
is FILES, so the variable name in the CL program is &FILES_ATFILE. If you
are using only one file in the CL program, you can omit the open ID from the RCV
command and the field names.
Pleasant Surprises
While it is doubtful that many shops will jump to
V5R4 just to get these new features in CL, it's still true that most shops will
be happy to take advantage of these enhancements as they move up to the current
release. The enhancements to CL in the last two releases also leave us wondering
what pleasant surprises might be in store for the next release.
Kevin Forsythe is the author of the new book
SQL for eServer i5 and
iSeries. He has over 18 years of experience
working with the iSeries platform and its predecessors. He has been a member of
the DMC team for the past nine years. Kevin's primary responsibility is
providing iSeries education, but he also provides customers with project
management, system design, analysis, and technical construction. In addition to
his technical skills (RPG IV, CL, OS/400, SQL, FTP, Query, VB, Net.Data), Kevin
possesses the ability to communicate new and complex concepts to his students.
He has been the primary instructor for DMC's iSeries-based AS/Credentials
training courses since 1997 and has authored courses such as Advanced ILE, SQL,
Embedded SQL, Operations Navigator, and Intro to WebSphere Studio. An
award-winning speaker, he has spoken at every COMMON Conference since the spring
of 2000.
LATEST COMMENTS
MC Press Online