This article offers the Display File Fields (DSPFF) utility, which uses space pointers to access file field information that the QUSLFLD API writes to a user space object. It consists of these iSeries objects: the DSPFF command itself, the main DSPFF program that is called by the command, the DSPFFFM display file that the main program uses, five externally described data structures that describe the sections of the user space and address some internal RPG control areas, the RTVINF utility program that retrieves database file key field information, the CRTUSRSPC command and its CL program CRTSPCCL that creates a user space if the space does not exist, and the DSPFFPL panel group object that shows Help text for the capabilities of the utility.
When you prompt the command, you are asked to provide the file name and library of a database file, display file, or Intersystem Communication Function (ICF) file to display. You can either display any single record format of the file or let it default to *FIRST. (The Help key on this display provides further information.)
When the DSPFF program is called, it first runs the CRTUSRSPC command to create the user space to hold the field information. Then, the QUSLFLD API is run to put the file record format field information into the space object. So far, this is similar to the way DSPRCDFMT works.
At this point, rather than calling the QUSRTVUS API to read the field information from the user space, the program calls the QUSPRTUS API to get a space pointer to the user space. Space pointers are 16-byte system objects that provide addressability to the space used by an object (in this case, the user space). Most of the time, pointer manipulation is done under the covers by compiler-generated code, and you don't have to worry about it. Occasionally, you might see the "pointer not set for location referenced" error message. This means that some bit of code failed to set a space pointer before the program tried to reference a data object that is based on the pointer. You will see a little bit of how this works in this article.
You call the QUSRTVUS API with just two parameters: the usual 20-byte qualified user space designation (name in the first 10 positions, library in the second 10) and a pointer variable name. In RPG IV, you define a pointer variable by placing an asterisk (*) in the DataType field on the D-spec. In some cases, you can allow RPG to define pointer variables for you--for example, when you are using based-on variables, as is done in this article. But I like to define them explicitly. A good practice is to initialize them to *NULL, which means that they are not yet pointing to (or addressing) any space object.
The API returns after setting a valid address to the user space into your pointer. If the error indicator defined on the call is off, you now have addressability defined into your user space, and you may read it in a manner similar to that used by the IBM system programs.
Now, "materialize" the control section of the user space. Since the control section is at offset zero, it may be addressed by the pointer returned by the QUSPTRUS API without any modification. The instructions that do this are in the SETPTR routine.
As you can see from the DDS, the externally described data structure APICTL is based on the pointer field APICTLPTR. The instant that this pointer is assigned an address by the
instruction, the information in the area of the user space that is addressed by the pointer becomes "visible" to the RPG program. If you get into debug mode and try to display any field in the APICTL structure before your pointer is set, you will get the "pointer not set for location referenced" error. Once the pointer is set, however, you can view any field in the structure. The layout of the APICTL area, which is standard for all the IBM List-into-User-Space APIs, is shown in Figure 1.
Figure 1: The layout of the APICTL area is standard for all List-into-User-Space APIs. (Click images to enlarge.)
The way the externally described structures APIHDR and APIDTL are "materialized" is similar. The program exploits the fact that the offsets in bytes to the start of the user space header and detail areas are set by the QUSLFLD API in the control area when it writes the format field information to the space. The field CTHDOS is the header offset, and CTDTOS is the detail offset. This structure is basically the same for all the List-into-User-Space APIs.
To set the APIHDRPTR space pointer to the start of the header area, add the header offset to the address of the beginning of the space:
|
The offset to the start of the detail area is set into the APIDTLPTR in the exact same way. The offset that you need is the APICTL structure subfield CTDTOS.
The last major thing you do in the *INZSR routine before moving to the MAIN-LINE is to get the file key field information (if the file in question is a database file, not a display or ICF file). This is done with the GETKEY routine, which sends the file name, library, and format name to the Retrieve File Information (RTVINF) program. An array of key field names is returned, which is essentially an ordered list: Element 1 is key field 1, element 2 is key field 2, and so on. Up to 99 keys are returned, which should be enough for almost all applications. RTVINF uses the QDBRTVFD API, which is roughly the API equivalent of the DSPFD command. It can return a wealth of information in a format that is rather complex to interpret, even though it runs very fast. Suffice it to say that the program uses similar pointer techniques to materialize the information returned, as I explained above for the DSPFF program.
You are now ready to call the BLDSFL routine in the MAIN-LINE to build the field information subfile, since you now have all pointers properly set to the start of the appropriate areas in the user space that contains the information. BLDSFL first looks at another control area subfield called CTENNR. This is the number of detail entries in the detail area of the user space, which is exactly the number of fields in the record format passed to the API. The number of entries could be zero (for example, in a display file format that has constant text only), so the test needs to be made to keep the program from falling over; if you try to read an offset into a space that points to beyond the end of the space, you will get an out-of-bounds error and be expelled from the game. For each detail entry found, the routine does the expected and rather mundane things to get the desired information in the subfile record fields and write the subfile record to the display file.
Now, you have to get the next detail area offset to "materialize" the next detail entry's field information. Make sure you have not already read the last entry, and then increment the detail pointer by the entry size field (CTENSZ) to point to the next entry in the detail area. This relies on the fact that the entries are contiguous within the detail area subspace and that each entry is offset from the previous entry by exactly "entry-size" bytes. Things change from release to release, so this method is much safer than using hard-coded offsets because you can rely on the QUSLFLD API to set the header offset, detail offset, number of entries, and entry size values correctly. For example, the detail area entry size (that is, the number of bytes returned for each field information occurrence) is now up to 448 bytes at V5R1; this is much more information than was returned at V1R3, when the DSPFF program was written. And it still works; we can rely on IBM to set these control fields correctly.
To elaborate further: When you create the externally described structure APIDTL, you might notice that its length is 288 bytes, which might be quite a bit less than the value of the entry size (that is, the value of field CTENSZ), which was set by the QUSLFLD API. This value will depend on what release you are on. CTENSZ is 448 bytes as of V5R1. From release to release, IBM often expands internal structures such as the detail area produced by the QUSLFLD API. As long you use the proper offset to find the start of the next detail area block, you do not need to "materialize" the entire structure into your program.
Figure 2 shows a sample of the display when the DSPFF command is run against a database file. You can press the Help key to see a list of valid function keys for this utility.
Figure 2: This sample display shows the DSPFF command for an actual database file.
To sum up, the DSPFF utility is a tool that lets you see the field description information for a file record format by using space pointers to access the information placed into a user space object by the QUSLFLD API. It is useful (as well as interesting!) to understand how pointers work, since some of the newer APIs require you to pass one or more pointers to them to access information. This actually became a business programming requirement for me when I needed to use the UNIX-style APIs--open(), read(), close(), and so forth--to read information from an Integrated File System (IFS) directory. I hope this article will make this kind of programming task a bit easier for you.
Richard Hart is an iSeries programmer with more years of experience on the IBM System/34 through the iSeries than he likes to think about. He can be reached by email at
LATEST COMMENTS
MC Press Online