Thursday, October 26, 2023

Renaming a CL procedure's name in a RPG program

One of my criticisms when using CL procedures in my RPG programs is that I had to use the name of the module. Sometimes the ten character name of the procedure, and module, was not descriptive enough for my sensibilities. I have discovered that a solution was provided in IBM i 7.2 that allows me to give my own name to CL procedures.

In this example what the code for the CL procedure is not necessary. All I need to know is that it will copy a file to a IFS folder. It has four parameters:

  1. Library the file is in
  2. File name
  3. Path name, directory and name the file will be called in the IFS
  4. A code returned from CL procedure to whatever called it

The CL procedure I will be using is in the module CLMODULE01. I can only have one CL procedure in a module, and the CLLE compiler gives the procedure the same name as the module. I think you will all agree that the name does not describe what it does. If this was a procedure I would give it another name when defining it in my RPG program.

I added the module to a binding directory, BINDINGDIR, in my library. I can check that it was added in one of two ways. The first is using the Working Binding Directory Entries command, WRKBNDDIRE, thus:

WRKBNDDIRE BINDINGDIR

Which displays:

               Work with Binding Directory Entries

Binding Directory:   BINDINGDIR     Library:   MYLIB


Opt   Object       Type      Library
 _    __________   _______   __________
 _    CLMODULE01   *MODULE   *LIBL

I can also use the SQL View BINDING_DIRECTORY_INFO to do the same:

01  SELECT ENTRY_LIBRARY,ENTRY,ENTRY_TYPE
02    FROM QSYS2.BINDING_DIRECTORY_INFO
03   WHERE BINDING_DIRECTORY_LIBRARY = 'MYLIB'
04     AND BINDING_DIRECTORY = 'RPGPGM01'

I am only interested in three columns returned by the View:

  1. ENTRY_LIBRARY:  Which library to find the module in
  2. ENTRY:  Name of module
  3. ENTRY_TYPE:  The type of the entry, in this case it is a module rather than a service program
ENTRY_               ENTRY_
LIBRARY  ENTRY       TYPE
-------  ----------  -------
*LIBL    CLMODULE01  *MODULE

As I have my module and binding directory ready I can create my RPG program:

01  **free
02  ctl-opt option(*srcstmt) dftactgrp(*no) 
              bnddir('*LIBL/BINDINGDIR') ;

03  dcl-pr CpyFileToIFS extproc(*CL:'CLMODULE01') ;
04    *n char(10) const ;   // Library
05    *n char(10) const ;   // File
06    *n char(100) const ;  // IFS path
07    *n char(1) ;          // Return code 
08  end-pr ;

09  dcl-s RtnCde char(1) ;

10  CpyFileToIFS('MYLIB' : 'TESTFILE' :
                 '/home/mydir/testfile.txt' : RtnCde) ;

Line 1: You should be using totally free format RPG.

Line 2: These are the control option I need for this program. I need the DFTACTGRP as I am calling an external procedure. I always like adding the BNDDIR so that no-one can forget to use this binding directory when compiling this program.

Lines 3 – 8: The prototype definition for my CL procedure.

Line 3: Here is where I give the procedure the name I want, CpyFileToIFS, rather than use the CL module's name. I have the EXTPROC with *CL to denote that the procedure is written in CL, followed by the procedure's name.

Lines 4 – 7: I never bother to give my procedure parameters names. The ones that are followed by CONST will be passed as strings.

Line 9: This variable definition is for the variable I will be receiving the returned code into.

Line 10: I am calling my CL procedure with the name I gave it.

I can now create my RPG program. As my binding directory is given in the control options the CLMODULE01 is bound into the final program. How can I know that? It should come as no surprise there are two ways.

The first way I could check is using the Display Program command, DSPPGM:

DSPPGM PGM(RPGPGM01) DETAIL(*MODULE)

Which gives me:

                         Display Program Information

Program  . . . . . . :  RPGPGM01     Library  . . . . . . :  MYLIB
Owner  . . . . . . . :  SIMON
Program attribute  . :  RPGLE
Detail . . . . . . . :  *MODULE


Opt  Module      Library     Attribute
 _   RPGPM01     QTEMP       RPGLE
 _   CLMODULE01  MYLIB       CLLE

Or I can use the SQL View BOUND_MODULE_INFO:

01  SELECT BOUND_MODULE_LIBRARY AS "Mod lib",
02         BOUND_MODULE AS "Module",
03         MODULE_ATTRIBUTE AS "Type"
04    FROM QSYS2.BOUND_MODULE_INFO
05   WHERE PROGRAM_LIBRARY = 'MYLIB'
06     AND PROGRAM_NAME = 'RPGPGM01'
07     AND OBJECT_TYPE = '*PGM'

Lines 1 – 3: I am only interested in the columns:

  1. BOUND_MODULE_LIBRARY:  Library the bound modules are in
  2. BOUND_MODULE:  Names of the modules
  3. MODULE_ATTRIBUTE:  Their attribute

The results are:

Mod lib  Module      Type
-------  ----------  -----
QTEMP    RPGPGM01    RPGLE
MYLIB    CLMODULE01  CLLE

I am so pleased to have found the ability for me to give the CL procedures more descriptive names I am tempted to modify some of my existing programs to add this to them.

 

You can learn more about the enhancements to the RPG's procedure prototype's external procedure parameter from the IBM website here.

 

This article was written for IBM i 7.5, and should work for some earlier releases too.

No comments:

Post a Comment

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.