(Originally posted 2011-07-17.)
Frank Yaeger of DFSORT Development suggested I pass this tip along to y’all. It’s his solution to a problem set by Brian Peterson of UnitedHealth Group…
In z/OS Release 12 two new messages were introduced: IEF032I and IEF033I replace IEF374I and IEF376I. The older messages were single-line step- and job-end messages. The new ones are their multiple-line analogues: IEF032I is 3 lines and IEF033I is 2 lines.
The problem is how to sift these messages out in a program.
Here’s Frank’s solution:
//S1 EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=... input file (FBA/133)
//SORTOUT DD DSN=... output file (FBA/133)
//SYSIN DD *
OPTION COPY
INREC IFTHEN=(WHEN=GROUP,BEGIN=(2,7,CH,EQ,C'IEF032I'), <1>
RECORDS=3,PUSH=(134:ID=1)),
IFTHEN=(WHEN=GROUP,BEGIN=(2,7,CH,EQ,C'IEF033I'), <2>
RECORDS=2,PUSH=(134:ID=1))
OUTFIL INCLUDE=(134,1,CH,NE,C' '),BUILD=(1,133)
/
It uses DFSORT’s IFTHEN WHEN=GROUP to form groups. Overall the trick is to assign a group number to those records that are part of the message (placing it in position 134) and leave the records which aren’t with a blank in position 134.
The OUTFIL statement keeps only those records without a blank in position 134, truncating the output to 133 bytes.
So, how does it distinguish between those records that are part of an IEF032I or IEF033I message? The INREC statement uses a pair of IFTHEN clauses in a short "pipeline":
- IFTHEN clause <1> begins a group when it encounters "IEF032I" in position 2 (after the ASA control character). For three records beginning with this one a group number is assigned (in position 134). It’s 1 byte long – specified with "PUSH=(134:ID=1)". It doesn’t matter what the group number is, so long as it’s there for the OUTFIL statement.
- IFTHEN clause <2> does the same for the "IEF033I" message. This time it’s two records beginning with the "IEF033I" line.
Looking back I see I used the term "pipeline" for IFTHEN in Unknown Unknowns in 2009. This example incorporates a two-stage pipeline: Any records not satisfying the BEGIN= clause in <1> (the first stage) are passed to the second stage (marked <2>). But no records that satisfy the clause are passed on. (If we wanted them to we could code "HIT=NEXT" – but that wouldn’t be useful here.)
The code I’ve shown above is just what Brian needed – and I haven’t altered it from what Frank sent me.
I think there are three fairly obvious twists to this:
- If you wanted to you could decode the multi-line message – perhaps with PARSE.
- If you wanted to support the old messages (IEF374I and IEF376I) with more IFTHEN clauses. You might do this if had multiple LPARs – not all at or above z/OS R.12 – to support. (Or maybe you’re a software vendor.)
- You could support multiple messages – not just the two versions mentioned here – and you might use OUTFIL to route them to multiple destinations. (I think you’d need another flag for that.)
But Frank’s example is a very good one and I’m glad he sent it to me. This is a sort of "guest post" though I did all the writing. I wonder if there are topics you would like Frank to actually "guest post" on. I can put them to him.