StrCenter() is an RPG IV subprocedure that takes any uncentered text variable (or string) and returns the centered text. Hence, the name StrCentergreat for centering text on displays and reports!
Since the introduction of RPG IV with V3R1, nothing other than a few syntactical changes warranted converting my RPG III code. But, with V3R2s addition of subprocedures and then V3R7s pointers and memory management for such things as unbounded arrays, I can now justify code conversion. While pointer manipulation and memory management operations are quite interesting topics, this article will focus on the much more interesting topic of subprocedures. Subprocedures can be described as well- contained (modular) logic that deals with a specific problem (limited scope) and has a well- defined set of arguments (interface) that describes only enough about the nature of the subprocedure to properly utilize it. This definition enables global usage of a subprocedure without being concerned about how a particular application uses it. In many respects, a subprocedure is like a well-constructed /COPY source member, except that, with subprocedures, we promote binarynot sourcereuse, and we can pass parameters (arguments) to it. But how could subprocedures be employed in my programs, you ask?
Assume you have a report or inquiry in which some text must be centered for proper presentation to the user. For example, say the Customer Service department has requested that you create an inquiry screen in which, by selecting a customer name from a list and pressing Enter, the user can access a full-screen panel that shows the name of the customer at the top. Since customer names can be very short or very long, a subprocedure such as StrCenter() ensures the name will always be centered, providing a professional look to the panel.
In Figure 1, I have used two cases to show the versatility of subprocedures in general and StrCenter() in particular.
Note that our subprocedure, StrCenter(), accepts two parameters or arguments: (1) a reference to the string to be centered and (2) the length within which to center the string.
This subprocedure will return the centered text to the receiver variable of our assignment in the EVAL statement (in this case, Title).
In Case 1, the same variable passed to StrCenter() as the first argument is also defined as the receiver. In this case, the second argument passed is the %SIZE of Title (40 bytes). Case 2 shows Title being defined as the receiver for the StrCenter() subprocedure results. MyText is passed as the referenced variable text to be centered in Title, with a numeric literal as a constant (40) passed as the second argument to the subprocedure .
(For more information about how to compile, see the sidebar Compiler Directives.)
The PR statement (Figure 2, Label B), or prototype definition statement, identifies and defines any value to be returned by the subprocedure. This must be the maximum length of receiver variable that can be returned by the subprocedure. I have limited this to a maximum string length of 256 characters.
Immediately following this statement are the parameters that will be passed to the StrCenter() subprocedure (Figure 2, Labels C and D). These can be given names or not; they are inconsequential to our discussion. The compiler that creates our program module is interested only in the number and type of parameters, not the names. Since one of the main benefits of subprocedures is hiding the implementation details (such as subprocedure local variable names) from the user application, we will not concern ourselves with what those names might be. If you want to review the implementation details of the StrCenter() subprocedure, see Subprocedures: A Step in the Right Direction! also in this issue.
Figure 3 shows a trivial program that uses this function to center text defined in MyText as left-justified. The result of the centering function is displayed with the DSPLY RPG op code.
As you can see, by using the StrCenter() subprocedure, you can ensure consistency in handling text-centering functions and avoid programmer resources being expended on recoding the same logic over and over again. But dont stop there; you can write many other subprocedures to save your programmers from wasting time recoding commonly required functions. The primary obstacle that we RPG programmers must overcome is the unspoken principle of If I didnt build it, it must not be any good. I must confess that I too have been guilty of this sin. But since I have been extensively utilizing subprocedures and service programs, I have come to accept (and blindly so) that I must depend upon others for the prebuilt components required to meet productivity objectives in todays world. And, if you are getting those components off the shelf, you may not be able to review the source code unless you buy it (usually, at quite a premium). So jump on the bandwagon! But dont just build subprocedures; become a user as well!
D Title S 40A INZ(Very, very, long text)
D MyText S 30A INZ(Short text)
CASE 1: EVAL Title = StrCenter(Title : %SIZE(Title))
Before StrCenter (): |Very, very, long text |
After StrCenter(): | Very, very, long text |
CASE 2: EVAL Title = StrCenter( MyText : 40)
Before StrCenter(): |Short text |
After StrCenter(): | Short text |
Figure 1: Using StrCenter()
** Compiler Directives*------------------------------------------------------------------
/If Not Defined( StrCenterHCopied )
/Define StrCenterHCopied
/Else
/Eof
/EndIf
** Prototype for StrCenter () Subprocedure
*D StrCenter PR 256A OPDESC
D {Text or String passed to be centered} 256A Options(*VARSIZE)
D {Size of Receiver Variable } 5P 0 CONST
*-
Figure 2: StrCenter() compiler directives and prototype
*=================================================================
* To compile:
*
* CRTBNDDIR BNDDIR(XXX/STRLIB)
* ADDBNDDIRE BNDDIR(XXX/STRLIB) OBJ((XXX/STRCENTER *MODULE))
* CRTRPGMOD MODULE(XXX/TEST) SRCFILE(XXX/QRPGLESRC)
* CRTPGM PGM(XXX/TEST) MODULE(XXX/TEST) +
* BNDDIR(XXX/STRLIB)
*
*=================================================================
/COPY SYSINC,StrCenterH
*
D MyText S 30A INZ(Uncentered Text)
D Title S 40A
*
C MyText DSPLY
* Produces output |Uncentered Text |
C EVAL Title = StrCenter( MyText:%SIZE(Title))
C Title DSPLY
* Produces output | Uncentered Text |
C EVAL *INLR = *ON
Figure 3: A Program Using StrCenter()
Compiler Directives
The compiler directives, shown in Figure 2, Label A, are specified at the top of the source for my prototype definition. I have defined a compiler condition variable, StrCenterHCopied, that will be created when the program reads the first /COPY that includes this definition. This technique avoids compiler errors that would result if another subprocedure or module had already prototyped it for compilation. As indicated with the /Eof directive, once the condition variable StrCenterHCopied has been defined, the compiler will receive an /Eof indication each time it attempts to copy the source for the prototype into the current compile text. Without these directives, /COPY directives for the same member would result in duplicate declarations for prototyped variables and thus end with compiler errors. As shown in the compile instructions, the StrCenter() subprocedure should be compiled and placed in a binding directory for string library (STRLIB) subprocedures. You can place your subprocedure in the binding directory by first creating the directory and then adding the StrCenter() module to it, as shown in the compile instructions in Figure 3.
By doing this, you will simplify binding when many modules defined in STRLIB are required. Then, all you have to do is define the binding directory, as I did in Figure 3s Create Program (CRTPGM) command, rather than list each module separately in the CRTPGM MODULE parameter.
LATEST COMMENTS
MC Press Online