It's time you learned how to use the List Service Program Information (QBNLSPGM) API.
A recent article of mine in iApplication Designer, "V6R1 CL: The Story Continues," prompted the following note from reader David S.: "I enjoyed your article on V6R1 (6.1) CL. One of the enhancements you mentioned reminded me of a question I have had for some time... [about] CL and RPG modules. If I change and recompile a module (the module may be used in multiple programs), how do I find which programs need to be updated/re-created to include the new module? Does 6.1 CL/RPG help with this?"
Unfortunately, 6.1 does not help in this specific area, but David's note did inspire me to provide a practical demonstration of how to use two types of APIs. The APIs are List and Open List, areas that we haven't talked about in this column yet. For the next several columns, we'll be developing an application that will find all of the places a module has been bound into a *SRVPGM or *PGM.
As we need to start somewhere, we will start with the List Service Program Information (QBNLSPGM) API, which is documented here. The QBNLSPGM API returns information about *SRVPGMs, similar to what is returned by the Display Service Program (DSPSRVPGM) command. In particular, the API can return information concerning what *MODULEs are bound into the *SRVPGM. The API takes four parameters:
Required Parameter Group:
1 |
Qualified user space name |
Input |
Char(20) |
2 |
Format name |
Input |
Char(8) |
3 |
Qualified service program name |
Input |
Char(20) |
4 |
Error code |
I/O |
Char(*) |
Default Public Authority: *USE
Threadsafe: No
The first parameter, Qualified user space name, is the name of the *USRSPC the API is to return information into. We will, in the program, be creating this *USRSPC using the Create User Space (QUSCRTUS) API. The first 10 bytes of the qualified name is the name of the *USRSPC object. The second 10 bytes is the name of the library containing the *USRSPC or one of the special values *CURLIB and *LIBL.
The second parameter, Format name, describes the type of information we want returned. The QBNLSPGM API supports several formats corresponding to the types of information that are available--procedure name exports, data imports, copyrights, etc. Format SPGL0100 is used to access *MODULE-related information. The format of the information returned with SPGL0100 can be found in the API documentation. The key piece of information we will be working with today is the bound module name located at decimal offset 20 of format SPGL0100. The QSYSINC/QRPGLESRC definition for format SPGL0100 is found in source member QBNLSPGM, and the first few fields of the format are shown below.
DQBNL010000 DS
D* Qbn LSPGM SPGL0100
D QBNSN00 1 10
D* Srvpgm Name
D QBNSLIBN 11 20
D* Srvpgm Library Name
D QBNBMN00 21 30
D* Bound Module Name
D QBNBMLN00 31 40
D* Bound Module Library
D QBNSFILN00 41 50
D* Source File Name
D QBNSFLN00 51 60
D* Source File Library
D QBNSFILM00 61 70
D* Source File Member
Within the QSYSINC-provided data structure QBNL010000 are the fields QBNBMN00 (the Bound Module Name) and QBNSN00 (the service program name), two fields that are clearly of interest to us. Also in the data structure is a wealth of
additional information about the module. We won't be using these additional fields, but, for instance, field QBNSFILM00 is the Source File Member name used to create the *MODULE. If necessary, we could use this source member information to confirm that module X was indeed created from source member X, determine if module Y was really X renamed, etc. Reviewing all of the information that is available to you, even if you don't believe you need it initially, may very well suggest additional features your application may need to provide.
If you don't have the QSYSINC library installed on your system, you can install it with RSTLICPGM, specifying option 13 of the operating system. The QBNLSPGM API returns one occurrence of the QBNL010000 data structure for each *MODULE found bound into a *SRVPGM.
The third parameter, Qualified service program name, is the name of the *SRVPGM we want information about. The first 10 bytes of the qualified name can be a specific *SRVPGM name, a generic *SRVPGM name such as A*, or the special value *ALL. The second 10 bytes of the qualified name can be the name of a specific library or one of the special values *ALL, *ALLUSR, *CURLIB, *LIBL, or *USRLIBL.
The fourth parameter, Error code, is the standard error code structure we have seen before.
With that information out of the way, let's now write a sample program that displays all occurrences of a specific module that is found within one or more *SRVPGMs. Here's the initial code (and I stress initial because this code needs several improvements, which we will make before concluding on this topic in a future column):
h dftactgrp(*no)
dModUsage pr
d ModNam 10 const
d SrchLib 10 const
dModUsage pi
d ModNam 10 const
d SrchLib 10 const
d/copy qsysinc/qrpglesrc,qusec
d/copy qsysinc/qrpglesrc,qusgen
dChkSrvPgmMod pr
dSetup pr
dGenHdr ds likeds(QUSH0100)
d based(ModLstSpcPtr)
dObjLibNam ds
d 10 inz('*ALL')
d ObjLib 10
dModLstSpcPtr s *
dCount s 10i 0
dNbrMods s 10i 0
dHits s 10i 0
dWait s 1
dModLstSpc c 'MODLUSRSPCQTEMP'
/free
// check that the required parameters were passed
if %parms < 2;
dsply 'There are two required parameters:';
dsply '1. The module you are searching for';
dsply '2. The library to be searched in';
dsply 'The program did not run.' ' ' Wait;
*inlr = *on;
return;
endif;
Setup();
ChkSrvPgmMod();
dsply (%char(Hits) + ' *SRVPGM instances of ' +
%trimr(ModNam) + ' found.') ' ' Wait;
*inlr = *on;
return;
/end-free
*****************************************************************
pChkSrvPgmMod b
dChkSrvPgmMod pi
dGetSrvPgmInfo pr extpgm('QBNLSPGM')
d QUsrSpcNam 20 const
d Format 8 const
d QSrvPgmNam 20 const
d QUSEC likeds(QUSEC)
d/copy qsysinc/qrpglesrc,qbnlspgm
dSrvPgmE ds likeds(QBNL010000)
d based(SrvPgmEPtr)
dSrvPgmEPtr s *
/free
// Get the list of all *SRVPGMs and bound *MODULEs
GetSrvPgmInfo( ModLstSpc :'SPGL0100' :ObjLibNam :QUSEC);
if (GenHdr.QUSIS = 'C');
SrvPgmEPtr = ModLstSpcPtr + GenHdr.QUSOLD;
for NbrMods = 1 to GenHdr.QUSNBRLE;
if SrvPgmE.QBNBMN00 = ModNam;
dsply ('*SRVPGM: ' + %trimr(SrvPgmE.QBNSLIBN) +
'/' + SrvPgmE.QBNSN00);
Hits += 1;
endif;
SrvPgmEPtr += GenHdr.QUSSEE;
endfor;
else;
dsply ('Unable to access *SRVPGMs.');
endif;
/end-free
pChkSrvPgmMod e
*****************************************************************
pSetUp b
dSetUp pi
dCrtUsrSpc pr extpgm('QUSCRTUS')
d SpcName 20 const
d SpcAttr 10 const
d SpcSiz 10i 0 const
d SpcVal 1 const
d SpcAut 10 const
d SpcTxt 50 const
d SpcRpl 10 const options(*nopass)
d QUSEC likeds(QUSEC) options(*nopass)
d SpcDmn 10 const options(*nopass)
d SpcTfrSiz 10i 0 const options(*nopass)
d SpcSpcAln 1 const options(*nopass)
dGetUsrSpcPtr pr extpgm('QUSPTRUS')
d SpcName 20 const
d UsrSpcPtr *
d QUSEC likeds(QUSEC) options(*nopass)
/free
// set Error code bytes provided to send exceptions
QUSBPRV = 0;
// Set the library to search for *SRVPGMs
ObjLib = SrchLib;
// Create *USRSPC for module listing
CrtUsrSpc( ModLstSpc :' ' :1 :x'00' :'*CHANGE' :' ' :'*YES' :QUSEC);
// Get pointer to *USRSPC for module listing
GetUsrSpcPtr( ModLstSpc :ModLstSpcPtr :QUSEC);
/end-free
pSetUp e
This program, MODUSAGE, takes two parameters. The first parameter is the name of the module we are looking for. The second parameter is the name of the library or one of the special values *ALL, *ALLUSR, *CURLIB, *LIBL, and *USRLIBL to search for *SRVPGMs. Given these two input parameters, the program then examines each *SRVPGM found in the specified library (or libraries in the case of a special value) and displays the qualified name of any *SRVPGM found that contains the specified *MODULE.
To compile MODUSAGE, use the command CRTBNDRPG MODUSAGE. To test MODUSAGE, in order to find all *SRVPGMs in library MYLIB that module MYMOD is bound to, use CALL MODUSAGE (MYMOD MYLIB).
As to how the program works, that will have to wait until our next column as we have run out of room in this issue of RPG Developer. There is, though, enough of the program shown above for you to use it for testing, and certainly feel free to examine the program in order to determine how it works. Hopefully, in the next column we'll confirm your understanding! And, yes, some of the style may appear a bit strange, but you will in time see why as we add more function to MODUSAGE.
One word of caution: While MODUSAGE accepts special values such as *LIBL, you may, for now, want to limit your testing to specific libraries (or at least to special values that do not include QSYS--for instance, *ALLUSR or *USRLIBL). Otherwise, you may end up with error message CPF3CAA--List is too large for user space MODLUSRSPC. This is one of the considerations that we will be addressing with a future enhancement to MODUSAGE.
Meanwhile, if you have other API questions, send them to me at
LATEST COMMENTS
MC Press Online