I recently taught an advanced RPG course. At one of the coffee breaks I overheard an interesting conversation between some of the students. They were discussing the merits of no longer using indicators in RPG IV. That's not the first time I've heard this (and probably not the last), and it is a common misconception.
Indicators are a lot more powerful in RPG IV, and we should use them more -- not less. What we should be giving up is the use of the RPG indicators (*INxx). Let's take a look at how the use of indicators has changed in RPG IV.
The problem was that RPG had only a set of predefined indicators. There were indicators for specific functions (*INKx for function keys, *INOx for overflow, *INLx for level breaks etc.) and the 99 indicators *IN01 to *IN99 for our own use.
Traditionally, there were a number of places where indicators had to be used:
- Resulting indicators for certain operation codes
- Conditioning and resulting indicators for display files and print files
It was up to us to determine what any indicator meant. And therein lay the problem. We were dependant upon the implementation of standards and good documentation to be able to determine the function of an indicator.
What has changed?
RPG IV saw the introduction of the following:
- Named Indicators
- Logical Expressions
- Built-In Functions (BIFs)
- The Indicator Data Structure (INDDS)
That means the only RPG indicator we may have to use is *INLR!
Indicators are now a recognized data type in RPG, so we can define them in the D Specs, as shown below. Note that when testing an indicator you do not need to compare it against *ON or *OFF.
DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++ D BadStatus S N D MonthEnd S N
The below code shows a named indicator being used for printer overflow. This is a simple example of the benefit of a named indicator; the name Overflow is more self-explanatory than *IN96 or *INOV. Also, you don't need to define the Overflow indicator in the D Specs; the compiler will define it for you.
FReport O E Printer OflInd(OverFlow) Write Detail; If OverFlow; Write Header; OverFlow = *Off; EndIf;
The below code shows the traditional means of setting an indicator; it should look familiar. It is setting an error condition if it is a month end and if the status is neither 'I' nor 'C'. At least I think it is setting an error condition; that is what indicator 31 is -- right?
*In31 = *Off; If EndMonth = 'Y'; If Status <> 'I' and Status <> 'C'; *In31 = *On; EndIf; EndIf;
And below you'll the same piece of code as a logical expression. The result of a logical expression is true or false, therefore it can be assigned directly to an indicator. Also, the EndMonth field has been replaced by the indicator MonthEnd, and *IN31 has been replaced by the indicator BadStatus.
If MonthEnd; BadStatus = (Status <> 'I' and Status <> 'C'); EndIf;
We no longer need to use resulting indicators on operation codes. Instead, we can use the relevant I/O BIF. The I/O BIFs are %OPEN, %FOUND, %EOF, %ERROR, %EQUAL and %STATUS. The code below shows an example of using the %OPEN, %ERROR and %FOUND BIFs. The %OPEN BIF indicates whether or not the file is open. The %ERROR BIF is set when the E extender is defined on an operation code (Chain in this case). We use the E extender in place of an error indicator in the low position. The %FOUND BIF is set automatically by the Chain operation.
If %Open(FileB); Chain(E) Key FileB; Select; When %Error; Dsply 'File Error'; When %Found(FileB); Dsply 'Got It'; EndIf; EndIf;
One of the nice things about %FOUND is that it reads the right way round, as opposed to the indicator on the CHAIN operation where the indicator is true if the record is NOT found.
Indicator Data Structure
By default, the indicators 01 to 99 on a display or print file are mapped to the indicators 01 to 99 in an RPG program. But when we use the file keyword INDDS (Indicator Data Structure), they are mapped to a data structure instead of the indicators. In other words, the 99 indicators used with the display or print file are now associated with the data structure instead of the indicators *IN01 to *IN99 in the program.
The code below shows an example of using the INDDS. The indicators for the display file are mapped to the data structure DspInd. DspInd is a 99 byte data structure, with each byte corresponding to one of the 99 indicators for the display file. This means that for the display file, we MUST use the indicators in the data structure and NOT the numbered indicators. For example, in this program, if we turned on indicator *IN31, it would have no impact on the display file. The program logic must refer to the indicator Error in order to have an impact on the display file. Named indicators are a lot easier to decipher!
FDisplay CF E WORKSTN INDDS(DspInd) D DspInd DS * Response indicators D F3Exit 3 3N D F12Cancel 12 12N * Conditioning indicators D AllErrors 31 33 D Error 31 31N D StDateErr 32 32N D EndDateErr 33 33N Eval AllErrors = *Zeros; StDateErr = StartDate < Today; EndDateErr = EndDate < StartDate; Error = StDateErr or EndDateErr; ExFmt MyScreen; If F3Exit or F12Cancel;
The use of INDDS requires the use of the file level keyword INDARA in the DDS for the display/print file. In most cases, changing a file to use INDARA will have no effect unless a RESET or CLEAR operation is used. In this case it will now be necessary to also RESET/CLEAR the associated indicators.
The point is that we should stop using RPG indicators but start using named indicators. They are self-documenting and much easier to use. Indicators now have a totally new meaning in RPG.
About the author: Paul Tuohy is CEO of ComCon, an iSeries consulting company. He is the author of Re-Engineering RPG Legacy Applications and is one of the quoted industry experts in the IBM Redbook "Who Knew You Could Do That With RPG IV?"