What’s New In CL Programming Kevin Forsythe DMC Consulting kevin.forsythe@dmcconsulting.com 1 What’s New In CL Programming In the last two releases, IBM has made huge and unprecedented changes in the CL programming language. Until V5R3 and V5R4, CL had seemed about as dormant as DOS! But now we can all thank IBM for beefing up this language and providing us with a number of great features. These enhancements improve CL program’s ability to interoperate with other languages, and generally make it easier and more productive to work with. 2 What’s New In CL Programming Included in the recent enhancements are: • 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 3 What’s New In CL Programming 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 it provides an even more compact form than the traditional packed (*DEC) format. The following chart illustrates the maximum values expressed by *INT, *UINT, and *DEC formats (for comparison). 4 What’s New In CL Programming • • • • • • Data Type *INT *UINT *DEC *INT *UINT *DEC Size in Bytes 2 2 2 4 4 4 Maximum value 32K 64K 999 2 Bil. 4 Bil. 9,999,999 5 What’s New In CL Programming A simple example of when to use one of these is any time that you need a “counter” or “index” variable. In the following example, 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 3 times before giving up. 6 What’s New In CL Programming PGM PARM(&FILE &LIB) DCL &FILE *CHAR (10) DCL &LIB *CHAR (10) DCL &X *UINT (2) CRTDUPOBJ OBJ(&FILE) FROMLIB(&LIB) OBJTYPE(*FILE) + TOLIB(ARCHIVE) DATA(*YES) MONMSG MSGID(CPF0000) EXEC(DO) DLTF ARCHIVE/&FILE CRTDUPOBJ OBJ(&FILE) FROMLIB(&LIB) + OBJTYPE(*FILE) TOLIB(ARCHIVE) DATA(*YES) ENDDO 7 What’s New In CL Programming DLT: DLTF &LIB/&FILE MONMSG MSGID(CPF0000) EXEC(DO) CHGVAR &X (&X +1) IF COND(&X >= 3) THEN(DO) SNDUSRMSG MSG('File' *BCAT &FILE *BCAT + 'in library' *BCAT &LIB *BCAT 'Was not destroyed.') + MSGTYPE(*INFO) TOUSR(*REQUESTER) GOTO END ENDDO GOTO DLT ENDDO 8 What’s New In CL Programming SNDUSRMSG MSG('File' *BCAT &FILE + *BCAT 'in library ' *BCAT &LIB *BCAT + 'destroyed.') MSGTYPE(*INFO) + TOUSR(*REQUESTER) END: ENDPGM 9 What’s New In CL Programming Pointers • Pointers are fairly new for most RPG programmers, but they have been around 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. 10 What’s New In CL Programming • 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 API’s, pointers provide much needed flexibility. • The following example shows 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. 11 What’s New In CL Programming PGM DCL &LIBL *CHAR (2750) DCL &PTR *PTR ADDRESS(&LIBL) DCL &LIB *CHAR (10) STG(*BASED) + BASPTR(&PTR) RTVJOBA USRLIBL(&LIBL) 12 What’s New In CL Programming CHECK: IF COND(&LIB = 'EUREKA') THEN(DO) SNDUSRMSG MSG('I Found it!') + MSGTYPE(*INFO) TOUSR(*REQUESTER) GOTO END ENDDO CHGVAR VAR(%OFS(&PTR)) VALUE(%OFS(&PTR) + 11) GOTO CHECK END: ENDPGM + 13 What’s New In CL Programming The field &PTR is defined as a *PTR data type and 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 further down the &LIBL field. 14 What’s New In CL Programming 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. 15 What’s New In CL Programming PGM DCL &LIBL *CHAR (2750) DCL &FIRSTLIB *CHAR10) + STG(*DEFINED) DEFVAR(&LIBL 1) • Variables may be defined as being sub-fields of other variables. This is similar to a data structure in RPG. 16 What’s New In CL Programming 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. This may not present any truly new ability, it does however, provide a much easier to read and understand logical control for CL Programs. The following example illustrates the use of the select statement by sending users to a different menu based upon their user class. 17 What’s New In CL Programming PGM DCL &CLASS *CHAR (10) RTVUSRPRF USRCLS(&CLASS) 18 What’s New In CL Programming SELECT WHEN COND(&CLASS = '*SECOFR') THEN( + GOTO UBERLEET) WHEN COND(&CLASS = '*SECADM') THEN( + GOTO NOTSOUBER) WHEN COND(&CLASS = '*SYSOPR') THEN( + GOTO REALWORK) WHEN COND(&CLASS = '*PGMR') THEN( + GOTO GEEKDOM) OTHERWISE CMD(GOTO LOCKDOWN) ENDSELECT END: ENDPGM 19 What’s New In CL Programming DOUNTIL Statement The DOUNTIL command provides a nice and easy to use tool for looping until some event happens. The following example shows how to use DOUNTIL to force a program to loop continuously until the job, subsystem or the system itself is shut down. 20 What’s New In CL Programming PGM DCL &ENDJOB *LGL DOUNTIL COND(&ENDJOB) CALL PGM1 CALL PGM2 CALL PGM3 RTVJOBA ENDSTS(&ENDJOB) ENDDO END: ENDPGM 21 What’s New In CL Programming Its 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. 22 What’s New In CL Programming DOWHILE Statement If DOUNTIL’s test at the end of the loop bugs you, you could use DOWHILE instead. It is very 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. 23 What’s New In CL Programming PGM DCL &ENDJOB *LGL RTVJOBA ENDSTS(&ENDJOB) DOWHILE COND(*NOT &ENDJOB) CALL PGM1 CALL PGM2 CALL PGM3 RTVJOBA ENDSTS(&ENDJOB ENDDO END: ENDPGM 24 What’s New In CL Programming • Example: PGM PARM(&SLSDIST &DATE) DCL VAR(&SLSDIST) TYPE(*CHAR) LEN(3) DCL VAR(&DATE) DCL VAR(&ERRORS) TYPE(*LGL) VALUE(‘1’) TYPE(*DEC) LEN(6 0) ENDPGM 25 What’s New In CL Programming DOFOR Statement If you have a loop that executes a specific number of times, DOFOR will come in handy. The following example illustrates a modified version of an earlier example. 26 What’s New In CL Programming PGM PARM(&FILE &LIB) DCL &FILE *CHAR (10) DCL &LIB *CHAR (10) DCL &X *INT (2) DCL &ERR *LGL 27 What’s New In CL Programming CRTDUPOBJ OBJ(&FILE) FROMLIB(&LIB) + OBJTYPE(*FILE) + TOLIB(ARCHIVE) DATA(*YES) MONMSG MSGID(CPF0000) EXEC(DO) DLTF ARCHIVE/&FILE CRTDUPOBJ OBJ(&FILE) FROMLIB(&LIB) + OBJTYPE(*FILE) + TOLIB(ARCHIVE) DATA(*YES) ENDDO 28 What’s New In CL Programming CHGVAR VAR(&ERR) VALUE(‘1’) DOFOR VAR(&X) FROM(1) TO(3) BY(1) DLTF &LIB/&FILE MONMSG MSGID(CPF0000) EXEC(ITERATE) CHGVAR VAR(&ERR) VALUE(‘0’) LEAVE ENDDO 29 What’s New In CL Programming IF COND(&ERR) THEN( + SNDUSRMSG MSG('File' *BCAT &FILE + *BCAT 'in library‘ *BCAT &LIB + *BCAT 'Was not destroyed.') + MSGTYPE(*INFO) TOUSR(*REQUESTER)) ELSE CMD( + SNDUSRMSG MSG('File' *BCAT &FILE + *BCAT 'in library ' + *BCAT &LIB *BCAT 'destroyed.') + MSGTYPE(*INFO) TOUSR(*REQUESTER)) END: ENDPGM 30 What’s New In CL Programming Subroutines Okay, is it just me, or is it incredible that IBM has added subroutine support to CL programs? While its true a lot of CL programs are far too simple to benefit the use subroutines. There are plenty of places where it is very useful. The following example 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. 31 What’s New In CL Programming PGM DCL &MSG *CHAR (80) DCL &ANS *CHAR (1) DCL &X *INT (2) DOUNTIL (&X = 1) CHGVAR &X 1 CALL PGM1 MONMSG MSGID(CPF0000) EXEC(CALLSUBR ERR) ENDDO 32 What’s New In CL Programming DOUNTIL (&X = 2) CHGVAR &X 2 CALL PGM2 MONMSG MSGID(CPF0000) EXEC(CALLSUBR ERR) ENDDO DOUNTIL (&X = 3) CHGVAR &X 3 CALL PGM3 MONMSG MSGID(CPF0000) EXEC(CALLSUBR ERR) ENDDO 33 What’s New In CL Programming SUBR SUBR(ERR) RCVMSG MSG(&MSG) SNDUSRMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&MSG) + VALUES(C I D R) DFT(R) TOMSGQ(*SYSOPR) + MSGRPY(&ANS) 34 What’s New In CL Programming SELECT WHEN (&ANS = C) THEN(+ SNDPGMMSG MSGID(CPF9897) + MSGF(QCPFMSG) MSGDTA(&MSG) + MSGTYPE(*ESCAPE)) WHEN (&ANS = R) THEN(+ CHGVAR &X 0) 35 What’s New In CL Programming WHEN (&ANS = D) THEN(DO) DUMPCLPGM SNDPGMMSG MSGID(CPF9897) + MSGF(QCPFMSG) MSGDTA(&MSG) + MSGTYPE(*ESCAPE)) ENDDO ENDSELECT ENDSUBR END: ENDPGM 36 What’s New In CL Programming 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 sub routine 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. 37 What’s New In CL Programming Multiple Files Another great and recent 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, there are still times when it is very convenient to read two or more files in the same program. The following example 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. 38 What’s New In CL Programming PGM PARM(&TEXT) DCLF FILE(APPLIBS) OPNID(LIBS) DCLF FILE(QAFDBASI) OPNID(FILES) DCL VAR(&TEXT) TYPE(*CHAR) LEN(40) /* LOOP THROUGH EACH LIBRARY /* IN THE APPLIBS FILE /* AND ADD ALL OF FILES /* IN EACH TO QGPL/FILES */ */ */ */ 39 What’s New In CL Programming DOWHILE COND(1 = 1) RCVF OPNID(LIBS) MONMSG MSGID(CPF0864) EXEC(LEAVE) DSPFD FILE(&LIBS_LIBNAME/*ALL) + TYPE(*BASATR) + OUTPUT(*OUTFILE) + OUTFILE(QTEMP/FILES) + OUTMBR(*FIRST *ADD) ENDDO 40 What’s New In CL Programming /* /* /* /* READ EACH FILE IN QGPL/FILES AND PERFORM A FNDSTRPDM AGAINST IT. SEARCHING FOR THE PARM &TEXT OVRDBF FILE(QAFDBASI) + TOFILE(QTEMP/FILES) DOWHILE COND(1 = 1) RCVF OPNID(FILES) */ */ */ */ MONMSG MSGID(CPF0864) EXEC(LEAVE) 41 What’s New In CL Programming IF (&FILES_ATDTAT = 'S' *AND + &FILES_ATFTYP = 'P') THEN(DO) FNDSTRPDM STRING(&TEXT) + FILE(&FILES_ATLIB/&FILES_ATFILE) + MBR(*ALL) OPTION(*NONE) PRTMBRLIST(*YES) + PRTRCDS(*NONE) MONMSG MSGID(PDM0000) ENDDO ENDDO DLTOVR FILE(QAFDBASI) ENDPGM 42 What’s New In CL Programming Each of the declare files have an OPNID parameter (LIBS and FILES respectively) which 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. 43 What’s New In CL Programming 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, the open ID is FILES, and so the variable name in the CL program is &FILES_ATFILE. If you are only using one file in the CL program, you can omit the open ID from the RCV command and the field names. 44 What’s New In CL Programming • Use Procedure calls to integrate more tightly with ILE applications. This also allows us to create more practical and functional tools. 45 What’s New In CL Programming • CALLPRC PRC(‘RUNSQL') + PARM((&SQLSTMT *BYVAL)) + RTNVAL(&SQLCODE) 46 Possible Future Changes •CLOSE command (read file more than once) •INCLUDE command (like /COPY in RPG) •Modify CVTDAT to support larger year range •Compiler option to keep unreferenced CL variables •Show DO/SELECT levels on compiler listing •Support *BYREF/*BYVAL for ILE CL procedures •Increased variable sizes •Support for Arrays 47 What would you like… What changes/enhancements would you like to see? 48 Any Questions ????? 49 What’s New In CL Programming While it is doubtful that many shops will jump to V5R4 just to get these new features in CL, its 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… 50