CL programs are often short and simple. However, some CL programs develop a life of their own and just grow and grow. Repetition is a common feature of such programs. This tip looks at three ways of avoiding repetitive CL code:
a. Parameterized subprograms
Subprograms are a great way to isolate common functions. Let's take a simple example. You need to reorganize a number of files. The basic steps are as follows:
These commands and their parameters properly typeset could take a dozen lines. If you want to process five files, that comes to 60 lines of code. You end up coding each command five times, which is a nuisance if you need to change a command's parameters. However, you could isolate the functionality in a REORG subprogram that accepts a file parameter:
pgm (&file) dcl &file *char len( 10 ) /* process &file */ endpgm
To reorganize your files you code, use this:
call reorg 'INVMST' call reorg 'INVBAL' call reorg 'CUSMST' call reorg 'ORDHDR' call reorg 'ORDDTL'
Subprograms are good for isolating common functions. However, repetitive functions specific to one job end up in separate source members; if you have numerous functions in sequentially named programs (e.g. INV821, INV822), your logic flow can be difficult to follow.
b. Array processing
Array processing is good for isolating specific functions in a job. Although CL doesn't support arrays, you can mimic them. Just treat an array as a character string, and treat elements as substrings. To define a file array you code the following:
dcl &pos *dec len( 5 ) value( 1 )
dcl &file *char len( 10 )
dcl &files *char len( 100 ) value( 'INVMST +
INVBAL +
CUSMST +
ORDHDR +
ORDDTL ')
&FILES defines the file array. Notice that the length of the field is large enough to hold at least one blank element. &FILE defines an element in the array. &POS defines the position of the current element. To loop round the array, you code this:
next:
chgvar &file %sst( &files &pos 10 )
chgvar &pos (&pos + 10)
if (&file *ne ' ') do
/* process &file */
goto next
enddo
The current element in the array is copied into &FILE and &POS incremented to point to the next element. The element is processed and the code repeated until the blank element at the end of the array is accessed.
CL arrays are simple to use and let you group related functions together rather than splitting them into separate programs.
c. QCMDEXC
Subprograms and arrays work when you can substitute a CL variable into a command parameter. This isn't always possible. For example, the OBJ parameter on the SAVOBJ command accepts a list of objects. So you can't substitute a variable directly into the SAVOBJ command:
dcl &objs *char len( 100 ) value( 'INVMST INVBAL CUSMST ORDHDR ORDDTL' ) savobj obj( &objs )
However, you can output the command to a string to process with QCMDEXC:
dcl &cmd *char len( 2000 )
dcl &cmdLen *dec len( 15 5 ) value( 2000 )
chgvar &cmd ( 'savobj' *bcat +
'obj(' *bcat &objs *bcat ')' *bcat +
'lib(' *bcat &objLib *bcat ')' *bcat +
'savf(' *bcat &savLib *tcat '/' *tcat +
&savFil *bcat ')' *bcat +
'dev( *savf )' )
call qcmdexc parm( &cmd &cmdLen )
&CMD holds the command string, and &CMDLEN defines its length. You can store &CMD's declared length in &CMDLEN rather than the length of the actual command string. The QCMDEXC program executes the command stored in &CMD.
The above tip was written by Julian Monypenny.