It's all about the _CPYBYTES instruction.
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:
CMD PROMPT('Departmental Expense Report') PARM KWD(DEPT) TYPE(*DEC) LEN(5 0) MIN(0) MAX(5) + PROMPT('Departments')
Here is an example of the command in action:
MYCMD VALUE(11111 2222 333 44 5)
The command processor passes a 17-byte string to the command processing
program (CPP). Here is that string in hexadecimal format:
. . . . + . . . . 1 . . . . + . . 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:
PGM PARM(&DEPTLIST)
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.
CRTCMD CMD(xxx/MYCMD) PGM(xxx/MYPGM) SRCFILE(xxx/QCMDSRC)
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.
|