All of the examples of subfiles I have given in previous posts have been "load all" subfiles. The subfile size is at the maximum, 9,999 records, and the entire subfile is loaded all at once. When loaded the display file controls the scrolling up and down within it, without any need for code in the program.

If give a "position to" field when a value is entered in it the subfile is reloaded starting at the nearest matching record and continuing onto the end of the subfile or available records from the input file. When I have presented this to users they have understood that if they enter "Hutchinson" then the subfile will start at the closest match. If they wanted the name "Hughes", rather than "Hutchinson", they would change the value in the "position to" field rather than expect to be able to page up through subfile records less than the value "Hutchinson" until they reached "Hughes".

In my experience of working with users, in many different companies, they understood and have been satisfied with this functionality. When I have given examples in this blog I receive messages telling me that this is not acceptable, the users must be able to page up to values less than "Hutchinson". I have until now ignored these complaints as they are from IT people, not from the people who use these subfile programs every day.

Today I relent, and am giving my version of a program that would allow people to page up to records before that entered in a "position to". To accomplish this I need to use a different type of subfile, a "screen at a time" subfile. This type of subfile will only load the same number of records that are displayed on the screen. If either the page up or page down keys is pressed the program has to reload the subfile with data.

It has been so many years since I created a "screen at a time" subfile I had to find an example to use. This is based upon an example I found from IBM written in RPG3.

This subfile will display a list of names taken from the PERSONP file. I will display the names in key order, and concatenate them for display. The source for the file is simple enough that I am not going to explain it in detail.

01 A R PERSONR 02 A FIRSTNAME 25A 03 A LASTNAME 30A 04 A K LASTNAME 05 A K FIRSTNAME

You have seen the file level keywords for the display file in many of my examples.

01 A DSPSIZ(24 80 *DS3) 02 A PRINT 03 A INDARA 04 A ERRSFL 05 A REF(PERSONP) 06 A CA03(03 'F3=Exit')

Line 3: As with all display files I use with RPG program I use the Indicator Area to convert the display's indicators to an indicator data structure in the RPG program.

Line 4: I always use the error subfile to display messages. Why not let have the display file handle any errors, rather than write a message subfile to do the same thing?

Line 5: I am referencing the PERSONP file so I do not have to give lengths and field types to fields from that file in this display file.

Line 6: The F3 key uses indicator 3. I know that sounds strange I would bother to mention that, but I could use any indicator. In my opinion it would not be wise to do so, but I could.

The display file consists of three record formats:

Subfile Subfile control Footer

The subfile is really simple.

07 A R SFL01 SFL 08 A ZRRN 2S 0H 09 A NAME 40A O 5 3 10 A LASTNAME R H 11 A FIRSTNAME R H

Line 8: The subfile relative record number only needs to be two numeric as the subfile size is only 10 (see when I describe the subfile control).

Line 9: This is the field that will contain the concatenated last and first names.

Lines 10 and 11: I want to have the last and first name fields in the subfile record too, I will describe in the RPG program why. Notice that they are hidden, like the subfile relative record number, so they will not be displayed when the subfile is shown.

The subfile control record is different from that of a "load all" type subfile.

12 A R CTL01 SFLCTL(SFL01) 13 A SFLSIZ(0010) 14 A SFLPAG(0010) 15 A OVERLAY 16 A PAGEDOWN(25) 17 A PAGEUP(26) 18 A 30 SFLDSPCTL 19 A 31 SFLDSP 20 A 32 SFLEND(*MORE) 21 A 33 SFLCLR 22 A 1 8'R P G P G M . C O M' 23 A 2 2'Screen at a time subfile+ example' 24 A 3 2'Position to' 25 A ZPOSITION R B 3 14REFFLD(LASTNAME) 26 A 4 3'Person name'

Lines 13 and 14: The subfile size and page are the same, only 10 records.

Lines 16 and 17: In a "screen at a time" subfile I need to perform all the processing for page up and down, therefore, I need to use these keywords to assign indicators to these functions. In older display files you may see ROLLDOWN and ROLLUP instead, but as I do not have an old fashioned 5250 terminal keyboard, the keys on my keyboard are labelled PgUp and PgDn .

Lines 18 – 21: This are the indicators I will be using in the RPG program to initialize and display the subfile.

Line 25: The "position to" field is defined to be the same as the last name field from the PERSONP file.

I use the footer record format just to display what keys can be used with this subfile.

27 A R FOOT01 28 A 23 3'F3=Exit'

And now to the RPG program, let me start with the definitions.

