Analyzing ILE Programs

It’s no secret that the Integrated Language Environment helps us all write more modular applications. Modules and service programs make it easy to construct programs from several small, easily maintained, reusable chunks of code. We can even create programs composed of several different languages.

Although development using modular chunks is easy, there is a bit of trouble in paradise. You sometimes need to know which application programs use particular modules and service programs. This is especially true when you modify modules and service programs, because you must rebind them to your application programs for the changes to take effect. In the past, there has been no convenient way to determine the modules and service programs your applications use. But now, you can have the Anzilepgm utility do the research and present the information to you.


Overview

Let’s take a quick look at the utility’s components. Command Anzilepgm (Figure 1) lets you specify the library whose programs you want to cross-reference. You can also specify one of three special values for the library-*ALLUSR to analyze all user libraries, *CURLIB to analyze the job’s current library, or *USRLIBL to analyze the libraries in the user portion of the job’s library list. This command is so simple that it needs no further explanation. SQL source member AnzCrtDb contains SQL statements that create the cross-reference files Anzilepgm uses. This member is of type Text.

Figure 1. Command ANZILEPGM

/* ======================================================== */
/* Command: ANZILEPGM - Analyze ILE programs                */
/* ======================================================== */
ANZILEPGM: CMD        PROMPT('Analyze ILE programs' )
           PARM       KWD(LIB )                  +
                      TYPE(*NAME)                +
                      LEN(10)                    +
                      SPCVAL((*ALLUSR)           +
                             (*CURLIB)           +
                             (*USRLIBL))         +
                      MIN(1)                     +
                      PROMPT('Library to analyze')

ILE program Anzilepgm consists of two modules, CL module Anzilepgm1 and RPG module Anzilepgm2. Anzilepgm1 serves as the driver for the utility, and Anzilepgm2 builds the cross-reference database.


 

The Cross-Reference Database

To create its database, Anzilepgm uses the RUNSQLSTM (Run SQL Statement) command to execute the SQL statements in source member AnzCrtDb (Figure 2). These statements produce two cross-reference files- AnzILEMod, which contains information about modules, and AnzILESvc, which contains information about service programs. The CREATE TABLE statements actually create the physical files, while the LABEL ON statements add text descriptions for the fields.

Figure 2 – Creating the cross-reference database

CREATE TABLE QTEMP/ANZILEMOD (PGMNAME CHAR(10),     
                              LIBNAME   CHAR(10),
                              MODNAME   CHAR(10),
                              MODLIB    CHAR(10),
                              MODSRC    CHAR(10),
                              MODSRCLIB CHAR(10),
                              MODSRCMBR CHAR(10),
                              MODATR    CHAR(10),
                              MODCRT    CHAR(13),
                              MODSRCUPD CHAR(13));
LABEL ON QTEMP/ANZILEMOD     (PGMNAME   IS 'Prog Name',
                              LIBNAME   IS 'Libr Name',
                              MODNAME   IS 'Module Name',
                              MODLIB    IS 'Module Libr',
                              MODSRC    IS 'Mod Src File'
                              MODSRCLIB IS 'Mod Src Libr',
                              MODSRCMBR IS 'Mod Src Mbr',
                              MODATR    IS 'Mod Attrib',
                              MODCRT    IS 'Mod Created',
                              MODSRCUPD IS 'Src Changed');
CREATE TABLE QTEMP/ANZILESVC (PGMNAME CHAR(10),
                              LIBNAME CHAR(10),
                              SVCNAME CHAR(10),
                              SVCLIB  CHAR(10),
                              SVCSIG  CHAR(16));
LABEL ON QTEMP/ANZILESVC     (PGMNAME IS 'Program Name',
                              LIBNAME IS 'Library Name',
                              SVCNAME IS 'Srv Pgm Name',
                              SVCLIB  IS 'Srv Pgm Libr',
                              SVCSIG  IS 'Srv Pgm Signature');

