(Author's Note: This technique came from On-Line Streaming Video RPG IV Training, where you can find more tips like this one.)
One barrier to writing subprocedures seems to be getting started with that first one. Where do you begin?
The answer to that question is to simply convert an existing subroutine to a subprocedure.
Let's use the subroutine named CENTERSR as an example of how this can be accomplished.
Consider the follow source code. It uses the subroutine CENTERSR to center the text in the field named CENTER. In this example, we copy a field whose content we want centered to the field named CENTER and then call the subroutine. After the subroutine returns, the data is copied back to the original field, presumably centered accurately, as follows:
D workfld S 255A
D center S 255A
D LeftMarg S 3P 0
D nLen S 3P 0
C eval center = myCompName
C exsr centerSR
C eval myCompName = Center
CSR CenterSR BegSR
C eval nLen = %Len(%Trim(Center))
C eval LeftMarg = %DIV(nLen : 2 )
C if leftMarg > 0
/free
%subst(workfld:leftmarg) = %TrimL(Center);
/end-free
C eval center = Workfld
C endif
CSR endCenterSR EndSR
To convert this to a subprocedure, replace the BEGSR and ENDSR statements with Subprocedure specifications, as follows:
C eval nLen = %Len(%Trim(Center))
C eval LeftMarg = %DIV(nLen : 2 )
C if leftMarg > 0
C eval %subst(workfld:leftMarg) = %TrimL(Center)
C eval center = Workfld
C endif
P CenterSR E
This creates a subprocedure starting point.
Next, convert the work fields to subprocedure parameters and local variables, as follows:
D CenterSR PI
D center 255A
D LeftMarg S 3P 0
D nLen S 3P 0
C eval nLen = %Len(%Trim(Center))
C eval LeftMarg = %DIV(nLen : 2 )
C if leftMarg > 0
C eval %subst(Center:leftMarg) = %TrimL(Center)
C endif
P CenterSR E
In the above example, the CENTER work field is converted to a parameter. The work field named WORKFLD is no longer needed. The other two fields, nLen and LeftMarg, are moved to the subprocedure. When a field is declared inside of a subprocedure, it is known as a local variable. It is not visible to the rest of the program at that point—only to the Calc specs within the subprocedure.
The last thing we need to do is create a prototype, which is a copy of the parameter list for the subprocedure. The RPG IV compiler uses the prototype to syntax-check your calls to your subprocedures. Without it, RPG IV would not be able to determine if the field you're passing on a parameter to your subprocedure should be numeric or character. So let's create a prototype for the CENTERSR subprocedure.
D center 255A
Prototypes are normally placed in the global Definition specifications near the top of the source member. It's a good idea to always put them into a /COPY member that contains prototypes for similar functions. For example, if we had procedures to left-justify text, right-justify text, center text, and search text, we might have a source member named TEXTPROTOS that contains the prototypes of all of these subprocedures.
The final step is to update the call to the subprocedure. We need to convert the call to the subroutine to a call to the subprocedure. We do that as follows:
This single line of code replaces the original Calc specs that moved, called, moved data. It also replaces the work fields we had to declare and manage. So the following has been replaced with the single CALLP operation:
D center S 255A
D LeftMarg S 3P 0
D nLen S 3P 0
C eval center = myCompName
C exsr centerSR
C eval myCompName = Center
Moving to subprocedures can be fun and exciting. Above all, it can be as easy or as complicated as you make it.
Bob Cozzi is a programmer/consultant, writer/author, and software developer of the RPG xTools, a popular add-on subprocedure library for RPG IV. His book The Modern RPG Language has been the most widely used RPG programming book for nearly two decades. He, along with others, speaks at and runs the highly-popular RPG World conference for RPG programmers.
LATEST COMMENTS
MC Press Online