The question sounded simple: How can I write to the same spool file from two programs?
I have written before about copying from more than one spool file to create a new one. But this time I will be writing to the same spool file directly from two programs.
Let me start with the DDS for the printer file:
01 A R HEADER 02 A 1'PAGE HEADER' 03 A SKIPB(001) ***************************************************************** 04 A R FORMAT01 05 A 1'PROGRAM 1' 06 A SPACEB(001) 07 A COUNTER 3 0 +2EDTCDE(Z) ***************************************************************** 08 A R FORMAT02 09 A 1'PROGRAM 2' 10 A SPACEB(001) 11 A COUNTER R +2REFFLD(COUNTER *SRC) 12 A EDTCDE(Z) ***************************************************************** 13 A R ENDREPORT 14 A 1'* * * END OF REPORT * * *' 15 A SPACEB(001) |
This printer file contains four record formats:
- HEADER: page heading
- FORMAT01: I will be writing this record format from the first program
- FORMAT02: And I will be writing this record format from the other program
- ENDREPORT: I always like to add a line like this to end of my reports as it allows the user to be sure that they have all of the report
I am going to use a CL program rather than use calls to the QCMDEXC API in my RPG programs.
01 PGM 02 DCL VAR(&JOBTYPE) TYPE(*CHAR) LEN(1) 03 RTVJOBA TYPE(&JOBTYPE) 04 IF COND(&JOBTYPE = '1') THEN(DO) 05 SBMJOB CMD(CALL PGM(PROGRAM0)) JOB(PROGRAM0) 06 RETURN 07 ENDDO 08 OVRPRTF FILE(TESTPRTF) MAXRCDS(*NOMAX) + SHARE(*YES) 09 CALL PGM(PROGRAM1) 10 CALL PGM(PROGRAM2) 11 ENDPGM |
Lines 2 – 7: As I always run my report generating programs in batch if this program is called interactively it will submit itself to batch.
Line 8: This is critical. I need to override the printer file to be shared, SHARE(*YES), then when it has been opened it can be used by more than one program.
Lines 9 and 10: These are the two programs that will be writing to this shared printer file.
And on to the first RPG program, PROGRAM1:
01 **free 02 dcl-f TESTPRTF printer ; 03 write HEADER ; 04 for Counter = 1 to 100 ; 05 if (%error) ; 06 write HEADER ; 07 endif ; 08 write(e) FORMAT01 ; 09 endfor ; 10 return ; |
Line 1: I only write programs in totally free RPG.
Line 2: The printer file is just defined as I would in any other program.
Line 3: I am printing the page header.
Line 4: I am using a For group which will be performed 100 times.
Lines 5 – 7: If the error indicator is on then the Header record format will be written. When the Header record format is written the error indication is set off.
Line 8: I write the FORMAT01 record format. If an error occurs when the write happens the error indicator is set on. 99.999% of the time an error happens when the page overflow is reached.
Line 10: Notice that I exit the program with a RETURN rather than setting on *INLR. By returning the spool file is left open. If *INLR is used the spool file is closed and I will get two spool files.
The second program, PROGRAM2, is almost identical to the first.
01 **free 02 dcl-f TESTPRTF printer ; 03 //write HEADER ; 04 for Counter = 1 to 100 ; 05 if (%error) ; 06 write HEADER ; 07 endif ; 08 write(e) FORMAT02 ; 09 endfor ; 10 write ENDREPORT ; 11 return ; |
What are the differences?
Line 3: I have commented out the line that writes the Header record format. This means that the first record from PROGRAM2 follows the last record from PROGRAM1. If I wanted to have the two sets of data separated I would write the Header record format which would start a new page and separate the records from the two programs.
Line 8: Here I am writing FORMAT02.
Line 10: At the end of this program I want to have the "End of report" printed.
Line 11: Return again.
As both of the programs return leaving the spool file open if I run this interactively then spool shows in WRKSPLF as still open, OPN. By running this in batch as the job ends the spool file is closed.
When I look in the spool file I can see that it contains records written by both programs:
PAGE HEADER PROGRAM 1 1 PROGRAM 1 2 . PROGRAM 1 58 PROGRAM 1 59 PAGE HEADER PROGRAM 1 60 PROGRAM 1 61 . PROGRAM 1 99 PROGRAM 1 100 PROGRAM 2 1 PROGRAM 2 2 . PROGRAM 2 17 PROGRAM 2 18 PAGE HEADER PROGRAM 2 19 PROGRAM 2 20 . PROGRAM 2 76 PROGRAM 2 77 PAGE HEADER PROGRAM 2 78 PROGRAM 2 79 . PROGRAM 2 99 PROGRAM 2 100 * * * END OF REPORT * * * |
This is a very simple example of what is possible. The printer file record formats could be a lot more complicated, and the printer file could contain record formats for "two different reports", but the record formats must all be in the same printer file. There is no reason why only two program should write to the same spool file, I could use more if I so desired.
This article was written for IBM i 7.4, and should work for some earlier releases too.
There is an alternative - and personally I think "cleaner" - approach to this topic. Namely passing the printer file as a parameter between the programs.
ReplyDeleteIt offers a number of advantages as I outlined in this article:
https://www.itjungle.com/2012/03/21/fhg032112-story01/
The problem Jon is your approach is different from the one Simon demonstrated. Yours is about producing reports using a common routine that has very similar pieces of information (as you demonstrated) but the demonstration by Simon is about two distinct reports being combined into one printer file.
ReplyDeleteI have done what Simon showed but on rare occasions and the only one I can think of quickly is about taking many prints from a old COLD storage product (PaperView) and combining them into one file for distribution to an outside vendor.
Jon I think your approach would be great if I could use it to produce the same report to multiple SPLFs.
-Matt