If you're a frequent reader of this column, then you probably know that I'm a big fan of user space objects and, likewise, not a fan of data areas.
However, there are shortcomings in user spaces. For example, there are no native Create User Space (CRTUSRSPC), Change User Space (CHGUSRSPC), or Retrieve User Space (RTVUSRSPC) commands. It seems there is a Delete User Space (DLTUSRSPC) command, though. This week, I want to solve the problem of one of those missing commands, RTVUSRSPC.
The Retrieve Data Area (RTVDTAARA) command has an interesting parameter list. In one parameter, you identify the data area, the starting position, and the length of the data you want to retrieve. Then, in a second parameter, you specify a CL variable that will receive the data being retrieved.
There are very few people left in the world using OS/400 who, I think, could write a clone of the RTVDTAARA command and create the correct command processing program (CPP) to run it. The command has a mixed-list parameter, also known as a list within a list. This is not too difficult to create in the command definition source, but the CPP structure to receive it is a bit unusual.
To create a command similar to RTVDTAARA, we'll need to reverse engineer it. Let's look at the command prompt to get an idea of what it does. Figure 1 illustrates the prompt for the RTVDTAARA command.
Figure 1: The RTVDTAARA CL command prompt looks like this.
Back in the days of CPF and System/38, you could simply look at the microfiche and read the command definition source statements for any CL command. At one point, the clever folks at Advanced Systems Concepts, Inc. wrote a Retrieve Command Definition Source command. But that command has long since been lost to obscurity and the ever-advancing security levels in OS/400.
RTVUSRSPC--Command Definition Source
I had to reverse engineer the parameter structure of RTVDTAARA in order to create the command definition source for a RTVUSRSPC command. After looking at the prompter and pressing F4 on each parameter (to get its data type), I realized that even though it looks like there are at least four parameters, there are in fact only two: one for the data area name and another for the return variable. I suppose I could have figured that out by reading the CL reference manual, but typing in the CL command and pressing F4 was much faster.
The first parameter contains not only the data area name, but also the starting location and number of bytes to retrieve. To me, this means an ELEM list with three pieces: a qualified object name and two numeric entries. In reality, I ended up with an ELEM list that contains a qualified name and another ELEM list; that is, it is an ELEM list within an ELEM list.
The second parameter is interesting. It seems to allow a CL return variable of any data type and any length to be specified. Not being too good at remembering such obscure command definition source syntax, I wrote to the original author of CL commands and asked him. It seems I'm not the only one who hasn't done this kind of thing for a while. He didn't remember either.
Since I had written many commands with this type of parameter before, I just needed to locate an existing example. So I went back to my old archives of Q38, the newsletter for programmers of the IBM System/38, and tried to locate a command I had previously written that might have a similar parameter. Fortunately, I found one--as well as its corresponding CPP. So life is good! Listed in Figure 2 is the command definition source code for the RTVUSRSPC command.
|
Figure 2: Here's the command definition source for RTVUSRSPC.
To compile the command definition for RTVUSRSPC, use the PDM option 14 or issue the following CL command:
CRTCMD CMD(RTVUSRSPC) PGM(TOOLKIT/RTKRTVUS) +
ALLOW(*IPGM *BPGM)
Most of the command definition source is very traditional: a qualified name and a mixed list. The RTNVAR parameter is more complicated and deserves additional explanation.
The RTNVAR parameter is a TYPE(*X) data type. This is an option that tells the command definition object to allow any type of value for this parameter. The RTNVAL(*YES) keyword indicates that this parameter accepts only CL variable names. This also means that when the CL command is compiled, you must specify ALLOW(*IPGM *BPGM) on the CRTCMD command.
When the CPP receives this parameter, a data structure is created that contains an attribute byte identifying the type and length of the CL variable. These additional pieces are created because I specified the PASSATR(*YES) and VARY(*YES *INT2) keywords on the PARM statement.
The PASSATR(*YES) keyword tells the parameter to include an extra attribute byte that indicates the type of data or CL variable type that is passed. The VARY(*YES) keyword tells the parameter to include the length of the value specified for the parameter as a prefix to the parameter's data. Since I specified VARY(*YES *INT2), the length is inserted as a 2-byte binary value. The actual data structure that I used in the CPP is illustrated in Figure 3.
|
Figure 3: This is the RTNVAR parameter data structure.
The data-type attribute byte (subfield nAttr) indicates the kind of CL variable that was passed to the program (numeric, character, etc.). The data-type attribute is followed by the parameter's length. The length is broken down further into decimal field length and decimal positions. These additional fields are used when the data type is numeric.
The area that will receive the return value begins in position 4 of this data structure and continues for the length of the CL variable. Be careful when writing this kind of stuff yourself; even though the subfield szRtnVar is 6000 bytes in length, you can only access the positions that are within the length of the CL variable passed in. That is, if the data length is 10, then only the first 10 positions have storage that you may access. I made the subfield 6000 bytes long because that is the current maximum length of a CL variable. I've heard rumors that in V5R3 the maximum length will increase to a much larger value, but I can't speculate on what that new limit will be.
Figure 4 illustrates what the prompted RTVUSRSPC CL command looks like.
Figure 4: And here's what the RTVUSRSPC CL command prompt looks like.
The RTVUSRSPC CL command can be used standalone or with the CRTUSRSPC and CHGUSRSPC commands that are included free with the RPG ToolKit. With these three CL commands and the capabilities of RPG IV and the RPG ToolKit, you can effectively replace data areas with user space objects and have a fairly seamless migration path.
RTVUSRSPC--Command Processing Program
Listed in Figure 5 is the RPG IV source code for RTKRTVUS, the CPP for the RTVUSRSPC command. If you own the RPG ToolKit, the program will compile and leverage the ease-of-use tools in the ToolKit. If you do not own the ToolKit, the program will also compile fine, but it will use significantly more lines of code to accomplish the same tasks. Nonetheless, it works fine with or without the ToolKit by activating or deactivating the /DEFINE compiler preprocessor directives.
|
Figure 5: RTKRTVUS is the CPP for the RTVUSRSPC command.
Bob Cozzi has been programming in RPG since 1978. Since then, he has written many articles and several books, including The Modern RPG Language--the most widely used RPG reference manual in the world. Bob is also a very popular speaker at industry events such as RPG World and is the author of his own Web site and of the RPG ToolKit, an add-on library for RPG IV programmers.
LATEST COMMENTS
MC Press Online