Two of my favorite commands in CL programs are Check Object (CHKOBJ) and Retrieve Object Description (RTVOBJD). You can do a lot with these two commands.
Even some experienced CL programmers may not fully understand these commands, so Ill explain them. Ill also include some of the reasons I like and dislike CHKOBJ and some of the problems programmers have with it.
The CHKOBJ command allows you to check the existence of an object, a member, or the users authority to an object. (Note that you must specify an object type on CHKOBJ.) For example, suppose you key in this command:
CHKOBJ OBJ(PGMA) OBJTYPE(*PGM)
If PGMA exists on the library list, the command just does a return. When the check is successful, the command completes normally and does not send any form of message. The way you find out that something went wrong is to monitor for possible escape messages, such as this one:
CHKOBJ OBJ(PGMA) OBJTYPE(*PGM)
MONMSG MSGID(CPF9801) EXEC(DO) /* Not found */
/* Your code for not found */
ENDDO /* Not found */
There are several conditions you can monitor with CHKOBJ. The following are the most typical:
CPF9801The object is not found. The message is really saying that the combination of name and object type have not been found.
CPF9802Not authorized. This message occurs only if you have used the AUT parameter, such as in the following example:
CHKOBJ OBJ(PGMA) OBJTYPE(*PGM) AUT(*USE)
CHKOBJ
If you do not have *USE authority, the escape message occurs. Note that if you do not use the AUT parameter, you are ensuring only that the object exists. You can use CHKOBJ on an object that you have no authorization to; however, you must be authorized to the library containing the object you are trying to check. (See the authorization error described for the CPF9820 message.)
The AUT parameter supports the simple values of *USE, *CHANGE, and *ALL. If you ask for *USE authority and actually have a greater authority to the object (such as *CHANGE), CHKOBJ completes normally. The individual authorities that make up the check you are asking for (such as *USE = *OBJOPR, *READ, and *EXECUTE) are checked rather than the word *USE.
You can also check for very specific combinations such as this one:
... AUT(*OBJOPR *READ *ADD)
CPF9810The library is not found. This message occurs if you used a qualified name and the library did not exist. Note the distinction between checking for a library object and checking for a qualified name. If you key in CHKOBJ OBJ(LIBA/OBJ1) OBJTYPE(*xxx) and LIBA does not exist, CPF9810 is sent. If LIBA exists, but not OBJ1, CPF9801 is sent. You can check whether a library exists by using code like this:
CHKOBJ OBJ(LIBA) OBJTYPE(*LIB)
In this case, CPF9801 occurs if the library is not found. It is when you use a qualified name for the object and the library is not found that CPF9810 occurs. Another error situation occurs when the library exists, but you are not authorized to it. See the CPF9820 message.
CPF9815The member does not exist. This occurs only if you specified the MBR parameter:
CHKOBJ OBJ(FILEA) OBJTYPE(*FILE) MBR(MBR1)
The escape message is telling you that the file exists, but the member does not. If the file does not exist, you get CPF9801, not CPF9815. You could specify the following instead:
CHKOBJ OBJ(FILEA) OBJTYPE(*FILE) MBR(*FIRST)
In this case, you are checking to see if there are any members in the file. If youve removed the first member but other members still exist, the command completes normally because there is still a first member. If you use an unqualified object name, the first file that the system comes to on the library list is the only one checked to see if the member exists. For example, if you have two QCLSRC files on the library list, and the member you are checking for is in the second file on the library list, you will get the CPF9815 escape message. If you use a qualified object name, it does not matter if the object is on the library list. Only the specific object is checked for the member.
CPF9820You are not authorized to the library. This message occurs if you specify a qualified library name that exists but you are not authorized to the library. Note that CPF9820 will occur even if you have not specified the AUT parameter.
There are some other CPF98xx conditions on CHKOBJ that I never monitor for. I suspect there are also some unusual MCHxxxx conditions that may be bubbled up, but I wouldnt monitor for them either.
If you specify an invalid command (such as describing a nonexistent object type), you will get the general CPF0001 escape message (you did not get by the command definition checking). A diagnostic message is sent prior to the CPF0001 escape to describe the specific error.
What I Like About CHKOBJ
The message you monitor for after CHKOBJ is nonambiguous. Many of the system commands have messages that describe multiple error conditions. These are reasonable when you are reading the message text, but when you are writing a program to handle specific error conditions, you want nonambiguous escape messages.
When Im coding, I find it simpler to check first for expected error conditions with CHKOBJ rather than try to monitor and understand the error conditions on some failed command. In addition, Ive memorized the important escape messages on CHKOBJ so that I dont have to look for what to monitor for.
What I Dont Like About CHKOBJ
The CPF9801 message says something like this:
Object xxx in library yyy not found.
You do not see the requested object type in the first-level text of the message. The object type specified is in the second-level text of the message, but Id prefer to see it in the first level.
A solution is the CHKOBJ3 command in the TAA Productivity Tools. It uses unique text for most object types. For example, if a *FILE object type is missing, the text reads File xxx in yyy not found.
Another solution is to change the text of message description CPF9801, inserting type *&5 right before not found. This way, CPF9801 reports something like Object xxx in library yyy type *zzz not found, which is much better. If you would like to make
this change on your system, run the Work with Message Descriptions (WRKMSGD) command, specifying a beginning of CPF9801. Then enter option 2 next to it, press Enter, and insert type *&5 in the place I have indicated. Press Enter again, and CPF9801 is changed foreveror at least until you upgrade the operating system to a new version or release.
Another thing I dont like about CHKOBJ is that normally you have to use a GOTO command to get around the case in which it is an error if the object does exist. For example:
CHKOBJ OBJ(FILEA) OBJTYPE(*FILE)
MONMSG MSGID(CPF9801) EXEC(DO) /* Not found */
GOTO GOODOBJ
/* Your bad object handling */
ENDDO /* Not found */
GOODOBJ: /* Your good object handling */
The problem with additional GOTO commands is that you can make a bad logic error by placing some commands between the ENDDO and the GOODOBJ label. The simple DO defined on the Monitor Message (MONMSG) command is a lot safer to use.
To handle the reverse logic situation, I use the CHKOBJ2 command in the TAA Productivity Tools.
CHKOBJ2 OBJ(FILEA) OBJTYPE(*FILE)
MONMSG MSGID(TAA9891) EXEC(DO) /* Found */
/* Your bad object handling */
ENDDO /* Found */
The CHKOBJ2 command just reverses the polarity of the command and sends you an escape message (TAA9891) if the object does exist.
An alternative solution is to use an &EXISTS variable, such as follows:
DCL &exists *LGL 1
CHGVAR &exists 1
CHKOBJ &lib/&obj &objtype
MONMSG cpf9801 EXEC(CHGVAR &exists 0)
Another thing that users typically want to know about objects is whether they are in use. CHKOBJ doesnt check for this. You need the Allocate Object (ALCOBJ) command, which isnt as clean-cut as CHKOBJ. ALCOBJ has a lot of restrictions within the command itself (for instance, you cannot allocate a printer or display file). The system also prevents meaningful function that could be achieved with a command like ALCOBJ, because it does not lock a program when it is called.
Some tools in QUSRTOOL and the TAA Productivity Tools can help, but they are not perfect because of the system limitations. You could look at the tools Check Active Program (CHKACTPGM), Check Active Object (CHKACTOBJ), and Check Active User (CHKACTUSR).
And the last thing about CHKOBJ I dont like is that it supports only a specific qualified library name, *LIBL, or *CURLIB. Thus, you cant ask whether PGMA exists anywhere in the system (but you can with DSPOBJD).
RTVOBJD Command
The RTVOBJD command provides all kind of information about the object. You can retrieve the create date, change date, last use date, size, owner, attribute, source member used to create the object (if any), etc.
When you prompt for the command, the numbers in the parentheses of the return values describe how to declare the variable to be used to hold the result. Figure 1 shows a portion of the RTVOBJD command prompt.
To return the owner name, you need to declare a variable of type *CHAR, with a length of 10. To return the auxiliary storage pool (ASP) of an object, you need to declare a variable of type *DEC, which has a length of (2 0).
To return both the owner and ASP, you would use code like this:
DCL &OWNER *CHAR LEN(10)
DCL &ASP *DEC LEN(2 0)
RTVOBJD OBJ(FILEA) OBJTYPE(*FILE) OWNER(&OWNER) ASP(&ASP)
If you return a date value, the dates come back as 13-byte character variables in the form of CYYMMDDHHMMSS. You have to substring out the date if you want just that piece of it. Note that the outfile used by the Display Object Description (DSPOBJD) command, QADSPOBJ, uses an MMDDYY format for some of the same dates (regardless of your job or system date format) and a separate field for time. The RTVOBJD SIZE parameter allows for a 15-digit number. This also differs from the DSPOBJD outfile file, which uses a 10-digit number (ODOBSZ) for size and then has an additional field (ODPUN) for bytes per unit to allow for larger sizes.
I use RTVOBJD frequently to determine which library an object exists in. For example, if the user specifies a library qualifier of *LIBL or *CURLIB, you can access the library by using the RTNLIB parameter on RTVOBJD. I have a lot of code that looks like this:
IF (%SST(&LIB 1 1) *EQ *) DO /* Get lib */
RTVOBJD OBJ(&LIB/&FILE) OBJTYPE(*FILE) RTNLIB(&LIB)
ENDDO /* Get lib */
The RTVOBJD command is used if the first position of the library name is an asterisk (*), indicating a special value. After these instructions, my code just uses the &LIB variable as the specific library name (either because the user entered it or because RTVOBJD found it).
One of the parameters that appears on RTVOBJD is USRDFNATR. This field (10 bytes) is left to your own imagination as to what you want to do with it. I am unaware of any CRT commands that allow you to set the attribute when you create an object. However, you can change the value with the QLICOBJD API. I front-ended the API with the CHGOBJD2 command in QUSRTOOL or the TAA Productivity Tools. To set the attribute, you just use this code:
CHGOBJD2 OBJ(xxx) OBJTYPE(*xxx) USRDFNATR(...)
To retrieve the attribute, you use this code:
DCL &USRDFNATR *CHAR LEN(10)
RTVOBJD OBJ(xxx) OBJTYPE(*xxx) USRDFNATR(&USRDFNATR)
Although CHKOBJ allows you to determine whether an object exists even if you are not authorized to it, you cannot use RTVOBJD unless you have some authorization. If you have any authorization, you can access the description, but a more typical set of code would look like this:
CHKOBJ OBJ(xxx) OBJTYPE(*xxx) AUT(*USE)
MONMSG MSGID(CPF9802) EXEC(DO) /* Not auth */
/* Your code for not authorized */
ENDDO /* Not auth */
RTVOBJD OBJ(xxx) OBJTYPE(*xxx) ...
RTVOBJD uses the same basic CPF98xx messages sent by CHKOBJ as well as some unique message IDs. So the alternative solution is to monitor for the CPF9802 message that will be sent by RTVOBJD:
RTVOBJD OBJ(xxx) OBJTYPE(*xxx) ...
MONMSG MSGID(CPF9802) EXEC(DO) /* Not auth */
/* Your code for not authorized */
ENDDO /* Not auth */
You can use the Display Library (DSPLIB) command to determine which objects you are not authorized to. The object name and type are listed, but the text description says *NOT AUTHORIZED. Neither DSPOBJD nor Work with Objects (WRKOBJ) lists objects you are not authorized to. QADSPOBJ, the outfile for DSPOBJD, will not show you the object, either.
Because RTVOBJD returns parameters, you can execute the command only in a CL program. If you are writing an HLL program like RPG and want object information, you can use the QUSROBJD API. Or you can use the RTVOBJD2 in the TAA
Productivity Tools. Your program would call the supplied program and receive back an externally described data structure with most of the typical object information.
Specific RTVxxx Commands
You can get a lot of general-purpose information about an object using RTVOBJD. However, the system offers other object information that is specific to the object type, such as a program or database file.
To get to this level of information, you can use either an API or one of the many RTVxxx commands in QUSRTOOL or the TAA Productivity Tools. For example, there are commands such as Retrieve Program Attribute (RTVPGMA), Retrieve Database File Attribute (RTVDBFA), Retrieve Job Description (RTVJOBD), and Retrieve Command Attribute (RTVCMDA).
Information Is the Object
When you are trying to control an application, CHKOBJ and RTVOBJD provide a simple means of checking and retrieving object information. If you are familiar with these commands, you can make a lot of good things happen.
Retrieve Object Description (RTVOBJD)
Type choices, press Enter.
Object . . . . . . . . . . . . . __________ Name
Library . . . . . . . . . . . *LIBL_____ Name, *LIBL, *CURLIB
Object type . . . . . . . . . . __________ *ALRTBL, *AUTL, *BNDDIR...
CL var for RTNLIB (10) . . __________ _ Character value
CL var for OBJATR (10) . . __________ _ Character value
CL var for USRDFNATR (10) . . __________ _ Character value
CL var for TEXT (50) . . ___________ Character value
CL var for OWNER (10) . . ___________ Character value
CL var for PGP (10) . . ___________ Character value
CL var for ASP (2 0) . . ___________ Number
CL var for OVFASP (1) . . ___________ Character value
CL var for CRTDATE (13) . . ___________ Character value
CL var for CHGDATE (13) . . ___________ Character value
CL var for SAVDATE (13) . . ___________ Character value
CL var for SAVACTDATE (13) . . ___________ Character value
CL var for RSTDATE (13) . . ___________ Character value
More...
F3=Exit F4=Prompt F5=Refresh F12=Cancel F13=How to use this display
F24=More keys
Figure 1: Part of the RTVOBJD command
LATEST COMMENTS
MC Press Online