Virtually all OS/400 commands that manipulate objects can use the library list. Or let me put that even better: Virtually all command parameters that reference objects let you qualify the object in such a way that the object is searched within the library list. The library list is, of course, that facility built into OS/400 that allows you to remove library name qualifiers every time you reference an object. Instead of looking for the object in a given library, the library list searches all libraries within the jobs library list until it finds the object or until it exhausts the library list, whichever happens first.
Figure 1 illustrates the structure of the library list. It has four portions: system, product, current, and user, totaling a maximum of 43 library names. Of these portions, the system is the most important because it houses QSYS, the library in which the operating system lives. In fact, QSYS is so important that you cannot remove it from the system portion of the library list.
I dont want to go into excessive detail describing what the library list is, does, and cannot do. Rather, Id like to focus on a particular problem: the potential multiplicity of objects in two or more libraries, when such libraries are in the library list at the same time.
For instance, suppose you call a program named INV657RG whose purpose is to print invoices. INV657RG is supposed to reside in library ACCTG, but a duplicate of the same program is in library DEVELOP, which you use as a scratch library while doing code maintenance. Both ACCTG and DEVELOP are in your library list. Which of the two INV657RG programs is executed when you call the program without a library qualifier?
The answer depends on the order in which the library names have been placed in the library list: The system will always pick up the program from the library whose name occurs first in the library list. Since the library list has a vertical organization, first means higher. Therefore, if you have placed DEVELOP higher than ACCTG within the library list, it will be DEVELOPs copy of the program that will be executed, not ACCTGs.
This behavior can be an asset, actually. During the development, maintenance, or debugging stages of your work, youll want to execute the copy in DEVELOP. Once the program is ready to be placed into production, you only have to move it from DEVELOP to ACCTG. But you know how it iseven the best policies are ignored or broken, usually by an oversight. This means that sometimes the wrong object may be accessed through the library list. The Find Object in the Library List (FNDOBJLIBL) command can help you determine if thats the case for a given object.
Figure 2 shows a typical panel presented by FNDOBJLIBL. As you can see, the command determined that INV657RG existed in both ACCTG and DEVELOP, as indicated by the library names highlighted with reverse image.
The standard Work with Objects (WRKOBJ) and Work with Objects using PDM (WRKOBJPDM) commands can perform the same service, but FNDOBJLIBL does something else: It gives you an image of the library list structure.
How It Works
The command (see Figure 3) has no parameters, since all work is performed interactively. When you execute it, ILE program OBJ022@ runs automatically. This program is comprised of two CL modules OBJ022CL (Figure 4) and OBJ023CL (Figure
5). The first thing OJB022CL does is retrieve the jobs library list. There are several ways to do so:
With the Retrieve Job Attributes (RTVJOBA) command, using parameters SYSLIBL, CURLIB, and USRLIBL
With the Display Library List (DSPLIBL) command
With the Display Job (DSPJOB) command, specifying TYPE(*LIBL) I used none of these. RTVJOBA cannot give me the name of the product libraries (if any are present); and DSPLIBL and DSPJOB cannot place their output in CL variables or an outfileonly on the screen or printerso they are not very reliable after a release upgrade. Instead of these approaches, I created my own command, Retrieve Library List (RTVLIBL), which is described in full in the sidebar, Retrieving the Library List. For now, just accept the fact that RTVLIBL retrieves all libraries in the library list in four CL variablesone per portion.
Next, OBJ022CL extracts the names of each individual library from the four strings returned by RTVLIBL. Ive named the variables &SYSnn (system portion), &PRDnn (product portion), &CURLIB (current library), and &USRnn (user portion). The program then stops to present the panel, waiting for the user to enter an object name and type.
For each of the possible 43 library names, OBJ022CL calls OBJ023CL. This new procedure determines whether the object exists in the given library and returns a display attribute byteeither a hexadecimal 20 (normal video) if the object was not found or a hexadecimal 21 (reverse image) if the object was found. Then it goes back to label AGAIN to redisplay the panel.
Procedure OBJ023CL (see Figure 5) is not very complicated. Essentially, it runs the Check Object (CHKOBJ) command. If the command fails (either the object doesnt exist or the library doesnt exist), it returns a hexadecimal 20 (normal video). If the object does exist, it returns a hexadecimal 21. Of course, you may be wondering why I have gone to the trouble of creating this additional procedure. The answer is that I have to perform the same task 43 times in a language that does not support subroutines. Calling an ILE procedure, bound by copy, is the most viable alternative.
The display file OBJ022DF (shown in Figure 6) defines quite a few fields; among them are 43 single-byte fields and 43 ten-byte fields, one of each for each library in the
library list. To avoid defining fields incorrectly, Ive defined two hidden fields, BYTE and NAME, as hidden fields. They are 1 and 10 bytes long, respectively. Then I define the actual working fields by reference, pointing to either BYTE or NAME as necessary. Notice the use of *SRC within the REFFLD keyword; *SRC means that the referenced field is contained in the same display file.
The display file potentially needs to highlight 43 output fields. I could have done it using indicators, but I feel that would have been too complicated and error-prone, because theres no direct relationship between an indicator number and the corresponding field name whose display attributes it controls. For instance, I could have assigned indicator 01 to highlight field SYS01 and 02 for SYS02, thereby creating a pretty correspondence (the two digits). But as soon as I reached the product libraries, Id end up with indicator 16 controlling the attribute of PRD01 and 17 for PRD02. And 18 for the current library. The pretty correspondence would be pretty no more. Its much easier to control the attributes via 1-byte fields that have names similar to those of the data fields they control, such as SYS01A controlling SYS01.
So, instead, I decided to highlight the output fields using a one-byte program-to- system field, which is to contain the appropriate hexadecimal display attribute value. For example, if you examine the DSPATR keyword for field SYS01 (the output field containing the first library name within the system portion of the library list), youll see that, instead of showing RI for reverse image, it shows &SYS01A, the one-byte program- to-system field I have already defined for that purpose. If I want to show SYS01 in reverse image, I assign hexadecimal 21 to SYS01A; conversely, to show it in normal video, I assign hexadecimal 20 to SYS01A.
We have covered a lot of ground examining some coding techniques, and now you have new CL and DDS skills, plus two utility commands you can start using immediately. I hope FNDOBJLIBL helps you realize that the library list is not a foe, but a friendan old, dear friend indeed.
Reference System API Reference: OS/400 Work Management APIs (SC41-4878-01, QBKAM701)
System portion (15 libraries maximum) Defined by system value QSYSLIBL.
Product portion (2 libraries maximum) In existence while menu or command is active.
Current portion (1 library maximum) Defined by user profile.
User portion (25 libraries maximum) Defined by system value QUSRLIBL or job description.
Figure 1: Structure of the Library List
Phew!
/*===================================================================*/
/* To compile: */
/* */
/* CRTCMD CMD(XXX/FNDOBJLIBL) PGM(XXX/OBJ022@) + */
/* SRCFILE(XXX/QCMDSRC) TEXT('Find Object in +*/
/* *LIBL') ALLOW(*IPGM *IMOD *INTERACT *EXEC) */
/* */
/* CRTDSPF FILE(XXX/OBJ022DF) SRCFILE(XXX/QDDSSRC) + */
/* TEXT('Display file for FNDOBJLIBL') */
/* */
/* CRTCLMOD MODULE(XXX/OBJ022CL) SRCFILE(XXX/QCLSRC) + */
/* TEXT('PEP for OBJ022@') */
/* */
/* CRTCLMOD MODULE(XXX/OBJ023CL) SRCFILE(XXX/QCLSRC) + */
/* TEXT('Called from OBJ022CL') */
/* */
/* CRTPGM PGM(XXX/OBJ022@) MODULE(XXX/OBJ022CL + */
/* XXX/OBJ023CL) TEXT('CPP for FNDOBJLIBL + */
/* command') */
/* */
/*prerequisite: */
/* */
/* Utility command FWDPGMMSG (see January 1998 issue). */
/* */
/*===================================================================*/
CMD PROMPT('Find Object in *LIBL')
Figure 3: Command FNDOBJLIBL
PGM
DCLF FILE(OBJ022DF)
DCL VAR(&CURLIBL) TYPE(*CHAR) LEN(11)
DCL VAR(&PRDLIBL) TYPE(*CHAR) LEN(22)
DCL VAR(&SYSLIBL) TYPE(*CHAR) LEN(165)
DCL VAR(&USRLIBL) TYPE(*CHAR) LEN(275)
MONMSG MSGID(CPF0000 MCH0000) EXEC(GOTO CMDLBL(ERROR))
/* Retrieve the job's library list */
RTVLIBL JOB(*) SYSLIBL(&SYSLIBL) PRDLIBL(&PRDLIBL) +
CURLIBL(&CURLIBL) USRLIBL(&USRLIBL)
CHGVAR VAR(&SYS01) VALUE(%SST(&SYSLIBL 1 10))
CHGVAR VAR(&SYS02) VALUE(%SST(&SYSLIBL 12 10))
CHGVAR VAR(&SYS03) VALUE(%SST(&SYSLIBL 23 10))
CHGVAR VAR(&SYS04) VALUE(%SST(&SYSLIBL 34 10))
CHGVAR VAR(&SYS05) VALUE(%SST(&SYSLIBL 45 10))
CHGVAR VAR(&SYS06) VALUE(%SST(&SYSLIBL 56 10))
CHGVAR VAR(&SYS07) VALUE(%SST(&SYSLIBL 67 10))
CHGVAR VAR(&SYS08) VALUE(%SST(&SYSLIBL 78 10))
CHGVAR VAR(&SYS09) VALUE(%SST(&SYSLIBL 89 10))
CHGVAR VAR(&SYS10) VALUE(%SST(&SYSLIBL 100 10))
CHGVAR VAR(&SYS11) VALUE(%SST(&SYSLIBL 111 10))
CHGVAR VAR(&SYS12) VALUE(%SST(&SYSLIBL 122 10))
CHGVAR VAR(&SYS13) VALUE(%SST(&SYSLIBL 133 10))
CHGVAR VAR(&SYS14) VALUE(%SST(&SYSLIBL 144 10))
CHGVAR VAR(&SYS15) VALUE(%SST(&SYSLIBL 155 10))
CHGVAR VAR(&PRD01) VALUE(%SST(&PRDLIBL 1 10))
CHGVAR VAR(&PRD02) VALUE(%SST(&PRDLIBL 11 10))
CHGVAR VAR(&CURLIB) VALUE(%SST(&CURLIBL 1 10))
CHGVAR VAR(&USR01) VALUE(%SST(&USRLIBL 1 10))
CHGVAR VAR(&USR02) VALUE(%SST(&USRLIBL 12 10))
CHGVAR VAR(&USR03) VALUE(%SST(&USRLIBL 23 10))
CHGVAR VAR(&USR04) VALUE(%SST(&USRLIBL 34 10))
CHGVAR VAR(&USR05) VALUE(%SST(&USRLIBL 45 10))
CHGVAR VAR(&USR06) VALUE(%SST(&USRLIBL 56 10))
CHGVAR VAR(&USR07) VALUE(%SST(&USRLIBL 67 10))
CHGVAR VAR(&USR08) VALUE(%SST(&USRLIBL 78 10))
CHGVAR VAR(&USR09) VALUE(%SST(&USRLIBL 89 10))
CHGVAR VAR(&USR10) VALUE(%SST(&USRLIBL 100 10))
CHGVAR VAR(&USR11) VALUE(%SST(&USRLIBL 111 10))
CHGVAR VAR(&USR12) VALUE(%SST(&USRLIBL 122 10))
CHGVAR VAR(&USR13) VALUE(%SST(&USRLIBL 133 10))
CHGVAR VAR(&USR14) VALUE(%SST(&USRLIBL 144 10))
CHGVAR VAR(&USR15) VALUE(%SST(&USRLIBL 155 10))
CHGVAR VAR(&USR16) VALUE(%SST(&USRLIBL 166 10))
CHGVAR VAR(&USR17) VALUE(%SST(&USRLIBL 177 10))
CHGVAR VAR(&USR18) VALUE(%SST(&USRLIBL 188 10))
CHGVAR VAR(&USR19) VALUE(%SST(&USRLIBL 199 10))
CHGVAR VAR(&USR20) VALUE(%SST(&USRLIBL 210 10))
CHGVAR VAR(&USR21) VALUE(%SST(&USRLIBL 221 10))
CHGVAR VAR(&USR22) VALUE(%SST(&USRLIBL 232 10))
CHGVAR VAR(&USR23) VALUE(%SST(&USRLIBL 243 10))
CHGVAR VAR(&USR24) VALUE(%SST(&USRLIBL 254 10))
CHGVAR VAR(&USR25) VALUE(%SST(&USRLIBL 265 10))
/* Present panel */
AGAIN:
SNDRCVF RCDFMT(PANEL)
IF COND(&IN03 *OR &IN12) THEN(GOTO +
CMDLBL(END_EXEC))
/* Highlight library where found */
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS01 &OBJTYPE &SYS01A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS02 &OBJTYPE &SYS02A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS03 &OBJTYPE &SYS03A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS04 &OBJTYPE &SYS04A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS05 &OBJTYPE &SYS05A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS06 &OBJTYPE &SYS06A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS07 &OBJTYPE &SYS07A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS08 &OBJTYPE &SYS08A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS09 &OBJTYPE &SYS09A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS10 &OBJTYPE &SYS10A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS11 &OBJTYPE &SYS11A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS12 &OBJTYPE &SYS12A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS13 &OBJTYPE &SYS13A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS14 &OBJTYPE &SYS14A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &SYS15 &OBJTYPE &SYS15A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &PRD01 &OBJTYPE &PRD01A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &PRD02 &OBJTYPE &PRD02A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &CURLIB &OBJTYPE &CURLIBA)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR01 &OBJTYPE &USR01A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR02 &OBJTYPE &USR02A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR03 &OBJTYPE &USR03A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR04 &OBJTYPE &USR04A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR05 &OBJTYPE &USR05A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR06 &OBJTYPE &USR06A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR07 &OBJTYPE &USR07A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR08 &OBJTYPE &USR08A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR09 &OBJTYPE &USR09A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR10 &OBJTYPE &USR10A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR11 &OBJTYPE &USR11A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR12 &OBJTYPE &USR12A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR13 &OBJTYPE &USR13A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR14 &OBJTYPE &USR14A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR15 &OBJTYPE &USR15A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR16 &OBJTYPE &USR16A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR17 &OBJTYPE &USR17A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR18 &OBJTYPE &USR18A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR19 &OBJTYPE &USR19A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR20 &OBJTYPE &USR20A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR21 &OBJTYPE &USR21A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR22 &OBJTYPE &USR22A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR23 &OBJTYPE &USR23A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR24 &OBJTYPE &USR24A)
CALLPRC PRC(OBJ023CL) PARM(&OBJ &USR25 &OBJTYPE &USR25A)
GOTO CMDLBL(AGAIN)
END_EXEC:
RETURN
ERROR:
FWDPGMMSG
MONMSG MSGID(CPF0000)
ENDPGM PGM PARM(&OBJ &OBJLIB &OBJTYPE &ATTR)
DCL VAR(&ATTR) TYPE(*CHAR) LEN(1)
DCL VAR(&OBJ) TYPE(*CHAR) LEN(10)
DCL VAR(&OBJLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&OBJTYPE) TYPE(*CHAR) LEN(7)
IF COND(&OBJLIB *EQ ' ') THEN(DO)
CHGVAR VAR(&ATTR) VALUE(X'20')
ENDDO
ELSE CMD(DO)
CHGVAR VAR(&ATTR) VALUE(X'21')
CHKOBJ OBJ(&OBJLIB/&OBJ) OBJTYPE(&OBJTYPE)
MONMSG MSGID(CPF0000) EXEC(DO)
CHGVAR VAR(&ATTR) VALUE(X'20')
ENDDO
ENDDO
ENDPGM A DSPSIZ(24 80 *DS3)
A CA03(03 'Exit')
A CA12(12 'Cancel')
A PRINT
*======================================================================
*
* Define data types.
A R PANEL
A BYTE 1A H
A NAME 10A H
*
* Define display attribute fields.
A CURLIBA R P REFFLD(BYTE *SRC)
A PRD01A R P REFFLD(BYTE *SRC)
A PRD02A R P REFFLD(BYTE *SRC)
A SYS01A R P REFFLD(BYTE *SRC)
A SYS02A R P REFFLD(BYTE *SRC)
A SYS03A R P REFFLD(BYTE *SRC)
A SYS04A R P REFFLD(BYTE *SRC)
A SYS05A R P REFFLD(BYTE *SRC)
A SYS06A R P REFFLD(BYTE *SRC)
Figure 4: CL Program OBJ022CL
Figure 5: CL Program OBJ023CL
A SYS07A R P REFFLD(BYTE *SRC)
A SYS08A R P REFFLD(BYTE *SRC)
A SYS09A R P REFFLD(BYTE *SRC)
A SYS10A R P REFFLD(BYTE *SRC)
A SYS11A R P REFFLD(BYTE *SRC)
A SYS12A R P REFFLD(BYTE *SRC)
A SYS13A R P REFFLD(BYTE *SRC)
A SYS14A R P REFFLD(BYTE *SRC)
A SYS15A R P REFFLD(BYTE *SRC)
A USR01A R P REFFLD(BYTE *SRC)
A USR02A R P REFFLD(BYTE *SRC)
A USR03A R P REFFLD(BYTE *SRC)
A USR04A R P REFFLD(BYTE *SRC)
A USR05A R P REFFLD(BYTE *SRC)
A USR06A R P REFFLD(BYTE *SRC)
A USR07A R P REFFLD(BYTE *SRC)
A USR08A R P REFFLD(BYTE *SRC)
A USR09A R P REFFLD(BYTE *SRC)
A USR10A R P REFFLD(BYTE *SRC)
A USR11A R P REFFLD(BYTE *SRC)
A USR12A R P REFFLD(BYTE *SRC)
A USR13A R P REFFLD(BYTE *SRC)
A USR14A R P REFFLD(BYTE *SRC)
A USR15A R P REFFLD(BYTE *SRC)
A USR16A R P REFFLD(BYTE *SRC)
A USR17A R P REFFLD(BYTE *SRC)
A USR18A R P REFFLD(BYTE *SRC)
A USR19A R P REFFLD(BYTE *SRC)
A USR20A R P REFFLD(BYTE *SRC)
A USR21A R P REFFLD(BYTE *SRC)
A USR22A R P REFFLD(BYTE *SRC)
A USR23A R P REFFLD(BYTE *SRC)
A USR24A R P REFFLD(BYTE *SRC)
A USR25A R P REFFLD(BYTE *SRC) *
* Define panel fields.
A 1 31'Find Object in *LIBL'
A DSPATR(HI)
A 3 2'The library list is as follows:'
A COLOR(BLU)
A 4 2'System:'
A SYS01 R O 4 12REFFLD(NAME *SRC) DSPATR(&SYS01A)
A SYS02 R O 4 23REFFLD(NAME *SRC) DSPATR(&SYS02A)
A SYS03 R O 4 34REFFLD(NAME *SRC) DSPATR(&SYS03A)
A SYS04 R O 4 45REFFLD(NAME *SRC) DSPATR(&SYS04A)
A SYS05 R O 4 56REFFLD(NAME *SRC) DSPATR(&SYS05A)
A SYS06 R O 5 12REFFLD(NAME *SRC) DSPATR(&SYS06A)
A SYS07 R O 5 23REFFLD(NAME *SRC) DSPATR(&SYS07A)
A SYS08 R O 5 34REFFLD(NAME *SRC) DSPATR(&SYS08A)
A SYS09 R O 5 45REFFLD(NAME *SRC) DSPATR(&SYS09A)
A SYS10 R O 5 56REFFLD(NAME *SRC) DSPATR(&SYS10A)
A SYS11 R O 6 12REFFLD(NAME *SRC) DSPATR(&SYS11A)
A SYS12 R O 6 23REFFLD(NAME *SRC) DSPATR(&SYS12A)
A SYS13 R O 6 34REFFLD(NAME *SRC) DSPATR(&SYS13A)
A SYS14 R O 6 45REFFLD(NAME *SRC) DSPATR(&SYS14A)
A SYS15 R O 6 56REFFLD(NAME *SRC) DSPATR(&SYS15A)
A 8 2'Product:'
A PRD01 R O 8 12REFFLD(NAME *SRC) DSPATR(&PRD01A)
A PRD02 R O 8 23REFFLD(NAME *SRC) DSPATR(&PRD02A)
A 10 2'Current:'
A CURLIB R O 10 12REFFLD(NAME *SRC) DSPATR(&CURLIBA)
A 12 2'User:'
A USR01 R O 12 12REFFLD(NAME *SRC) DSPATR(&USR01A)
A USR02 R O 12 23REFFLD(NAME *SRC) DSPATR(&USR02A)
A USR03 R O 12 34REFFLD(NAME *SRC) DSPATR(&USR03A)
A USR04 R O 12 45REFFLD(NAME *SRC) DSPATR(&USR04A)
A USR05 R O 12 56REFFLD(NAME *SRC) DSPATR(&USR05A)
A USR06 R O 13 12REFFLD(NAME *SRC) DSPATR(&USR06A)
A USR07 R O 13 23REFFLD(NAME *SRC) DSPATR(&USR07A)
A USR08 R O 13 34REFFLD(NAME *SRC) DSPATR(&USR08A)
A USR09 R O 13 45REFFLD(NAME *SRC) DSPATR(&USR09A)
A USR10 R O 13 56REFFLD(NAME *SRC) DSPATR(&USR10A)
A USR11 R O 14 12REFFLD(NAME *SRC) DSPATR(&USR11A)
A USR12 R O 14 23REFFLD(NAME *SRC) DSPATR(&USR12A)
A USR13 R O 14 34REFFLD(NAME *SRC) DSPATR(&USR13A)
A USR14 R O 14 45REFFLD(NAME *SRC) DSPATR(&USR14A)
A USR15 R O 14 56REFFLD(NAME *SRC) DSPATR(&USR15A)
A USR16 R O 15 12REFFLD(NAME *SRC) DSPATR(&USR16A)
A USR17 R O 15 23REFFLD(NAME *SRC) DSPATR(&USR17A)
A USR18 R O 15 34REFFLD(NAME *SRC) DSPATR(&USR18A)
A USR19 R O 15 45REFFLD(NAME *SRC) DSPATR(&USR19A)
A USR20 R O 15 56REFFLD(NAME *SRC) DSPATR(&USR20A)
A USR21 R O 16 12REFFLD(NAME *SRC) DSPATR(&USR21A)
A USR22 R O 16 23REFFLD(NAME *SRC) DSPATR(&USR22A)
A USR23 R O 16 34REFFLD(NAME *SRC) DSPATR(&USR23A)
A USR24 R O 16 45REFFLD(NAME *SRC) DSPATR(&USR24A)
A USR25 R O 16 56REFFLD(NAME *SRC) DSPATR(&USR25A)
A 17 2'AA '
A DSPATR(UL) COLOR(BLU)
A 19 2'Enter options, press Enter.'
A COLOR(BLU)
A 21 2'Object:'
A OBJ R B 21 12REFFLD(NAME *SRC) DSPATR(HI)
A 22 2'Type:'
A OBJTYPE 7A B 22 12DSPATR(HI)
A 24 2'F3=Exit F12=Cancel'
A COLOR(BLU)
Figure 6: Display File OBJ022DF
Retrieving the Library List
As the main article explains, none of the three classical methods of retrieving the library list works well enough. There is another method, however, which involves the use of an API named QUSRJOBI. This API provides job-related information in a variable (not a user space), but it is a bit difficult to use, as most APIs are. Thats what prompted me to make up a user command as a front-end to the API. The result was RTVLIBL (see Figure A1).
Its parameters are as follows:
JOB: This parameter identifies the job whose library list is to be retrieved. The job name can be fully qualified. It defaults to *, which retrieves the library list of the current job.
SYSLIBL: This parameter returns the system portion of the library list. The program that uses RTVLIBL must use a 165-byte character variable to receive this information.
PRDLIBL: This parameter moves the names of the product libraries into a 22-byte character variable.
CURLIBL: This parameter moves the names of the current library into an 11-byte character variable.
USRLIBL: This parameter moves the names of the user portion of the library list into a 275-byte character variable.
These parameters are not required. If JOB is not specified, you get the library list of the current job. If you dont use a variable for some of the four return variable parameters, you wont get that information. For example, you can use RTVLIBL with only the SYSLIBL parameter if youre interested only in the system portion of the library list.
All four return variable parameters return the library names in a continuous stream, at 11-byte intervals: a 10-byte library name, and a one-byte display attribute. This means that the first library name begins on byte 1, the second library name begins on byte 12 (1 + 11), the third on byte 23 (12 + 11), and so on.
How It Works
The commands processing program, LIBL006CL (Figure A2) calls API QUSRJOBI. This API is rather complicated, however, and I wont explain it all. Instead, you may want to look up its description in the System API Reference: OS/400 Work Management APIs referenced at the end of the article. Still, I have used some important coding techniques, which Id like to show you.
To begin with, QUSRJOBI can use a number of different data formats depending on the kind of information you want to retrieve. For my purposes, I used format JOBI0700, which includes the library list and other information items. This format, however, doesnt have a
fixed size. Its size depends on the number of library names contained in each of the four portions of the library list being retrieved. Since CL doesnt support variable-length variables, I placed myself in the worst-case scenario and decided to assume that the library list would have all 43 library names. That turns out to be 473 bytes for the library list, so I rounded it up to 500 before calling the API.
The API error code parameter (the last parameter of this API) returns a message ID and message data if the API ended in error. That may happen, for example, if the job specified does not exist. Therefore, program LIBL006CL finds out if the API returned any data in the error code parameter by examining bytes 5 to 8 of the error code. If they contain anything but hexadecimal zeros, there was an error. In that case, I merely forward the error as an escape message, extracting the message ID from bytes 9 to 15 and the message data from bytes 17 to 96.
If no error was found, I determine how many library names are in each portion, extracting binary values from the receiving variable (&RCVVAR). To retrieve the system portion of the library list, I initialize the offset to 81 and the length to 11 times the number of libraries in the system portion before extracting the library names with a substring (%SST) function. This operation may yield escape message CPF3601 if the user did not use the SYSLIBL parameter of the RTVLIBL command, so I monitor for it in order to ignore it.
The rest of the library list portions are retrieved the same way. Now that I have the offset of the system portion in &OFFSET and its length in &LENGTH, I can calculate the offset of the next portion (product) by adding both, and I can calculate the new length by multiplication. And so on.
One obvious advantage of RTVLIBL (and, implicitly, of QUSRJOBI) is that you can retrieve the library list of any job on the system.
/*===================================================================*/
/* To compile: */
/* */
/* CRTCMD CMD(XXX/RTVLIBL) PGM(XXX/LIBL006CL) + */
/* SRCFILE(XXX/QCMDSRC) TEXT(Retrieve + */
/* Library List) ALLOW(*IPGM *IMOD + */
/* *BPGM *BMOD) */
/* */
/*===================================================================*/
CMD PROMPT(Retrieve Library List)
PARM KWD(JOB) TYPE(Q1) DFT(*) SNGVAL((*)) +
PROMPT(Job name)
Q1: QUAL TYPE(*NAME) LEN(10) EXPR(*YES)
QUAL TYPE(*NAME) LEN(10) EXPR(*YES) PROMPT(User +
name)
QUAL TYPE(*CHAR) LEN(6) RANGE(000000 999999) +
EXPR(*YES) PROMPT(Job number)
PARM KWD(SYSLIBL) TYPE(*CHAR) LEN(165) +
RTNVAL(*YES) PROMPT(System portion (165A))
PARM KWD(PRDLIBL) TYPE(*CHAR) LEN(22) +
RTNVAL(*YES) PROMPT(Product libraries +
(22A))
PARM KWD(CURLIBL) TYPE(*CHAR) LEN(11) +
RTNVAL(*YES) PROMPT(Current library (11A))
PARM KWD(USRLIBL) TYPE(*CHAR) LEN(275) +
RTNVAL(*YES) PROMPT(User portion (275A)) /*===================================================================*/
/* To compile: */
/* */
/* CRTCLPGM PGM(XXX/LIBL006CL) SRCFILE(XXX/QCLSRC) + */
/* TEXT(CPP for RTVLIBL command) */
Figure A1: Command RTVLIBL
/* */
/* Prerequisite: */
/* FWDPGMMSG command, published in the January 1998 issue. */
/* */
/*===================================================================*/
PGM PARM(&QJOBNAM &SYSLIBL &PRDLIBL &CURLIBL +
&USRLIBL)
DCL VAR(&APIERR) TYPE(*CHAR) LEN(96) VALUE(X00000060)
DCL VAR(&CURLIBL) TYPE(*CHAR) LEN(11)
DCL VAR(&DTAFMT) TYPE(*CHAR) LEN(8) VALUE(JOBI0700)
DCL VAR(&INTJOBID) TYPE(*CHAR) LEN(16) VALUE( )
DCL VAR(&LENGTH) TYPE(*DEC) LEN(9)
DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(256)
DCL VAR(&MSGF) TYPE(*CHAR) LEN(10)
DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&MSGID) TYPE(*CHAR) LEN(7)
DCL VAR(&NBRCURLIB) TYPE(*DEC) LEN(9)
DCL VAR(&NBRPRDLIB) TYPE(*DEC) LEN(9)
DCL VAR(&NBRSYSLIB) TYPE(*DEC) LEN(9)
DCL VAR(&NBRUSRLIB) TYPE(*DEC) LEN(9)
DCL VAR(&OFFSET) TYPE(*DEC) LEN(9)
DCL VAR(&PRDLIBL) TYPE(*CHAR) LEN(22)
DCL VAR(&QJOBNAM) TYPE(*CHAR) LEN(26)
DCL VAR(&RCVVAR) TYPE(*CHAR) LEN(500)
DCL VAR(&RCVVARLEN) TYPE(*CHAR) LEN(4)
DCL VAR(&SYSLIBL) TYPE(*CHAR) LEN(165)
DCL VAR(&USRLIBL) TYPE(*CHAR) LEN(275)
MONMSG MSGID(CPF0000 MCH0000) EXEC(GOTO CMDLBL(ERROR))
/* Retrieve library list */
CHGVAR VAR(%BIN(&RCVVARLEN)) VALUE(500)
CALL PGM(QUSRJOBI) PARM(&RCVVAR &RCVVARLEN +
&DTAFMT &QJOBNAM &INTJOBID &APIERR)
/* If API ends in error, forward to caller */
IF COND(%BIN(&APIERR 5 4) *GT 0) THEN(DO)
SNDPGMMSG MSGID(%SST(&APIERR 9 7)) MSGF(QCPFMSG) +
MSGDTA(%SST(&APIERR 17 80)) MSGTYPE(*ESCAPE)
ENDDO
CHGVAR VAR(&NBRSYSLIB) VALUE(%BIN(&RCVVAR 65 4))
CHGVAR VAR(&NBRPRDLIB) VALUE(%BIN(&RCVVAR 69 4))
CHGVAR VAR(&NBRCURLIB) VALUE(%BIN(&RCVVAR 73 4))
CHGVAR VAR(&NBRUSRLIB) VALUE(%BIN(&RCVVAR 77 4))
/* Extract system portion of library list */
CHGVAR VAR(&OFFSET) VALUE(81)
CHGVAR VAR(&LENGTH) VALUE(&NBRSYSLIB * 11)
IF COND(&LENGTH *GT 0) THEN(DO)
CHGVAR VAR(&SYSLIBL) VALUE(%SST(&RCVVAR &OFFSET &LENGTH))
MONMSG MSGID(CPF3601)
ENDDO
/* Extract product libraries */
CHGVAR VAR(&OFFSET) VALUE(&OFFSET + &LENGTH)
CHGVAR VAR(&LENGTH) VALUE(&NBRPRDLIB * 11)
IF COND(&LENGTH *GT 0) THEN(DO)
CHGVAR VAR(&PRDLIBL) VALUE(%SST(&RCVVAR &OFFSET &LENGTH))
MONMSG MSGID(CPF3601)
ENDDO
/* Extract current library */
CHGVAR VAR(&OFFSET) VALUE(&OFFSET + &LENGTH)
CHGVAR VAR(&LENGTH) VALUE(&NBRCURLIB * 11)
IF COND(&LENGTH *GT 0) THEN(DO)
CHGVAR VAR(&CURLIBL) VALUE(%SST(&RCVVAR &OFFSET &LENGTH))
MONMSG MSGID(CPF3601)
ENDDO
/* Extract user portion of library list */
CHGVAR VAR(&OFFSET) VALUE(&OFFSET + &LENGTH)
CHGVAR VAR(&LENGTH) VALUE(&NBRUSRLIB * 11)
IF COND(&LENGTH *GT 0) THEN(DO)
CHGVAR VAR(&USRLIBL) VALUE(%SST(&RCVVAR &OFFSET &LENGTH))
MONMSG MSGID(CPF3601)
ENDDO
RETURN
ERROR:
FWDPGMMSG
MONMSG MSGID(CPF0000)
ENDPGM
LATEST COMMENTS
MC Press Online