|
Page 1 of X
Hey, Ted:
We know how to number pages on a report.
We'd like to be able to show the total number of pages
on each page. For instance, we'd like to see something
such as Page 2 of 9.
Any ideas on how we might accomplish that?
-- Jean
Can you predict the number of pages that will be generated?
For example, if you know that each page will contain output
from 40 input records, and you know that there are 235
input records, you can predict that there will be six pages
of output. The Number of Current Records (NBRCURRCD)
parameter of the Retrieve Member Description (RTVMBRD)
command may tell you the number of input records. I say
"may" because this technique only works if your program
is reading all input records.
If you can't predict the number of pages of output, you'll
have to wait until the spooled file is generated, then
update the report. The Retrieve Spooled File Attributes
(QUSRSPLA) API can tell you the number of pages in a
spooled file.
DCL &PAGES *DEC 5
DCL &WHICHSPLF *CHAR 4
DCL &RCVLEN *CHAR 4
DCL &RECEIVER *CHAR 144
/* Get number of pages produced by report */
CHGVAR VAR(%BIN(&WHICHSPLF)) VALUE(-1)
CHGVAR VAR(%BIN(&RCVLEN)) VALUE(144)
CALL PGM(QUSRSPLA) PARM(&RECEIVER &RCVLEN +
'SPLA0100' '*' ' ' ' ' QSYSPRT &WHICHSPLF)
CHGVAR VAR(&PAGES) VALUE(%BIN(&RECEIVER 141 4))
QUSRSPLA has nine parameters, but you don't have to put
values in all of them and you can omit the last one.
- Receiver variable -- a data structure to contain data
about the spooled file
- Length of receiver variable
- Format name -- SPLA0100 has everything you need
- Qualified job name -- a single * means the current job
- Internal job identifier -- ignore
- Internal spooled file identifier -- ignore
- Spooled file name
- Spooled file number -- -1 means the last spool file
of that name
- Error code -- ignore
Here's some CL code that might work for you. It performs
the following functions:
- calls a program that generates a report, leaving the
special character sequence :P:G: after the word "of".
- calls QUSRSPLA to find out how many pages are in the
report,
- copies the spooled file to a database file,
- calls RPG program UPDTPAGE, which replaces :P:G: with
the total number of pages
- rebuilds the spooled file from the updated disk file.
PGM
DCL &PAGES *DEC 5
DCL &WHICHSPLF *CHAR 4
DCL &RCVLEN *CHAR 4
DCL &RECEIVER *CHAR 144
/* Run a program that creates a report with file QSYSPRT */
/* It should number pages like this: Page xxx of :P:G:
CALL PGM(somepgm)
/* Get number of pages produced by report */
CHGVAR VAR(%BIN(&WHICHSPLF)) VALUE(-1)
CHGVAR VAR(%BIN(&RCVLEN)) VALUE(144)
CALL PGM(QUSRSPLA) PARM(&RECEIVER &RCVLEN +
'SPLA0100' '*' ' ' ' ' QSYSPRT &WHICHSPLF)
CHGVAR VAR(&PAGES) VALUE(%BIN(&RECEIVER 141 4))
/* Copy the report to a database file */
CRTPF FILE(QTEMP/SPOOLFILE) RCDLEN(133)
MONMSG MSGID(CPF7302)
CPYSPLF FILE(QSYSPRT) TOFILE(QTEMP/SPOOLFILE) +
SPLNBR(*LAST) MBROPT(*REPLACE) CTLCHAR(*FCFC)
/* Update the number of pages */
OVRDBF FILE(SPOOLFILE) TOFILE(QTEMP/SPOOLFILE)
CALL PGM(UPDTPAGE) PARM(&PAGES)
DLTOVR FILE(SPOOLFILE)
/* Rebuild the spooled file */
OVRPRTF FILE(QSYSPRT) CTLCHAR(*FCFC)
CPYF FROMFILE(QTEMP/SPOOLFILE) TOFILE(QSYSPRT)
DLTOVR FILE(QSYSPRT)
ENDPGM
Here's the RPG program that replaces :P:G: with the number
of pages:
* Replace :P:G: with total number of pages in a report
*
FSpoolFile UF f 133 disk
D PrtLine ds
D PrtImage 2 133
D UpdtPage pr ExtPgm('UPDTPAGE')
D NbrOfPages 5p 0
D AlphaPage s 5
D Pos s 10i 0
* *Entry parameters
D UpdtPage pi
D NbrOfPages 5p 0
C eval AlphaPage =
C %triml(%editc(NbrOfPages:'3'))
C read SpoolFile PrtLine
C dow not %eof
C eval Pos = %scan(':P:G:' : PrtImage)
C if Pos > *zero
C eval %subst(PrtImage : Pos : 5) = AlphaPage
C update SpoolFile PrtLine
C endif
C read SpoolFile PrtLine
C enddo
C eval *inlr = *on
You need to take the code and adapt it for your situation.
To make it easier for you to use try this program on your system,
here's something you should be able to compile and run with no
modification. It adds total pages to the output of the Display
Job (DSPJOB) command. It uses the same techniques as the code
given above, but instead of scanning for :P:G:, it looks for the
word PAGE. You could probably use this support with many existing
reports. There is a risk that PAGE may appear on your report
somewhere in the body of your report. To minimize this risk, the
scan uses a starting column that is set when the first instance
of the scan string is located.
First, the CL program, DSPJOB01C. Use Create Bound CL Program
(CRTBNDCL) and compile it to run in the default activation group:
/* Demonstrate the use of a text replacement program to */
/* replace Pagexxxx with Pagexxxx of yyyy. */
PGM
DCL &PAGES *DEC 5
DCL &SPLNBR *DEC 5
DCL &WHICHSPLF *CHAR 4
DCL &RCVLEN *CHAR 4
DCL &RECEIVER *CHAR 144
/* Create a report */
OVRPRTF FILE(QPDSPJOB) HOLD(*YES)
DSPJOB OUTPUT(*PRINT)
/* Retrieve number of pages and spool file number */
CHGVAR VAR(%BIN(&WHICHSPLF)) VALUE(-1)
CHGVAR VAR(%BIN(&RCVLEN)) VALUE(144)
CALL PGM(QUSRSPLA) PARM(&RECEIVER &RCVLEN +
'SPLA0100' '*' ' ' ' ' 'QPDSPJOB' &WHICHSPLF)
CHGVAR VAR(&PAGES) VALUE(%BIN(&RECEIVER 141 4))
CHGVAR VAR(&SPLNBR) VALUE(%BIN(&RECEIVER 77 4))
/* Create work file in QTEMP if not there already */
CRTPF FILE(QTEMP/SPOOLFILE) RCDLEN(133)
MONMSG MSGID(CPF7302)
/* Copy report to work file */
CPYSPLF FILE(QPDSPJOB) TOFILE(QTEMP/SPOOLFILE) +
SPLNBR(*LAST) MBROPT(*REPLACE) CTLCHAR(*FCFC)
/* Replace Pagexxxx with Pagexxxx of yyyy */
OVRDBF FILE(SPOOLFILE) TOFILE(QTEMP/SPOOLFILE)
CALL PGM(DSPJOB01R) PARM(&PAGES)
DLTOVR FILE(SPOOLFILE)
/* Rebuild the report */
OVRPRTF FILE(QSYSPRT) CTLCHAR(*FCFC)
CPYF FROMFILE(QTEMP/SPOOLFILE) TOFILE(QSYSPRT)
DLTOVR FILE(QSYSPRT)
/* Delete the original spooled file */
/* DLTSPLF FILE(QPDSPJOB) SPLNBR(&SPLNBR) */
ENDPGM
I commented out the next to the last line, which deletes the
original output of DSPJOB, so you could compare the two reports.
You will probably want to delete the original output in a
production situation.
Here is RPG program DSPJOB01R, which inserts the number of
total pages. Use Create Bound RPG Program (CRTBNDRPG)
command and compile it to run in the default activation group.
* Replace PageXXXX with PageXXXX of YYYY
*
FSpoolFile UF f 133 disk
D PrtLine ds
D PrtImage 2 133
D UpdtPage pr ExtPgm('UPDTPAGE')
D NbrOfPages 5p 0
D AlphaPage s 4
D PageNbr s 8
D Pos s 10i 0
D Start s 10i 0 INZ(1)
*Entry
D UpdtPage pi
D NbrOfPages 5p 0
C evalr AlphaPage = %editc(NbrOfPages:'3')
C read SpoolFile PrtLine
C dow not %eof
C eval Pos = %scan('Page' : PrtImage : Start)
C if Pos > *zero
C eval Start = Pos
C eval PageNbr = %subst(PrtImage : Pos : 8) +
C AlphaPage
C eval %subst(PrtImage : Pos - 8 : 16) =
C PageNbr + ' of ' + AlphaPage
C update SpoolFile PrtLine
C endif
C read SpoolFile PrtLine
C enddo
C eval *inlr = *on
See the January
30, 2002, issue for another tip that uses the QUSRSPLA API.
-- Ted
|