I am a big believer in creating commands to drive CL programs. Perhaps the greatest benefit of using commands is that the command processor converts parameter arguments to the proper data formats. But the command processor is not without its shortcomings. Anyone who has tried to pass a list of decimal numbers from a command to a CL program knows that CL has no way to extract decimal values from a list. Fortunately, this problem is easily overcome in V5R3.
Consider the following command, which accepts up to five department numbers:
PARM KWD(DEPT) TYPE(*DEC) LEN(5 0) MIN(0) MAX(5) +
PROMPT('Departments')
Here is an example of the command in action:
The command processor passes a 17-byte string to the command processing program (CPP). Here is that string in hexadecimal format:
000511111F02222F00333F00044F00005F
The first two bytes contain a binary integer that tells how many elements are in the list. In this case, there are five elements. Since an element is defined to be a five-digit packed decimal number, each element occupies three bytes.
The designers of the CL compiler did not provide a way to extract decimal numbers from a list, but V5R3 has a way to overcome that problem. i5/OS includes the Machine Interface (MI) _CPYBYTES instruction, which can copy a series of characters from one variable to another, regardless of the data types of those variables. _CPYBYTES requires three parameters: the variable to receive the data, the variable from which the data is copied, and the number of bytes to copy. The first two variables are passed by reference (i.e., their addresses in memory are passed to _CPYBYTES), but the third parameter must be passed by value. Since V5R3 allows parameters to be passed to procedures by value, V5R3 CL can bind to the _CPYBYTES command.
Here is a CPP for the command given above:
DCL VAR(&DEPTLIST) TYPE(*CHAR) LEN(32)
DCL VAR(&COUNTER) TYPE(*INT) LEN(4)
DCL VAR(&ELEMENTS) TYPE(*INT) LEN(4)
DCL VAR(&SIZE) TYPE(*INT) LEN(4) VALUE(3)
DCL VAR(&POS) TYPE(*INT) LEN(4) VALUE(3)
DCL VAR(&CHARVAR) TYPE(*CHAR) LEN(3)
DCL VAR(&NUMDEPT) TYPE(*DEC) LEN(5)
DCL VAR(&CHARDEPT) TYPE(*CHAR) LEN(5)
CHGVAR VAR(&ELEMENTS) VALUE(%BIN(&DEPTLIST 1 2))
DOFOR VAR(&COUNTER) FROM(1) TO(&ELEMENTS)
CHGVAR VAR(&CHARVAR) VALUE(%SST(&DEPTLIST &POS &SIZE))
CALLPRC PRC('_CPYBYTES') +
PARM((&NUMDEPT) (&CHARVAR) (&SIZE *BYVAL))
CHGVAR VAR(&CHARDEPT) VALUE(&NUMDEPT)
/* The next department number in the list has been extracted. */
/* The department number is in &NUMDEPT in numeric format and */
/* in &CHARDEPT in character format. */
CHGVAR VAR(&POS) VALUE(&POS + &SIZE)
ENDDO
The first CHGVAR command initializes the &ELEMENTS variable with the number of elements in the list in order to make the DOFOR loop run once for each value in the list. Within the loop, the three-byte substring that contains a decimal number is extracted into &CHARVAR, a working variable. &CHARVAR is fed to _CPYBYTES, which copies the department number into packed-decimal variable &DEPTNUM. The extraction has been successful! At this point, the program is able to use the extracted department number in decimal format or copy the department number to a character variable, as need dictates.
If you'd like to create these objects, you'll need the following commands. Replace xxx with the name of your library.
CRTCLMOD MODULE(xxx/MYPGM) SRCFILE(xxx/QCLSRC)
CRTPGM PGM(xxx/MYPGM) MODULE(xxx/MYPGM)
To learn more about creating commands, see Power CL by Ted Holt and Ernie Malaga. For up-to-date V5R3 CL features, refer to Complete CL, also by Ted Holt and Ernie Malaga .
Paul Amsden has worked in the information technology field for more than 10 years.
LATEST COMMENTS
MC Press Online