This code might be a little choppy because I had to do a lot to trim it down and convert it for more of a demo kind of purpose. The SHOLIBSIZ command can be used to call the SHOLIBSIZ program, or the program can be called directly.
The program calls the Retrieve Library Description (QLIRLIBD) API requesting two elements to be returned. The two keys are key 6 for the Library size information structure and key 7 for the Number of objects in library.
The elements are returned in a structure of variable-length "records". The program steps through the structure using an offset to to extract substrings. The substrings are determined by looking at which key is identified in the part of the structure being examined.
After the values are extracted, the size of the *LIB object itself is retrieved by running RTVOBJD. That value is formatted along with all the others into a message that is sent back out to *PRV -- previous call level. That's different from sending to *EXT as can be seen by running the command from the command line of the MAIN system menu, from the QCMD display or from a PDM command line. PDM knows to resend the message to *EXT; but QCMD will ignore it as will a basic system menu.
Also note that the final message is sent as *NOTIFY. That can be important if you have the program run inside of another CLP, whether by running the command or calling the program, and you use MONMSG for MsgID CPF9897.
You can modify the code to send the info out any way you wish. Run it from QCMD and have the detailed messages shown or just run it from PDM; you should see the message easily enough.
Finally note that the CL is from a source file that has 112-byte records. Some lines will probably be truncated if you put it into an older 92-byte QCLSRC file.
The SHOLIBSIZE *CMD:
/* CRTCMD CMD( MYLIB/SHOLIBSIZ ) + PGM( MYLIB/SHOLIBSIZ ) + SRCFILE( mylib/QCMDSRC ) + SRCMBR( SHOLIBSIZ ) + REPLACE( *NO ) + */ SHOLIBSIZ: CMD PROMPT('Show Library Size') PARM KWD(LIBNAM) TYPE(*NAME) LEN(10) MIN(1) + PROMPT('Library name')
The command is simple. Create it wherever you want it and point it at the program. That's all there is for that piece.
The SHOLIBSIZ *PGM:
/*---------------------------------------------------------------------------*/ /* SHOLIBSIZ: Retrieves library size and displays it in a message... */ /*---------------------------------------------------------------------------*/ pgm ( + &Lib + ) dcl &Lib *char 10 /* QLIRLIBD returns variable records into this field. We'll process the */ /* two records returned to extract the data we need... */ dcl &LibDta *char 256 /* Each variable record is extracted in turn and various descriptive data */ /* is set up... */ dcl &VarRcd *char 64 dcl &VarRcdRtn *int /* Number of variable records returned */ dcl &VarRcdLen *int /* Length of the current VARRCD... */ dcl &offsVarRcd *int /* Offset into the current VARRCD... */ dcl &KeyID *int /* Key ID of the current VARRCD... */ dcl &SizFld *int /* Size of current VARRCD data field... */ /* Loop counter... */ dcl &CNT *int /* *dec and binary representations of the *LIB object size and the reported */ /* "library size" from QLIRLIBD... */ dcl &LO_Size *dec ( 15 0 ) /* Size of the LIB object itself... */ dcl &LibObjSiz *char 4 /* Size of the LIB object itself... */ dcl &Size *char 4 /* Size of all objects... */ dcl &OB_Mult *char 4 /* Multiplier of the object sizes... */ dcl &InfStat *char 1 /* Information status... */ /* Binary representations of number of objects in the library... */ dcl &ObjNbr *char 4 /* Used for formatting final message... */ dcl &msgdta *char 26 /* Message data to format... */ dcl &msg *char 100 /* Final message text... */ /* Verify that the requested library exists... */ chkobj QSYS/&Lib objtype( *LIB ) monmsg ( CPF9801 ) exec( do ) sndpgmmsg msgid( CPF9898) msgf( QCPFMSG ) + msgdta( 'Library' *BCAT &Lib *BCAT 'not found' ) + msgtype( *ESCAPE ) return enddo /* Create a *MSGF and MsgD. This is temporary and used because it's trivial */ /* to format variable values this way (much easier than writing my own code) */ crtmsgf QTEMP/#SLS monmsg ( cpf2112 ) addmsgd SLS0001 msgf( QTEMP/#SLS ) + msg( + 'Library &1 size is &2 * &3. (*LIB size: &4 + Count: &5).' + ) + fmt( (*CHAR 10) (*UBIN 4) (*UBIN 4) (*UBIN 4) (*UBIN 4) ) /* Retrieve the size and object count via Retrieve Library Description */ /* (QLIRLIBD) API. The API is asked to return two description records. */ /* The first is for key ID 6, library size information, and the second is */ /* for key ID 7, number of objects in the library... */ call QLIRLIBD ( + &libdta + x'00000100' + &lib + X'000000020000000600000007' + x'0000000000000000' + ) /* Because the returned structure contains two variable records, we must */ /* parse the structure according to the API documentation. This code sets */ /* two fields needed for the parsing: the number of variable records */ /* actually returned is a *bin(4) value beginning at position 9 of the */ /* returned structure. Although this should always = 2 for the call here, */ /* we extract it anyway. We might have future uses and need to change */ /* the code in this program. The offset to the first variable length */ /* record will always be 16 (i.e., position 17)... */ chgvar &VarRcdRtn %bin( &LibDta 9 4 ) chgvar &offsVarRcd ( 17 ) /* Loop through the structure and extract the variable records. Handle each */ /* record according to the key ID... */ dofor &CNT from( 1 ) to( &VarRcdRtn ) chgvar &VarRcdLen %bin( &LibDta &offsVarRcd 4 ) /* Extract a variable record according to the length returned... */ chgvar &VarRcd %sst( &LibDta &offsVarRcd &VarRcdLen ) /* Extract key ID and data length from this variable record... */ chgvar &KeyID %bin( &VarRcd 5 4 ) chgvar &SizFld %bin( &VarRcd 9 4 ) /* Bump our offset to the next variable record. We must account for the */ /* three *bin(4) fields at the start of each record (12) and the length */ /* of the data field (&SizFld)... */ chgvar &offsVarRcd ( &offsVarRcd + 12 + &SizFld ) /* Process key ID 6... */ if ( &KeyID *EQ 6 ) do /* Extract library size fields. This includes a base plus a multiplier... */ chgvar &Size %sst( &VarRcd 13 4 ) chgvar &OB_Mult %sst( &VarRcd 17 4 ) chgvar &InfStat %sst( &VarRcd 21 1 ) /* Check if the library size includes all objects in the library. */ if ( &InfStat *eq '0' ) do sndpgmmsg msg('Some objects locked or not authorized.') + topgmq( *PRV ) sndpgmmsg msg('Library objects size does not include all objects.') + topgmq( *PRV ) enddo enddo /* Process key ID 7... */ else if ( &KeyID *EQ 7 ) do /* Extract number of objects... */ chgvar &ObjNbr %sst( &VarRcd 13 4 ) enddo enddo /* We also retrieve the size of the *LIB object itself. This is displayed */ /* in the message because the 'library size information' value includes */ /* the size of the *LIB object. The user is supplied this value so that */ /* it can be subtracted if desired... */ rtvobjd &Lib objtype( *LIB ) size( &LO_Size ) /* Convert to *char to satisfy the CHGVAR command... */ chgvar %bin( &LibObjSiz ) &LO_Size /* Display the message with the info... */ /* We could have extracted the &Size and other fields as *INT variables, */ /* but *CHAR variables are easy to string together into a &msgdta */ /* variable. The MsgD doesn't know they aren't *INTs... */ chgvar &msgdta ( &Lib *cat + &Size *cat + &OB_Mult *cat + &LibObjSiz *cat + &ObjNbr + ) rtvmsg msgid( SLS0001 ) msgf( QTEMP/#SLS ) + msgdta( &msgdta ) msg( &msg ) dltmsgf QTEMP/#SLS /* We retrieve the msg text rather than send msg SLS0001 because the MsgF */ /* is going to be deleted. We'd have trouble viewing SLS0001 if the */ /* format no longer existed. The system wouldn't be able to display it. */ sndpgmmsg msgid( CPF9897 ) msgf( QCPFMSG ) + msgdta( &msg ) + topgmq( *PRV ) + msgtype( *NOTIFY ) /* ...and get out of this program... */ return endpgm
That can be compiled as OPM or ILE CL. It could have more error handling, but there isn't much point to it. It needs to be at Least V5R3, though it can be changed fairly easily to run at any earlier release.
It could also be changed to take advantage of V5R4 by declaring a few structures and basing them on *PTRs. Advance the structures through the variable-record space by adding offsets to the *PTRs.
Paste the code into a streamfile in your IFS. Use CPYFRMSTMF to copy into a source member. I have PDM options that run either CPYTOSTMF or CPYFRMSTMF depending on which way I'm going. I use either iNav or Windows Explorer to access the streamfile depending on how networking is set up.
Be aware that even the API can take a few minutes to process a large, complex library. The library might have many objects or a few objects such as source files with many members. The library directory structure needs to be processed by the API to get the detail needed to supply the totals.
Run the command against a few libraries to get a feel for it. Let me know if there are questions.