Because Anzilepgm creates the files in library QTEMP, the information is no longer available after your job ends. You could keep the information in permanent files, but we don’t advise it. The temporary files always reflect the state of your objects at the time you analyze them, but permanent files run the risk of not being synchronized with your objects should you make changes without refreshing the database.

After the utility loads these files, you can query their contents however you’d like. You can simply print a report showing the information, search for information about how a particular object is used, or even use the information as input to a utility to compile programs.


 

The CL Driver

Anzilepgm1 functions much like an OPM CL program that acts as a driver for an OPM RPG program. That is, Anzilepgm1 acts as the entry point, setting overrides and other environmental conditions necessary for the RPG program. But unlike an OPM environment, in which the CL driver and RPG program are two separate programs, Anzilepgm1 is a module bound with RPG module Anzilepgm2 to form a single program. Anzilepgm1 (Figure 3) first executes the DSPOBJD (Display Object Description) command to create a file containing a list of the program and service program objects to be analyzed. This file serves as input to module Anzilepgm2.

Figure 3 – CL module Anzilepgm1

/* ========================================================= */
/* Module: ANZILEPGM1 - Analyze ILE programs - Main driver   */
/* ========================================================= */
PGM        PARM( &Library )
DCL        &Library *CHAR  10
DCL        &MsgID   *CHAR   7
DCL        &MsgF    *CHAR  10
DCL        &MsgFLib *CHAR  10
DCL        &Msgdta  *CHAR 100
MONMSG     (CPF0000 MCH0000) EXEC(GOTO Error)
DSPOBJD    &Library/*ALL           +
           OBJTYPE(*PGM *SRVPGM)   +
           OUTPUT(*OUTFILE)        +
           OUTFILE(QTEMP/QADSPOBJ)
DLTF       QTEMP/ANZILEMOD
MONMSG     CPF0000
DLTF       QTEMP/ANZILESVC
MONMSG     CPF0000
RUNSQLSTM  SRCFILE(ANZILEPGM) +
           SRCMBR(ANZCRTDB)
OVRDBF     QADSPOBJ  QTEMP/QADSPOBJ
OVRDBF     ANZILEMOD QTEMP/ANZILEMOD
OVRDBF     ANZILESVC QTEMP/ANZILESVC
CALLPRC    ANZILEPGM2
DLTOVR     *ALL
RETURN
Error:
RCVMSG     MSGTYPE(*LAST)    +
           MSGDTA(&MsgDta)   +
           MSGID(&MsgID)     +
           MSGF(&MsgF)       +
           MSGFLIB(&MsgFLib)
MONMSG     (CPF0000 MCH0000)
SNDPGMMSG  MSGID(&MsgID)        +
           MSGF(&MsgFLib/&MsgF) +
           MSGDTA(&MsgDta)      +
           MSGTYPE(*ESCAPE)
MONMSG     (CPF0000 MCH0000)
ENDPGM

Next, Anzilepgm1 creates the cross-reference files by issuing the RUNSQLSTM command for source member AnzCrtDB. Finally, after issuing file overrides, the CL module invokes main procedure Anzilepgm2 with the CALLPRC (Call Procedure) command.


 

The RPG Processor

RPG module Anzilepgm2 (Figure 4) does the real work of Anzilepgm. This module uses several procedures and APIs to gather the cross-reference information. The main procedure reads a record from the file produced by the DSPOBJD command. When the object is a service program or an ILE program, the procedure invokes procedure BldModLst and BldSvcLst to build a list of modules and service programs the object uses.

Figure 4 – RPG module Anzilepgm2

  //  ===============================================================
  //  Module: ANZILEPGM2 - Analyze ILE programs - Build database       
  //  ===============================================================  
                                                                       
FQadspobj  IPE  E             Disk                                     
FAnzilemod O    E             Disk    Prefix(Mod_)                     
F                                     Rename(Anzilemod:Modrec)         
FAnzilesvc O    E             Disk    Prefix(Svc_)                     
F                                     Rename(Anzilesvc:Svcrec)         
                                                                       
  // ------------------------------------------- Procedure prototypes
D Bldmodlst       PR                                                   
D                               20    Value                            
D                                8    Value                            
                                                                       
D Bldsvclst       PR                                                   
D                               20    Value                            
D                                8    Value                            
                                                                       
D Crtusrspc       PR                                                   
D                               20    Value                            
                                                                       
D Getlstinf       PR                                                   
D                               20    Value                            
D                               10U 0                                  
D                               10U 0                                  
D                               10U 0                                  
                                                                       
D Pgmisile        PR              N                                    
D                               20    Value                            
                                                                       
  // ------------------------------------------------- API prototypes
D Qbnlpgmi        PR                  Extpgm('QBNLPGMI')               
D   Apiusrspc                   20    Const                            
D   Apilstfmt                    8    Const                            
D   Qpgmname                    20    Const                            
D   Apierr                      16                                     
                                                                       
D Qbnlspgm        PR                  Extpgm('QBNLSPGM')               
D   Apiusrspc                   20    Const                            
D   Apilstfmt                    8    Const                            
D   Qpgmname                    20    Const                            
D   Apierr                      16                                     
                                                                       
D Qclrpgmi        PR                  Extpgm('QCLRPGMI')               
D  Pgmi0100                    161                                     
D  Pgmilen                      10U 0 Const                            
D  Pgmifmt                       8    Const                            
D  Qpgmname                     20    Const                            
D  Apierr                       16                                     
                                                                       
D Quscrtus        PR                  Extpgm('QUSCRTUS')               
D  Uspcname                     20    Const                            
D  Uspcextatr                   10    Const                            
D  Uspcsiz                      10U 0 Const                            
D  Uspcinzval                    1    Const                            
D  Uspcpubaut                   10    Const                            
D  Uspctext                     50    Const                            
D  Uspcrpl                      10    Const                            
D  Apierr                       16                                     
                                                                       
D Qgetlstmod      PR                  Extpgm('QUSRTVUS')               
D  Apiusrspc                    20    Const                            
D  Apilstpos                    10U 0 Const                            
D  Apisizent                    10U 0 Const                            
D  Apirtnvar                   508                                     
                                                                       
D Qgetlstspg      PR                  Extpgm('QUSRTVUS')               
D  Apiusrspc                    20    Const                            
D  Apilstpos                    10U 0 Const                            
D  Apisizent                    10U 0 Const                            
D  Apirtnvar                    56                                     
                                                                       
D Qgetlstinf      PR                  Extpgm('QUSRTVUS')               
D  Apiusrspc                    20    Const                            
D  Apilstpos                    10U 0 Const                            
D  Apisizent                    10U 0 Const                            
D  Apirtnvar                    16                                     
                                                                       
  // ----------------------------------------------- Global variables
D Modfmt        E DS                  Extname(Anzilemod)               
D                                     Based(Modfmtptr)                 
D                                     Prefix(Mod_)                     
                                                                       
D Svcfmt        E DS                  Extname(Anzilesvc)               
D                                     Based(Svcfmtptr)                 
D                                     Prefix(Svc_)                     
                                                                       
D Modfmtptr       S               *   Inz(*NULL)                       
D Svcfmtptr       S               *   Inz(*NULL)                       
                                                                       
  //  ---------------------------------------------------------------  
  //  - Main procedure                                                 
  //  ---------------------------------------------------------------  
 /free                                                                 
  If Odobtp = '*SRVPGM' Or Pgmisile(Odobnm + Odlbnm);                  
    Bldmodlst(Odobnm + Odlbnm:Odobtp);                                 
    Bldsvclst(Odobnm + Odlbnm:Odobtp);                                 
  Endif;                                                               
 /end-free                                                             
                                                                       
  //  ---------------------------------------------------------------
  //  Procedure: BldModLst - Populate database with modules used       
  //  ---------------------------------------------------------------
P Bldmodlst       B                                                    
D                 PI                                                   
D Qpgmname                      20    Value                            
D Objtype                        8    Value                            
                                                                       
D Apiusrspc       C                   'PGML0100  QTEMP     '           
                                                                       
D Apierr          S             16                                     
D Apilstpos       S             10U 0                                  
D Apinbrent       S             10U 0                                  
D Apirtnvar       S            508                                     
D Apisizent       S             10U 0                                  
D X               S             10U 0                                  
                                                                       
 /free                                                                 
  Crtusrspc(Apiusrspc);      // Create User Space To Hold Module List
                                                                       
  If Objtype = '*SRVPGM';                        // Build Module List
    Qbnlspgm(Apiusrspc:'SPGL0100':Qpgmname:Apierr);                    
  Else;                                                                
    Qbnlpgmi(Apiusrspc:'PGML0100':Qpgmname:Apierr);                    
  Endif;                                                               
                                                                       
  Getlstinf(Apiusrspc:Apilstpos:Apinbrent:Apisizent); // Get List Hdr
                                                                       
  If Apinbrent < 1;                                   // Process List
    Return;                                                            
  Endif;                                                               
                                                                       
  Modfmtptr = %ADDR(Apirtnvar);                                        
                                                                       
  For X = 1 To Apinbrent;                                              
    Qgetlstmod(Apiusrspc:Apilstpos:Apisizent:Apirtnvar);               
    Write Modrec;                                                      
    Apilstpos = Apilstpos + Apisizent;                                 
  Endfor;                                                              
                                                                       
  Return;                                                              
 /end-free                                                             
P Bldmodlst       E                                                    
                                                                       
  //  ---------------------------------------------------------------
  //  Procedure: BldSvcLst - Populate database with service            
  //  ---------------------------------------------------------------
P Bldsvclst       B                                                    
D                 PI                                                   
D Qpgmname                      20    Value                            
D Objtype                        8    Value                            
                                                                       
D Apiusrspc       C                   'PGML0200  QTEMP     '           
                                                                       
D Apierr          S             16                                     
D Apilstfmt       S              8                                     
D Apilstpos       S             10U 0                                  
D Apinbrent       S             10U 0                                  
D Apirtnvar       S             56                                     
D Apisizent       S             10U 0                                  
D X               S             10U 0                                  
                                                                       
 /free                                                                 
  Crtusrspc(Apiusrspc); // Create User Space For Service Program List
                                                                       
  If Objtype   = '*SRVPGM';             // Build Service Program List
    Qbnlspgm(Apiusrspc:'SPGL0200':Qpgmname:Apierr);                    
  Else;                                                                
    Qbnlpgmi(Apiusrspc:'PGML0200':Qpgmname:Apierr);                    
  Endif;                                                               
                                                                       
  Getlstinf(Apiusrspc:Apilstpos:Apinbrent:Apisizent); // Get List Hdr
                                                                       
  If Apinbrent < 1;                                   // Process List
    Return;                                                            
  Endif;                                                               
                                                                       
  Svcfmtptr = %ADDR(Apirtnvar);                                        
                                                                       
  For X = 1 To Apinbrent;                                              
    Qgetlstspg(Apiusrspc:Apilstpos:Apisizent:Apirtnvar);                                                
    If %SUBST(Apirtnvar:31:10) <> 'QSYS      ';                  
      Write Svcrec;                                                    
    Endif;                                                             
    Apilstpos = Apilstpos + Apisizent;                                 
  Endfor;                                                              
                                                                       
  Return;                                                              
 /end-free                                                             
P Bldsvclst       E                                                    
                                                                       
  //  ---------------------------------------------------------------
  //  Procedure: CrtUsrSpc - Creates a user space                      
  //  ---------------------------------------------------------------
P Crtusrspc       B                                                    
D                 PI                                                   
D Uspcname                      20    Value                            
                                                                       
D Apierr          S             16                                     
                                                                       
 /free                                                                 
  Quscrtus(Uspcname:                                                   
           'ANZILEPGM':4096:X'00':'*ALL':*BLANKS:'*YES':Apierr);       
  Return;                                                              
 /end-free                                                             
P Crtusrspc       E                                                    
                                                                       
  //  ---------------------------------------------------------------
  //  Procedure: GetLstInf - Retrieves generic header list format  
  //  ---------------------------------------------------------------
P Getlstinf       B                                                    
D                 PI                                                   
D Uspcname                      20    Value                            
D Lstpos                        10U 0                                  
D Lstnbrent                     10U 0                                  
D Lstsizent                     10U 0                                  
                                                                       
D Uspcrtnvar      DS                                                   
D Uspclstpos                    10U 0                                  
D                               10U 0                                  
D Uspcnbrent                    10U 0                                  
D Uspcsizent                    10U 0                                  
                                                                       
 /free                                                                 
  Qgetlstinf(Uspcname:125:16:Uspcrtnvar);        // Get list position
  Lstpos    = Uspclstpos + 1;                                          
  Lstnbrent = Uspcnbrent;                                              
  Lstsizent = Uspcsizent;                                              
  Return;                                                              
 /end-free                                                             
P Getlstinf       E                                                    
                                                                       
  //  ---------------------------------------------------------------
  //  Procedure: PgmIsILE - Returns indicator for program type         
  //                       *ON = ILE program                           
  //                       *OFF = Not ILE program                      
  //  ---------------------------------------------------------------
P Pgmisile        B                                                    
D                 PI              N                                    
D Qpgmname                      20    Value                            
                                                                       
D Apierr          S             16                                     
                                                                       
D Pgmi0100        DS                                                   
D Pgmipgmtyp            161    161                                     
                                                                       
 /free                                                                 
  Qclrpgmi(Pgmi0100:%SIZE(Pgmi0100):'PGMI0100':Qpgmname:Apierr);       
  Return (Pgmipgmtyp = 'B');        // *ON=Ile Pgm, *OFF=Not Ile Pgm 
 /end-free                                                             
P Pgmisile        E                                                    

BldModLst populates the cross-reference database with modules used by the object. The procedure uses APIs QBNLPGMI to retrieve information for modules and QBNLSPGM to retrieve information for service programs. Procedure BldSvcLst populates the cross-reference database with service programs used by the object. This procedure’s workings are, for all practical purposes, identical to those of BldModLst. Because these procedures are so similar, we discuss only BldModLst.

BldModLst first creates a user space to contain the module information retrieved by the APIs. Next, it retrieves the information by invoking the appropriate API. The procedure then extracts (from the generic header portion of the user space) the entry size and the number of entries in the module list. Finally, the procedure extracts the information from the user space and writes it to the cross-reference database.


 

Conclusion

The next time you modify a module or service program, you can use Anzilepgm to find all application programs that reference it. Anzilepgm makes the job of rebinding modified modules and service programs to your applications easier, faster, and more reliable.


Installing Anzilepgm

You should create source physical file ANZILEPGM to contain all source from the Anzilepgm utility. If you opt to use your own source file, be sure to change references to source file ANZILEPGM in the utility and installation process below.

RUNSQLSTM   SRCFILE(YourLib/ANZILEPGM)       +
            SRCMBR(ANZCRTDB)

DSPOBJD     YourLib/*ALL                     +
            OBJTYPE(*PGM *SRVPGM)            +
            OUTPUT(*OUTFILE)                 +
            OUTFILE(QTEMP/QADSPOBJ)
 
CRTCMD      CMD(YourLib/ANZILEPGM)           +
            PGM(ANZILEPGM)                   +
            SRCFILE(YourLib/Anzilepgm)
 
CRTCLMOD    MODULE(ANZILEPGM1)               +
            SRCFILE(YourLib/Anzilepgm)
 
CRTRPGMOD   MODULE(ANZILEPGM2)               +
            SRCFILE(YourLib/Anzilepgm)
 
CRTPGM      PGM(ANZILEPGM)                   +
            MODULE(ANZILEPGM1 ANZILEPGM2)    +
            ACTGRP(QILE)