Everybody
enjoys writing new code, but there is still legacy code out there to maintain.
(And as I keep reminding myself, the pay is the same whether I write fixed-format
RPG or free-format RPG.) This service program and RPG/DDS test source was
the result of a situation where a legacy application happened to be out of
indicators, raising the issue of how to control display attributes without
the use of an indicator.
I knew that I could control the display attributes of a field through the
use of the DDS keyword DSPATR and a P-type (program-to-system) variable.
To make the process simple and re-useable, I decided to create a prototyped
procedure that makes it simple to manipulate the value of the display attribute
in the P-type field.
The following source
code describes a very simple service program, a display file and a bound
RPG program. The objects may serve as an example for application development
on a couple of levels. It demonstrates how an RPG program can be made to
manipulate display attributes without using indicators. It also provides
a step-by-step description of how to create a service program, and how to
use a service program procedure via a bound RPGLE program.
The RPG source (Fig. 1) of the service program used to set field display
color and other field attributes is represented below. The program's procedure
accepts up to three parameters as input and returns the hex character that
is necessary to define the display field's attribute.
The first parameter is designed to reflect the color attribute. The second
parameter may be used to define an attribute other than color, such as UL
(underline) or RI (reverse image). The third parameter is used to determine
if the field is to be protected.
|
Fig.
1 |
The D specs (in Fig.1)
define the hex patterns that represent color and other attributes. The source
code performs some simple tests up front to determine how many parameters
have been passed. Since *OMIT is used in conjunction with *NOPASS, %ADDR
is used instead of %PARM to see if the first parameter was passed, because
*OMIT will be counted as a parameter even if it contains no value (null).
The body of the program logic sets the attributes and uses the %BITOR BIF
to manipulate the bits representing combinations of color, underline, reverse
image, and the protect attributes. The hex value passed back to the requesting
application will cause fields referencing the P-type variable to show the
resulting display attribute, defined by the bit-pattern.
To demonstrate the use of this application, first create a module from the
source:
(CRTRPGMOD MODULEMYLIB/UTDATRRI))
Then create a service program from the module:
CRTSRVPGM SRVPGM(MYLIB/UTDATRRI) EXPORT(*ALL) TEXT('Display attribute service
program') ACTGRP(QILE)
In most cases, a service program will have multiple procedures defined.
It is best to create a service source member to contain the procedures to
be exported rather than specifying EXPORT(*ALL) on the command. But for the
purpose of this example, and since this small service program contains only
one procedure, EXPORT(*ALL) will suffice when you create the object.
Next create a binding directory:
CRTBNDDIR BNDDIR(MYLIB/UTDATRRI) TEXT('Binding directory for display attributes')
Add a binding directory
entry: ADDBNDDIRE BNDDIR(MYLIB/UTDATRRI) OBJ((UTDATRRI *SRVPGM))
The binding directory serves as documentation and will allow you
to use the 'H' spec within your RPGLE program, simplifying the program creation.
|
Fig. 2 |
To test the service program, I created a simple display
file and a program. The source above (Fig. 2) is a small pop-up window display
file, UTDATRDP. This contains a record format to allow you to see the results
of the display attribute values applied as calls to the service program change
the program-to-system variable.
The display attribute of the field, Z$TXT1 is contained in the P-type field
DSPATR. The field value manipulated in the RPG program will contain the hex
representation of the display attribute, which defines how the device file
is to present the field, in normal, high-intensity or underlined and determines
whether the field is protected.
CRTDSPF FILE(MYLIB/UTDATRDP) RSTDSP(*YES)
The sample code below (Fig. 3) is a small RPG program using the display
and bound to the service program UTDATRRI. Compile the RPG program UTDATRRP
using the create bound RPG program command.
CRTBNDRPG PGM(MYLIB/UTDATRRP)
Since the 'H' spec contains the binding directory keyword, option 14 from
your PDM member list (CRTBNDRPG) is all you need to create the program --
if you've created the binding directory mentioned in the instructions above.
The test program is very simplistic, but does illustrate the basic relationship
between a bound process and a service program, prototyping the named procedure
from the service program it will use.
Call the program and press the enter key to see the results of the SetColor()
procedure as it is invoked by the test program. The procedure with the variable
parameter list makes manipulating the display attribute fairly simple. And
you won't have to remember the hex values for the various attributes you
need to apply to a field.
|
Fig. 3 |
With the service program in place, all I have to do
is SetColor() to define display attributes. That's all there is to it. Have
fun with it!
There are other hex values you might want to include in your service program,
such as column separators. If you chose to make a production application
from this source, you might want to put some more sophisticated validity
checking in the service program, such as a monitor block to manage exceptions,
and perhaps you might add an error return code to the parameter list.
I wouldn't recommend this technique to control individual error conditions
for a large number of screen fields on the same record format. It could get
confusing naming a large number of P-type fields and setting individual values
for a large number of fields. The technique could be effective, however,
where a screen has all the fields protected (view only) in one mode and unprotected
in an update mode. With the display attributes pointed to a common P-type
field, all the screen fields could be input-capable, or protected with just
a single line of RPG code (SetColor()) and no indicators.
In addition to the display attributes, the program also makes an interesting
use of procedure prototypes, demonstrating two very useful options, *OMIT
and *NOPASS. It is not usual to see the two used in conjunction. Just be
careful of how you test the parameters when using *OMIT, and remember to
use %ADDR instead of %PARMS to test whether a value has been passed or not.