In my last post, which you can see here, I wrote about defining files within subprocedures and I mentioned that you have to use a File data structure to read the record into. These are defined using the LIKEREC keyword when defining the data structure in the DCL-S (or Data Definition specification in fixed definitions). The LIKEREC defines which kinds of fields of the record are to be included in the data structure:
- LIKEREC(record_format:*INPUT) - input capable fields only
- LIKEREC(record_format:*OUTPUT) - output capable fields only
- LIKEREC(record_format:*ALL) - all fields
The examples I gave in my previous post were all for physical files. With physical files the fields tend to be both input and output capable.
That made me think which commonly used files contain something other than just input fields?
In a printer file the fields would all be output only. For my example I am going to use one of the subprocedures I wrote about in my last post.
01 dcl-proc Second ; 02 dcl-pi *n ind ; 03 end-pi ; 04 dcl-f TESTFILE keyed ; 05 dcl-ds F2 likerec(TESTFILER) ; 06 dcl-f TESTPRTF printer ; 07 dcl-ds F_Header likerec(ZHEADER:*output) ; 08 dcl-ds F_Line likerec(ZLINE:*output) ; 09 write ZHEADER F_Header ; 10 dow (1 = 1) ; 11 read TESTFILER F2 ; 12 if (%eof) ; 13 return *on ; 14 endif ; 15 eval-corr F_Line = F2 ; 16 write ZLINE F_Line ; 17 enddo ; 18 end-proc ;
Line 4: My physical file is defined as input, which is the default if the *USAGE keyword is not given for a physical or logical file.
Line 5: As not second parameter is given in the LIKEREC keyword *INPUT is assumed. Therefore, my file data structure, F2, will contain all the input capable fields from the record format TESTFILER.
Line 6: Using the *USAGE keyword when defining a printer file is unnecessary as it can only be used for output.
Line 7 and 8: These are my file data structures for two record formats in my printer file. These have to be defined as output, as there are only output capable fields in a printer file. If the second parameter is not given, input is assumed and the program will not compile, with a RNF7701 message "The data structure is not allowed for the operation."
Line 9: Writes the first line to the print file moving the values in the subfields of F_Header to the fields in the ZHEADER record format.
Line 11: In my Do-loop I am reading the record format TESTFILER into the data structure F2.
Line 15: As the fields in the record format TESTFILER and the printer file's record format ZLINE are the same I can use a EVAL-CORR to move them, en masse, from the one data structure to the other.
Line 16: Now I write the printer file's record format ZLINE using the subfields in F_Line to populate the fields in the record format.
So printer files are easy, all I have to do is to remember to define the LIKEREC for the data structures to be output.
The most commonly used file I can think of that has both input and output fields are display files. So I created a very simple display with input and output fields within it.
A DSPSIZ(24 80 *DS3) A INDARA A CA03(03 'F3=Exit') A R SCREEN A 2 3'Both (in & output) .' A F001 3A B 2 24 A 3 3'Input only . . . . .' A F002 3A I 3 24 A 4 3'Output only . . . :' A F003 3A O 4 24
F001 is both input and output, FLD002 is input only, and FLD003 is output only.
Here is my RPG subprocedure to use that display file. I know there is some odd redundant code within it, but I will explain why later.
07 dcl-proc DisplayFile ; 08 dcl-pi *n ind ; 09 end-pi ; 10 dcl-f TESTDSPF workstn indds(IndDs) ; 11 dcl-ds F_Input likerec(SCREEN:*input) ; 12 dcl-ds F_Output likerec(SCREEN:*output) ; 13 dcl-ds F_All likerec(SCREEN:*all) ; 14 dcl-ds IndDs ; 15 Exit ind pos(3) ; 16 end-ds ; 17 F_All.F001 = '1' ; 18 F_All.F002 = '1' ; 19 F_All.F003 = '1' ; 20 exfmt SCREEN F_All ; 21 F_Output.F001 = '2' ; 22 F_Output.F003 = '2' ; 23 write SCREEN F_Output ; 24 read SCREEN F_Input ; 26 return *on ; 27 end-proc ;
Line 10: Those of you who are regular readers of this blog not that I use the Indicator Data Structure to handle indicators between the display file and the RPG program. The INDDS keyword defines the name of my Indicator data structure, which you can see on lines 14 – 16.
Lines 11 – 13: I have defined three File data structures, one for input, one for output, and the last for all. This is so I can show how they contain different subfields, based on how the fields are defined in the display file's source code.
When I compiled this code I can see how those three data structures are defined:
F_ALL DS(9) F001 A(3) F002 A(3) F003 A(3) F_INPUT DS(6) F001 A(3) F002 A(3) F_OUTPUT DS(6) F001 A(3) F003 A(3)
The data structure F_All contains all three fields, regardless of their type.
As F_Input only contains the input capable fields it contains F001, the field defined as both, and F002, which is the input only field.
F_Output has the output capable fields FLD001 and FLDD03.
What happens when I run this program?
Line 17 – 20: After moving "1" to all of the screen fields to F_All and then EXFMT the record format the following is displayed:
Both (in & output) . 1__ Input only . . . . . ___ Output only . . . : 1
There is no value in the Input field it is for input only, for the "1" to appear the field would have had to be coded at least as both input and output capable.
Before I discuss the next part of the program I want to ask you a question: What is an EXFMT?
Yes, it does display the display file's record format, but it is a combination of two operations: a write followed by a read. I could, if I want to use write and read operations in place of the EXFMT. In my experience of COBOL on the IBM i it does not have a EXFMT equivalent, I have to write and read the display file's record format. COBOL uses an output buffer for the write, and an input buffer for the read. I can do the same in RPG by using separate File data structures, one defined for output, F_Output, and the other for input, F_Input.
Lines 21 – 23: Using F_Output as my output buffer I can load values in the data structure's subfields and then pass them to the display file's record format using the data structure. My display file would look like this:
Both (in & output) . 2__ Input only . . . . . ___ Output only . . . : 2
When I change the values of the fields on the screen:
Both (in & output) . 3__ Input only . . . . . 3__ Output only . . . : 2
And press Enter the "input buffer", F_Input data structure, looks like:
EVAL F_Input F_INPUT.F001 = '3 ' F_INPUT.F002 = '3 '
I think that has covered the main scenarios I have to read, write, and update files. I am sure there are other more obscure ways of defining fields within files, and by using any combination of the examples I have given in these last two posts should give you the information to cope with them.
You can learn more about the LIKEREC keyword in RPG from the IBM website here.
This article was written for IBM i 7.2, and should work for earlier releases too.