Anatomy of a P-Field
October 13, 2004 Dominic Lefevre
It may appear that text-based screens are dead, but looks can be deceiving. Text-based interfaces, or “green screens,” are still very widely used, and not just on iSeries systems. What’s more, text-based systems are not going away anytime soon, because they’re effective and easy to develop. As long as we still have to write them, we might as well have a little fun, right? One of the ways to have fun writing green-screen programs is by using P-fields.
LOOK, MA, NO INDICATORS!
P-fields are one-byte codes that control the color and attributes of a field in a display file. Before P-fields were added to data description specifications (DDS), it was necessary for a programmer to make decisions about color and attributes during development. Whichever attributes were selected had to be included in the DDS. To apply different attributes to a field in different circumstances required the use of conditioning indicators.
In the following example, the NAME field is shown in blue. ADDRESS appears in white and will be underlined if indicator 11 is on. The color and attributes of the PHONE field depend on the setting of indicators 12, 13, 15, and 16. Yuck!
A NAME 20A O 10 6COLOR(BLU) A ADDRESS 20A O 11 6COLOR(WHT) A 11 DSPATR(UL) A PHONE 12A O 12 6 A N15N16 COLOR(BLU) A N15 16 COLOR(RED) A 15N16 COLOR(PNK) A 15 16 COLOR(WHT) A 12 DSPATR(RI) A 13 DSPATR(UL)
It works, but it’s hardly any fun. Besides, I don’t like indicators 11, 12, 13, 15, and 16. (I don’t like any of the other indicators, either.) So let me tell you about P-fields.
P-fields allow you to determine color and attributes at run time without using indicators. Load a P-field with a character in one of two ranges–hexadecimal 20 through 3F or hexadecimal A0 through BF–and the system takes care of the rest. These hex values and their meanings are listed under the discussion of the DSPATR keyword in the DDS reference, which you can find on IBM’s iSeries Infocenter. Notice that P-fields can’t be used for attributes MDT (modified data tag), OID (operator idenfication), PC (position cursor), and SP (select by light pen).
In the following display file fragment, the NAME field’s attributes are controlled by the value in the NAMEATTR field.
A NAME 20A B 10 6DSPATR(&NAMEATTR) A NAMEATTR 1A P
Notice the usage entry of P for the NAMEATTR field. This tells the system that NAMEATTR is a P-field.
One way an RPG program might load a value into a P-field is by assigning a hexadecimal literal, like this:
nameattr = x'28';
The hex 28 value causes the field to blink on a dumb terminal and to be displayed in red on a not-quite-so-dumb terminal. That’s not obvious enough for my tastes. The source code will be more readable if you assign a named constant to the P-field, like this:
D Blink C Const(x'28') NameAttr = Blink;
But the P-field value does not have to be hard-coded in the program’s source code. It could be stored in a file or data area, passed into a program through a parameter, assigned a value according to user input, and so on.
In the following example, the P1 variable is initialized by a calling program and passed to this program through a parameter.
D Dspatr2r PR ExtPgm('CALLEDPGM') D p1 1A D Dspatr2r PR D p1 1A /free NameAttr = p1;
Here the P1 value is retrieved from a data area.
D DspAttrs DS 32 DtaAra(DspAttrs) D p1 1 1A /free In DspAttrs; NameAttr = p1;
How did the appropriate value get into the data area? Someone put it there.
CHGDTAARA DTAARA(DSPATTRS) VALUE(X'28')
Let your imagination run wild a minute and think about the possibilities.
THE MEANING OF A P-FIELD VALUE
There is a method to the madness of P-fields. Each of the eight bits has a meaning, or at least each bit had a meaning, before color terminals came along. Table 1 applies to monochrome terminals, which were usually green or amber text on a blank background.
Bit(s) | Meaning |
0 | 1 = protected |
1 | Always 0 |
2 | Always 1 |
3 | 1 = column separators |
4 | 1 = blink |
5 | 1 = underlined |
5-7 | 111 = non-display |
6 | 1 = high intensity |
7 | 1 = reverse image |
Table 1: Bit definitions for P-field values on monochrome monitors
Bits are numbered 0 to 7 from beginning to the end. If the first bit is on, the field will be protected. That is, the user won’t be able to key into it. If you want a field to blink, turn on the fifth bit.
Things are not so nice and tidy in the world of color monitors. IBM retrofitted colors to the 5250 data stream without expanding the size of P-fields. As a result, there are not enough eligible bit patterns to handle all combinations of colors and display attributes. For example, if you want a field to blink, you have to display it in red. None of the other colors supports blinking. If you ask for yellow or turquoise, you get column separators whether you want them or not.
Nevertheless, you can still derive certain generalities by examining the P-field values for color monitors, as Table 2 shows.
Bit(s) | Meaning |
0 | 1 = protected |
1 | Always 0 |
2 | Always 1 |
2-4 | 110 = column separators |
5 | 1 = underlined |
5-7 | 111 = non-display |
7 | 1 = reverse image |
Table 2: Bit definitions for P-field values on color monitors
MEET %BITOR
Ready to have a little fun with P-fields? Say hello to the %BITOR function. Chances are you’ve never used this function before, but it comes in very handy when you’re working with P-fields. The %BITOR lets you combine colors and attributes.
Since attributes of monochrome monitors are more sensible than those of color monitors, let me begin with a monochrome illustration. Here are the monochrome values from Table 1 defined as hexadecimal constants.
D Normal C Const(x'20') D Protect C Const(x'80') D ColSep C Const(x'10') D Blink C Const(x'08') D Underline C Const(x'04') D Hi C Const(x'02') D Reverse C Const(x'01') D NonDisplay C Const(x'07')
In the following code fragment, the blink, high intensity, and protect attributes are applied to P-field NAMEATTR depending on various conditions.
NameAttr = Normal; If PaymentIsOverdue; NameAttr = %BitOr(NameAttr:Blink); EndIf; If CustomerType = 'A'; NameAttr = %BitOr(NameAttr:Hi); EndIf; If Mode = 'INQUIRY'; NameAttr = %BitOr(NameAttr:Protect); EndIf;
The result of executing this code is that the fields conditioned by NAMEATTR may be displayed in normal mode or in any combination of the blink, high intensity, and protect attributes, all without indicators.
But we don’t use monochrome monitors where I work, so here’s an example using color monitors. Since all colors won’t combine with all attributes, you have fewer choices, but protect, reverse image, underline, and nondisplay are safe.
In this example, text comments are stored in physical file COMMENTS. These comments are displayed within various programs as needed, to provide instructions. Here is the unembellished DDS definition of the COMMENTS file.
A UNIQUE A R COMMENTREC A ID 8 A SEQUENCE 3P 0 A TEXT 78 A COLOR 3 A UNDERLINE 1 A REVERSE 1 A K ID A K SEQUENCE
The ID field contains a common value for each set of related comments. The SEQUENCE field defines the order in which the comments within a set are to be displayed. The COLOR, UNDERLINE, and REVERSE fields define the formatting that is to be applied to the comment text.
The following display file DDS fragment shows that the text is to be displayed in a subfile. The subfile’s text field is controlled by a P-field.
A R SFL SFL A SFLTEXT 78 B 6 2DSPATR(&SFLTEXTATR) A SFLTEXTATR 1A P
The following demonstration RPG program shows how a comment set is loaded with the soft-coded display attributes applied to the comment text.
FComments IF E K Disk Prefix(Cmt) FCommentdf CF E Workstn SFile(Sfl:RRN) D CommentRG PR ExtPgm('COMMENTRG') D parmCmtSet 8A Const D parmMode 3A Const D CommentRG PI D parmCmtSet 8A Const D parmMode 3A Const D RRN S 4S 0 D CmtKeys DS LikeRec(CommentRec:*Key) D Blue C Const(x'3A') D Green C Const(x'20') D Pink C Const(x'38') D Red C Const(x'28') D Turquoise C Const(x'30') D White C Const(x'22') D Yellow C Const(x'32') D Protect C Const(x'80') D Reverse C Const(x'01') D Underline C Const(x'04') /Free CmtKeys.CmtID = parmCmtSet; SetLL %kds(CmtKeys:1) CommentRec; DoW '1'; ReadE %kds(CmtKeys:1) CommentRec; If %EOF; Leave; EndIf; SflText = CmtText; Select; When CmtColor = 'BLU'; SflTextAtr = Blue; When CmtColor = 'PNK'; SflTextAtr = Pink; When CmtColor = 'RED'; SflTextAtr = Red; When CmtColor = 'TRQ'; SflTextAtr = Turquoise; When CmtColor = 'WHT'; SflTextAtr = White; When CmtColor = 'YLW'; SflTextAtr = Yellow; Other; SflTextAtr = Green; EndSl; If CmtUnderline = 'Y'; SflTextAtr = %BitOr(SflTextAtr:Underline); EndIf; If CmtReverse = 'Y'; SflTextAtr = %BitOr(SflTextAtr:Reverse); EndIf; If parmMode <> 'CHG'; SflTextAtr = %BitOr(SflTextAtr:Protect); EndIf; RRN += 1; Write Sfl; EndDo; ExFmt Ctl; *inLR = *On; /End-Free
The comment set to be loaded is the one indicated by the value in the first parameter. As each of the set’s records are read, the appropriate color and display attributes are applied. Notice that the %BITOR function adds attribute bits as needed.
The second parameter indicates whether the comments may be changed. In the interest of keeping the example short, I omitted the necessary logic to update the comments file. My only purpose in adding this parameter to this example was to include a test for the PROTECT attribute.
SAY GOODBYE TO INDICATORS
P-fields are a superior alternative to indicators. Using P-fields with named constants that represent display attributes results in clearer code. P-fields can be stored in external objects like files and data areas or passed to a program through parameters.
However, that does not mean you should use P-fields only. Having to create a P-field for every data field on a display can get unwieldy. If a field always has a certain color or display attribute (it’s always underlined, for example), it may not be worth the trouble to use a P-field. But for those times when you need more flexibility, P-fields are the way to go.