01 **free 02 ctl-opt option(*nodebugio:*srcstmt:*nounref) dftactgrp(*no) ; 03 dcl-f DSPFILE workstn indds(Dspf) sfile(SFL01:ZRRN) ; 04 dcl-ds Dspf qualified ; 05 Exit ind pos(3) ; 06 PageDown ind pos(25) ; 07 PageUp ind pos(26) ; 08 SflInds char(4) pos(30) ; 09 SflDspCtl ind pos(30) ; 10 SflDsp ind pos(31) ; 11 SflEnd ind pos(32) ; 12 SflClr ind pos(33) ; 13 end-ds ; 14 dcl-f PERSONP disk keyed ; 15 dcl-s SflSize like(ZRRN) inz(10) ; 16 dcl-s SavedPosition like(ZPOSITION) ;

Line 1: You know that I am going to write this in totally free RPG.

Line 2: My favorite control options make it easier to debug this program and reduce the size of the final object. I need the DFTACTGRP as I am using procedures within this program.

Line 3: The definition of the display file, I described above. The INDDS keywords is the other "side" of the indicator area I used in the display file. It allows me to redefine number indicators to have really meaningful names.

Lines 4 – 13: This is the redefinition of the display file's number indicators to have real names. As the data structure is qualified the subfields will need to be used prefixed with the data structure names.

Lines 8 – 12: This might confuse some. These are the indicators used to control the display, etc., of the subfile. Each indicator has an individual subfield name, lines 9 – 12. But I have also defined a character subfield, SflInds which overlays those indicators. More on why I did this later in the program.

Line 14: Definition of the input file, PERSONP .

Line 15: I have created this field to contain the maximum number that the subfile can have. I will use this variable rather than the hard-coded number. If in the future I decide to change the number of subfile records I can just change the initialized value here, not have to search the source code for where the maximum number of subfile records is used.

Line 16: I am defining this variable to hold the last value that was entered into the "position to" field. This way I can tell if the value in the "position to" has been changed.

On to the "main body" of the program.

17 SubfileDown() ; 18 dow (1 = 1) ; 19 write FOOT01 ; 20 exfmt CTL01 ; 21 if (Dspf.Exit) ; 22 leave ; 23 elseif (Dspf.PageDown) ; 24 if not(Dspf.SflEnd) ; 25 SubfileDown() ; 26 endif ; 27 elseif (Dspf.PageUp) ; 28 SubfileUp() ; 29 elseif (ZPOSITION <> SavedPosition) ; 30 setll ZPOSITION PERSONR ; 31 SubfileDown() ; 32 SavedPosition = ZPOSITION ; 33 endif ; 34 enddo ; 35 *inlr = *on ;

Line 17: Call the procedure for the page down, to perform the initial load of the subfile.

Line 21: If the F3 keyed is pressed on the screen then indicator Dspf.Exit , mapped in the indicator data structure, is on and I know to exit this Do loop.

Line 23: If the page down is pressed, see how much easier to know what this indicator is used for, I don't want to reload the subfile is I am displaying the last set of records. If the subfile end indicator, Dspf.SflEnd line 24, is on then I know I have reached the last set and am not going to do another page down routine, line 25. If it is not then I need to load the subfile with the next set of records from the file.

Line 27: If the page up was pressed I need to "move up" through the file to get the previous ten records. I do that in the SubfileUp procedure, line 28.

Line 29: I only need to perform the "position to" logic if the value in the screen field is different from that in the saved field, defined on line 16. If it has been used I need to position the file to the value in the position to field, line 30, and then execute the procedure that loads the subfile, line 31. When that is complete I need to move the value of the position to display file field to the saved position to variable, line 32.

The first procedure used by the program, SubfileDown , is the one that loads the subfile.

36 dcl-proc SubfileDown ; 37 Dspf.SflInds = '0001' ; 38 write CTL01 ; 39 Dspf.SflInds = '1000' ; 40 for ZRRN = 1 to SflSize ; 41 read PERSONR ; 42 if (%eof) ; 43 Dspf.SflEnd = *on ; 44 leave ; 45 endif ; 46 NAME = %trimr(LASTNAME) + ', ' + FIRSTNAME ; 47 write SFL01 ; 48 endfor ; 49 if (ZRRN > 1) ; 50 Dspf.SflDsp = *on ; 51 else ; 52 return ; 53 endif ; 54 if not(Dspf.SflEnd) ; 55 read PERSONR ; 56 if (%eof) ; 57 Dspf.SflEnd = *on ; 58 else ; 59 setll (LASTNAME:FIRSTNAME) PERSONR ; 60 endif ; 61 endif ; 62 end-proc ;

Lines 37 – 39: Now you see why I created the subfield Dspf.SflInds . On line 37 I turn off indicators SflDspCtl , SflDsp , and SflEnd , and turn on SflClr so I clear the subfile when I write the subfile control on line 38. On line 39 I just turn on the indicator to display subfile control indicator, and leave the others off. That is a more efficient way to set these indicators without having to turn each one on or off individually.

