RPG and COBOL were not designed for library list operations, so working with library lists in these languages requires calling a CL program or the QCMDEXC API. The subprocedures described in this article were designed to work directly from RPG and COBOL programs. They do everything the CL library list commands do, and more!
Many of us have grown accustomed to calling a CL program or the QCMDEXC API to perform operations such as adding or removing a library from a library list. This usually results in cumbersome and unreadable code that someone will have to maintain in the future. One solution to this problem is to create a host of subprocedures that you can use directly in your RPG or COBOL programs to perform these options. For library list functions, using subprocedures instead of a CL program or the QCMDEXC API not only makes the code more readable, but also enforces code reuse for commonly used operations.
To further explain this concept, I have created a service program with a host of subprocedures that perform library list operations. (The code for this program and for the subprocedures can be found on the MC Web site at www.midrangecomputing. com/mc/99/02.) The subprocedures range from adding a library to the library list to returning the current system, product, current, or user library list.
These subprocedures will come in handy in most applications that require changing the library list. For example, an application that installs new software requires that the library or libraries containing the old program objects and data (as well as the libraries containing the new information) be in the library list. If multiple machines are used, these libraries could have different names. A single job description containing an initial library list is all that is needed to change the library list to the one needed for the software installation.
Another example of when these subprocedures might come in handy would be the times when you use certain applications that are needed only for limited operations. These applications could range from any external tools you may have installed to fax software that is required only when faxing takes place in the application. If the tool or fax software exists
in a separate library, you can use these tools to first verify that the library in question is in the library list. Then, if you find that it is not, add the library to the library list. And, finally, after the specific operation is performed, you can remove the library from the library list.
Once youve downloaded the code from MCs Web site, take a close look at the subprocedures. I will discuss a few keywords that you may not have used before, as well as discuss how each of the subprocedures works. Hopefully, these subprocedures will be of use to you. But, more importantly, every bit of code that you can read and understand will help you build your skills for programming in the ILE environment.
The #PushLib and #PopLib Subprocedures
The #PushLib and #PopLib subprocedures are simple. If you are familiar with the Push and Pop operations used with stacks in operations programming, you have probably already guessed what the #PushLib and #PopLib subprocedures do. #PushLib will place the library passed to it onto the top of the library list. #PopLib will either remove the library on the top of the library list or remove the library name specified in the incoming library name parameter.
The #PopLib procedure uses the *NOPASS keyword on the library name parameter. This allows us to call #PopLib without any parameters. You will notice in the code for the #PopLib procedure that if no parameters are passed or if the library to remove equals the special value of *FIRST, #PopLib calls another procedure, #RtvLibL, to retrieve the user library list information and place it into an array. Then #PopLib puts the value of the first element of that array into the library name parameter to be used on the Remove Library List Entry (RMVLIBLE) command.
The #AddLibLE Procedure
The #AddLibLE procedure is used as a good example of replacing something that usually would have been coded as a QCMDEXC in a program with a simple procedure call. The parameters passed to this procedure are the same as the parameters on the Add Library List Entry (ADDLIBLE) command. Again, the keyword *NOPASS is used on the position parameter and the reference library parameter. I would guess that most of the time when you use the ADDLIBLE command you specify only a library. There are cases, however, when you want to place the library somewhere in the middle of the library list, and that is why the position and reference library parameters are optional.
In the first few statements of the #AddLibLE procedure, you will again see the use of another existing procedure, #PushLib. If only a library name is specified, or if the position of the library is the special value *FIRST, you simply call the #PushLib procedure, which already accomplishes this task. This is a simple example of breaking subprocedures down to perform the most basic operation and using the already existing procedure in another procedure.
If a position and reference library are specified in the #AddLibLE procedure, you will simply call QCMDEXC with the ADDLIBLE command, specifying the data passed in. Again, this procedure makes your code much more readable, as you code only the QCMDEXC API call in the procedure itself.
The #ChgLibLJD Procedure
The #ChgLibLJD procedure may be a little confusing at first. The #ChgLibLJD procedure uses a job description that is passed to it and changes the jobs user library list to the initial library list specified in the job description.
This procedure uses the QWDRJOBD API to determine the number of libraries and the initial library list entries contained within the job description. This information is loaded into an array, which QLICHGLL uses to change the user library list.
This procedure could be used when data from different systems is contained in different libraries. When a user is moving from one system to another, a call to this procedure with the name of a job description set up for a specific system would immediately set up the library list for use with that system.
The #RtvLibL Procedure
The #RtvLibL procedure retrieves the system library list, product library, current library, or user library list and returns a pointer to the data structure that contains the library list information. There are four different data structures set up within this procedure, one for each different library list. Depending on the library list type value passed into the procedure, the #RtvLibL procedure will fill and return the location of the data structure containing the library list information requested. On the receiving side of the procedure, a simple generic data structure may be used with the BASED keyword.
This #RtvLibL procedure was used in the #PopLib procedure. This is one working example of how to use the #RtvLibL procedure. Referring back to the #PopLib procedure, you will see that the data structure LibData and the pointer variable LibPtr are declared in the D-specs. The LibData data structure uses the BASED keyword. This keyword tells the system that the location of the data is found at the location referenced by the LibPtr pointer variable type. The LibPtr variable is set by calling the #RtvLibL procedure. If the call is successful, the pointer will contain a reference to where you will find the library list information. If the call is unsuccessful, the #RtvLibL procedure returns *NULL, telling us that an error occurred.
Returning to the #RtvLibL procedure, you will notice another difference in the variable declarations. Each of the four data structures used to retrieve and return the data contains the STATIC keyword. This keyword is used because the data structures are local only to the #RtvLibL procedure. If you had omitted the STATIC keyword, the pointer returned would reference the information that used to contain the information requested during the procedure call.
By the time you get back to the calling program, the particular part of memory that held this information during the call could have already been reused, possibly corrupting the data you had wanted. The STATIC keyword tells the system that the memory holding this information should be made available to all programs and subprocedures in the call stack. Another way around this problem would have been to move the data structures to the global variable definitions.
The #VerLib Procedure
The #VerLib procedure is another simple procedure that lets the calling program know if a specific library is already included in the library list and the position that it is in. The two input parameters required for this procedure are the library name you wish to verify, and which library list to look in. The library list could be the system, product, current, or user library list denoted by *SYSTEM, *PRODUCT, *CURRENT, or *USER respectively. This procedure also makes use of the #RtvLibL procedure, returning the specified library list into a data structure and performing a simple LOOKUP operationyet another example of using a procedure already created to perform an option instead of reinventing the wheel.
If the library is found in the library list, a number greater than zero is returned. This number tells the position of the library that you have requested verification for in the library list. A value of zero means the library was not found in the library list. A value of negative one indicates that an error occurred somewhere in the process. This error most likely would occur while retrieving the specified library.
The More You Know...
The purpose of my showing you these library functions is twofold. First, I am giving you some code that could help you in your system development. Second, and more important, I am trying to show you that using service programs will simplify your job.
When you reach a point in a program where you realize that a QCMDEXC must be used, chances are that this isnt the first time youve come to such a realization, and that there are other programs that have also used the same QCMDEXC statement. By combining these heavily used commands into a service program and building the command using parameters passed into the procedure, your coding will be easier to maintain and
more readable. Start with one procedure that calls only the QCMDEXC API with the command as the only parameter. If this is the first procedure you create, it will be simple to code, but it will be enough to show you how subprocedures work. You will find that those once-cryptic statements are now nothing more than simple EVAL or CALLP statements.
The use of subprocedures within your system is limited only by your imagination and creativeness. Using subprocedures effectively also takes practice. It is a good idea to create subprocedures that perform smaller tasks and use these smaller subprocedures in other subprocedures. Breaking an operation into simpler operations not only reduces the chance of error, but also limits certain code to one spot on the system. This will make maintenance a much easier proposition in the long run.
AS/400 ILE Concepts V4R2 (SC41-5606-01, CD-ROM QB3AQ701)