Line 40: I use a For group to control the number of time I read the input file, PERSONP . The For will increment the value in the subfile relative record field, ZRRN until it reaches the value in the variable I defined to contain the number of records in the subfile.

Line 41: I read the file.

Lines 42 – 45: If I encounter the end of file I set on the indicator that is used to control whether "More" or "Bottom" is displayed. I then exit the For group.

Line 46: I concatenate the last and first name fields to make the name.

Line 47: When I write the subfile record remember that the last and first name fields are also included.

Line 49: After exiting the For group I test if any records were written to the subfile. If some where I set on the subfile display indicator, Dsp.SflDsp , line 50. If no records were written I return from this procedure to the "main body", line 52.

Line 54 – 61: One of the problems of using a "screen at a time" subfile is determining when the last record was read from the file, and turn on the end of subfile indicator. I have to read one more record to determine if the last record written was at the end of the file, line 55. If end of file was encountered, line 56 and 57, I set on the end of subfile indicator. If end of file was not encountered, lines 58 and 59, I need to reset the file pointer to just before the record that was read by using a SETLL .

Next procedure is the one used if the page up key was pressed to display records before the one on the current subfile.

63 dcl-proc SubfileUp ; 64 chain 1 SFL01 ; 65 setll (LASTNAME:FIRSTNAME) PERSONR ; 66 for ZRRN = 1 to SflSize ; 67 readp PERSONR ; 68 if (%eof) ; 69 leave ; 70 endif ; 71 endfor ; 72 setll (LASTNAME:FIRSTNAME) PERSONR ; 73 SubfileDown() ; 75 end-proc ;

Line 64: I am chaining to get the file's key fields from the first record of the current subfile.

Line 65: I use SETLL the set the file pointer just before the first record that was in the subfile.

Line 66: Another For group that does the same thing as the last one. It loops the same number of times as the size of the subfile.

Line 67: In this situation I need to read "backwards" to where the start of the "previous" subfile should be, I do this using the read prior operation code, READP .

Lines 68 – 70: If I encounter end of file, well really beginning of file, before I finish performing the For loop I exit.

Line 72: I use SETLL to position the file pointer just before the last record I read, which is going to be the first record of the subfile.

Line 73: I call the procedure SubfileDown to fill the subfile.

What does this look like when I call the program:

R P G P G M . C O M Screen at a time subfile example Position to Person name ALLEN, REG ASTON JR, JOHN BENNION, RAYMOND BERRY, JOHNNY BIRCH, BRIAN BLANCHFLOWER, JACKIE BOND, ERNEST BULLOCK, JAMES BYRNE, ROGER CAREY, JOHNNY More... R P G P G M . C O M Screen at a time subfile example Position to Person name HILDITCH, LAL HOPKINSON, SAMUEL JONES, MARK JONES, THOMAS LYDON, GEORGE MCGLEN, WILLIAM MCLENAHAN, HUGH MCNULTY, THOMAS MCSHANE, HAROLD MELLOR, JACK More... R P G P G M . C O M Screen at a time subfile example Position to Person name PARKER, THOMAS PEARSON, STAN RAMSDEN, CHARLES REDMAN, BILLY ROWLEY, JACK SILCOCK, JACK STEWARD, ALFRED WALTON, JOHN WHITEFOOT, JEFFREY WILLIAMS, FRANK More... R P G P G M . C O M Screen at a time subfile example Position to Person name WILSON, JACK Bottom

When I enter "M" into the position to field and press Enter the subfile is position to the first record in the file with a last name that starts with "M".

R P G P G M . C O M Screen at a time subfile example Position to M Person name MCGLEN, WILLIAM MCLENAHAN, HUGH MCNULTY, THOMAS MCSHANE, HAROLD MELLOR, JACK PARKER, THOMAS PEARSON, STAN RAMSDEN, CHARLES REDMAN, BILLY ROWLEY, JACK More...

When I press the page up key the subfile is loaded with the ten records from the file that were before the pattern I entered.

R P G P G M . C O M Screen at a time subfile example Position to M Person name CROMPTON, JACK DALE, WILLIAM DOWNIE, JOHN GALLIMORE, STANLEY GIBSON, DONALD HILDITCH, LAL HOPKINSON, SAMUEL JONES, MARK JONES, THOMAS LYDON, GEORGE More...

In my opinion this is just silly. If wanted to see the people with the last name that started with "L" I would have entered "L" in the position to field instead.

The real problem I have with "screen at a time" subfiles versus the "load all" type is that if I page up, down, up, and down continuously I have performed a large number of reads of the same records from the file, wasting I/O resources, just to display the same data.

This article was written for IBM i 7.3, and should work for some earlier releases too.