And lots of folks will find value in your open source effort.

Almost 20 years ago we wrote a REXX API for processing IMS log records https://www.ibm.com/support/knowledgecenter/SSAVJ9_2.4.0/alzu-rexx.html. It didn't really take off so we dropped it from products based upon IMSPI. It's a very difficult problem to solve with a language that only has one data type.

On 2020-03-20 5:32 PM, Martin Packer wrote:
To reveal a little more, what I might open source is a particular RMF SMF
record - with its own quirks. :-) But only a few per interval. Which
narrows it right down. :-)

Cheers, Martin

Martin Packer

zChampion, Systems Investigator & Performance Troubleshooter, IBM

+44-7802-245-584

email: martin_pac...@uk.ibm.com

Twitter / Facebook IDs: MartinPacker

Blog:
https://www.ibm.com/developerworks/mydeveloperworks/blogs/MartinPacker

Podcast Series (With Marna Walle): https://developer.ibm.com/tv/mpt/    or
https://itunes.apple.com/gb/podcast/mainframe-performance-topics/id1127943573?mt=2


Youtube channel: https://www.youtube.com/channel/UCu_65HaYgksbF6Q8SQ4oOvA



From:   David Crayford <dcrayf...@gmail.com>
To:     IBM-MAIN@LISTSERV.UA.EDU
Date:   20/03/2020 09:21
Subject:        [EXTERNAL] Re: IGGCSI00 and REXX
Sent by:        IBM Mainframe Discussion List <IBM-MAIN@LISTSERV.UA.EDU>



Oh no! Run for the hills :)

Good luck with that! I wouldn't fancy processing an SMF 110 CMF record
(with a dictionary) in REXX! I've done it in Java and that was onerous.


On 2020-03-20 3:16 PM, Martin Packer wrote:
I might be about to open that can of worms permanently (SMF and
REXX) ... :-)

Seriously, I have a few tips and tricks on processing SMF with REXX. And
I’m aiming to open source something. It’s not quite ready and it will be
the START of something, not a finished journey. (The idea being others
could pitch in - once the project is open sourced.)

(I just need a little time and the help from some IBMer who’s already
open
sourced some code.)

Cheers, Martin

Sent from my iPad

On 20 Mar 2020, at 05:45, David Crayford <dcrayf...@gmail.com> wrote:

I'm not knocking your code which looks very good, but yet again it's
a
good example of why REXX is a poor language for processing binary data.

I don't use REXX much these days. On z/OS I use either Lua [1] or
Python
[2], mainly Lua as it runs in TSO/ISPF which Python doesn't. Both
languages have
libraries for reading/writing binary data (structs). They even handle
endian conversion.

It's tempting to reach for REXX as the simple option but in many cases
the result is write-only code and technical debt. I believe some people
process SMF records
using REXX which sounds like a can of worms that I wouldn't want to
open.
[1]
https://urldefense.proofpoint.com/v2/url?u=http-3A__www.inf.puc-2Drio.br_-7Eroberto_struct_&d=DwICaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=BsPGKdq7-Vl8MW2-WOWZjlZ0NwmcFSpQCLphNznBSDQ&m=EnMRsdCNK5TSVa2NdwFVO_hqxLs-qNfXpICslQ6OLm8&s=7dmlBzEToMG1IckWXl6gsP3w1Gp-Nja6MRmmsGqR96Y&e=

[2]
https://urldefense.proofpoint.com/v2/url?u=https-3A__docs.python.org_2_library_struct.html&d=DwICaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=BsPGKdq7-Vl8MW2-WOWZjlZ0NwmcFSpQCLphNznBSDQ&m=EnMRsdCNK5TSVa2NdwFVO_hqxLs-qNfXpICslQ6OLm8&s=ktUzw10BPpe8ICjJZlckotvmlS1igg615sGJ7mDI6CU&e=

On 2020-03-20 8:08 AM, Dale R. Smith wrote:
On Thu, 19 Mar 2020 21:04:27 +0800, David Crayford
<dcrayf...@gmail.com> wrote:
I think that sample is a perfect example why you shouldn't use REXX
for
processing complex records!

All the magic number offsets and data conversions will only get worse
as
the complexity of the program increases.
Which is why REXX has variables!  Set the "magic numbers" once, in one
place and reference them by variable name.  If the value changes, update
the variable setting and nothing else needs to be changed.  Talk about
"magic"!  :-)>
I have written several REXX programs that use the Catalog Search
Interface (CSI, aka IGGCSI00).  I figured out early on that a lot of the
code for setup, processing, and error decoding could be done with a set
of
common routines that could be used in every REXX program that I create
that
uses CSI.  That way, I only have to code the unique parts for the
particular processing I want to do and then include the common code.
Yes,
you have to code offsets and/or lengths for each Catalog Field you want
to
process, and those are documented in the manual.  (DFSMS Managing
Catalogs).
The CSI Common Code and the REXX programs that use are not completely
independent of each other, (that is some variables need to be set in the
main program and used in the CSI Code some are set in the CSI Code and
used
in the main program.  Their are also two routines that must be defined
in
the main program that are called from the CSI Common Code.  The routines
must be named PROCESS_ENTRY:  and ENTRY_ERROR: (The CSI Common code will
Call PROCESS_ENTRY for every Catalog Entry returned, PROCESS_ENTRY then
Calls the correct routine to process that entry.  I set it up that way
to
allow multiple Catalog Entry types to be processed in a single program.
Here is a working example of a REXX program I wrote (GDGINFO) that
uses
CSI to extract and display information on one or GDG Catalog Entries.
The
REXX program expects the GDG DSN as it's only parameter.  The DSN
specified
to GDGINFO must contain at least one period.  It can be a full DSN, like
XXXXX.A.B, or a prefix like XXXX.  It can also contain wildcards, like
XXXX.*.YYYYY or XXXX.userid.**  CMDOUT is where the output is written
to.
It can be written to SYSOUT or a data set.   GDGINFO can be run in TSO
Batch (CMDOUT default to SYSOUT) or under TSO/ISPF (CMDOUT goes to a
temporary file that will be viewed.  Here is some sample output from
GDGINFO XXXX.
Data-Set-Name                                OwnerID  Limit Defined
Alter-Date Extended?  Empty?  Order Purge?  Scratch?
XXXX.A.B.C.D                                 *          005     000
NEVER      NOEXTENDED NOEMPTY  LIFO NOPURGE SCRATCH
XXXX.A                                       *          002     000
2012-02-04 NOEXTENDED NOEMPTY  LIFO NOPURGE SCRATCH
XXXX.A.B.C                                   *          252     037
2012-10-10 NOEXTENDED NOEMPTY  LIFO NOPURGE SCRATCH
XXXX.A.B,C.D                                 *          005     000
2011-03-30 NOEXTENDED NOEMPTY  LIFO NOPURGE NOSCRATCH
XXXX.A.B.C                                   *          025     001
2009-01-29 NOEXTENDED EMPTY    LIFO NOPURGE SCRATCH
XXXX.A.B.C                                   *          020     020
2020-03-19 NOEXTENDED NOEMPTY  LIFO NOPURGE SCRATCH
Ownerid is set to "*" if no owner is defined.  Limit is how many
generations are allowed.  Defined is how many generations are Cataloged.
000 means no generations are currently Cataloged.  Alter-Date is the
last
date that a generation was added or deleted.  NEVER means that no
generation was ever created for this GDG.  EXTENDED/NOEXTENDED indicates
whether the GDG allows a maximum of 255 generations (NOEXTENDED) or a
maximum of 999 generations (EXTENDED).
Here is the main REXX program with a "/*%INCLUDE CSICOM */" where the
CSI Common Code will go.  I'll include the CSI Common Code after
GDGINFO:
/*--------------------------- GDGINFO REXX
---------------------------*/
/* Extract and Display Information for the Specified GDG Definitions.
*/
/*--------------------------------------------------------------------*/
GDGINFO:
     Parse Source . ctype ename eoutddn edsname . system subsys .
     pgmvers = 1          /* Program Version */
     msghdr  = ename': '  /* Message Header for Say */
     tso     = (system = 'TSO')
     ispf    = (subsys = 'ISPF')
     If \tso Then
        Do
           Say ename 'must be invoked from TSO.'
           Exit 4
        End
     Address TSO
     batch   = (SYSVAR('SYSENV') = 'BACK')
     outddn  = 'CMDOUT'   /* Output DD Name */
     myuid   = Userid()
     Numeric Digits 10

     Arg dsn .

     If dsn = '' Then
        Do
           Say msghdr 'No Data Set Name Specified.'
           Say msghdr 'A Data Set Name is Required.'
           Exit 4
        End
     If Pos('.',dsn) = 0 Then
        Do
           Say msghdr 'Invalid Data Set Name Specified: ' dsn
           Say msghdr 'A Data Set Name must contain at least one
period.'
           Exit 4
        End
     If Right(dsn,1) = '.' Then dsn = dsn'**'

     Call DEFOUT
     If result \= 0 Then Call EXIT result

     Call CSI_INIT        /* Initialize CSI Parameters     */

/*--------------------------------------------------------------------*/
/* CSI Settings used by this Program. */

/*--------------------------------------------------------------------*/
     gdgempty = '80'x     /* GDGATTR  - GDG EMPTY Parm     */
     gdgscr   = '40'x     /* GDGATTR  - GDG SCRATCH Parm   */
     gdgfifo  = '20'x     /* GDGATTR  - GDG FIFO Parm      */
     gdgpurge = '10'x     /* GDGATTR  - GDG PURGE Parm     */
     gdgext   = '08'x     /* GDGATTR  - GDG EXTENDED Parm  */
     attlen   = 1         /* Length of GDG Attributes Byte */
     limlen   = 2         /* Length of GDG Extended Limit  */
     altlen   = 4         /* Length of GDG Alteration Date */
     genlen   = 4         /* Length of GDG Generations     */
     ownlen   = 8         /* Length of Owner ID            */

     rec.0    = 0         /* Initialize Output Array Count */
     gettype  = 'GDG'     /* Catalog Entry Type to Process */
     n = WordPos(gettype,etypesi)   /* Get Entry Number    */
     If n = 0 Then
        Do
           Say msghdr 'Invalid Entry Type Specified: ' gettype
           Call EXIT 4
        End
     dtypes   = Word(dtypesi,n)     /* CSI Type(s) to Use  */
/* CSI Field Names to Return */
     fldnames = 'OWNERID GDGATTR GDGLIMTE GDGALTDT GENLEVEL'
     gdghdr   = 'Data-Set-Name                                OwnerID
',
                'Limit Defined Alter-Date Extended?  Empty?  Order',
                'Purge?  Scratch?'

     Call CSI_SET         /* Initialize CSI Parameter List */
     Call CSI_PROCESS     /* Extract Catalog Information   */
     If rec.0 > 0 Then 'EXECIO' rec.0 'DISKW' outddn '(STEM REC. FINIS'
     Call EXIT 0

/*---------------------------- GDG_ENTRY
-----------------------------*/
/* Extract Information for GDG, (Generation Data Group), Entries. */

/*--------------------------------------------------------------------*/
GDG_ENTRY:
     ptr2 = ptr1 + (fldlen*2)  /* Point to Field Lengths */
     lownerid  = C2D(SubStr(csiwork,ptr2,fldlen))  /* Owner ID */
     ptr2 = ptr2 + fldlen      /* Skip Field Length */
     lgdgattr  = C2D(SubStr(csiwork,ptr2,fldlen))  /* Attribute */
     ptr2 = ptr2 + fldlen      /* Skip Field Length */
     lgdglimte = C2D(SubStr(csiwork,ptr2,fldlen))  /* Limit */
     ptr2 = ptr2 + fldlen      /* Skip Field Length */
     lgdgaltdt = C2D(SubStr(csiwork,ptr2,fldlen))  /* Alter Date */
     ptr2 = ptr2 + fldlen      /* Skip Field Length */
     lgenlevel = C2D(SubStr(csiwork,ptr2,fldlen))  /* Generations */
     ptr2 = ptr2 + fldlen      /* Skip Field Length */

     If lownerid  < ownlen Then
        Do
           Say msghdr 'No Owner ID Returned for Entry: ' csiename
           Return
        End
     If lgdgattr  < attlen Then
        Do
           Say msghdr 'No GDG Attributes Returned for Entry: ' csiename
           Return
        End
     If lgdglimte < limlen Then
        Do
           Say msghdr 'No GDG Limit Returned for Entry: ' csiename
           Return
        End
     If lgdgaltdt < altlen Then
        Do
           Say msghdr 'No GDG Alteration Date Returned for Entry: ',
               csiename
           Return
        End

     ownerid  = SubStr(csiwork,ptr2,ownlen)
     ptr2 = ptr2 + ownlen      /* Skip Owner ID */
     gdgattr  = SubStr(csiwork,ptr2,attlen)
     ptr2 = ptr2 + attlen      /* Skip Attribute */
     gdglimte = Right(C2D(SubStr(csiwork,ptr2,limlen)),3,'0')
     ptr2 = ptr2 + limlen      /* Skip Limit */
     gdgaltdt = Left(C2X(SubStr(csiwork,ptr2,altlen-1)),5)
     If gdgaltdt = '00000' Then
        altdate = 'NEVER     '
     Else
        Do
           altdate = Date('S',gdgaltdt,'J')
           altdate = Translate('1234-56-78',altdate,'12345678')
        End

     If rec.0 = 0 Then Call BLDREC gdghdr
     If ownerid = '' | Left(ownerid,1) == 'FF'x Then
        ownerid = Left('*',8)
     If BitAnd(gdgattr,gdgext)   == gdgext   Then
        extopt = 'EXTENDED  '
     Else
        extopt = 'NOEXTENDED'
     If BitAnd(gdgattr,gdgempty) == gdgempty Then
        empopt = 'EMPTY  '
     Else
        empopt = 'NOEMPTY'
     If BitAnd(gdgattr,gdgfifo)  == gdgfifo  Then
        ordopt = ' FIFO'
     Else
        ordopt = ' LIFO'
     If BitAnd(gdgattr,gdgpurge) == gdgpurge Then
        puropt = 'PURGE  '
     Else
        puropt = 'NOPURGE'
     If BitAnd(gdgattr,gdgscr)   == gdgscr   Then
        scropt = 'SCRATCH'
     Else
        scropt = 'NOSCRATCH'
     If lgenlevel = 0 Then
        gencnt = 000
     Else
        gencnt = Right(lgenlevel / genlen,3,'0')
     Call BLDREC Left(csiename,44) ownerid Right(gdglimte,5),
                 Right(gencnt,7) altdate extopt empopt ordopt,
                 puropt scropt
     Return

/*-------------------------- PROCESS_ENTRY
---------------------------*/
/* Process Data Set Entry Returned by CSI. */

/*--------------------------------------------------------------------*/
PROCESS_ENTRY:
     Arg etype .
     Select /* Entry Type */
        When etype = 'GDG' Then Call GDG_ENTRY
     Otherwise
        Nop
     End /* Select Entry Type */
     Return

/*--------------------------- ENTRY_ERROR
----------------------------*/
/* Process Entry Errors. */

/*--------------------------------------------------------------------*/
ENTRY_ERROR:
     toterr = toterr + 1
     Call CSI_ENTRY_ERROR
     Return

/*%INCLUDE CSICOM */

/*------------------------------ DEFOUT
------------------------------*/
/* Define the Output File (outddn).  If running in Batch, Allocate */
/* the Output to Sysout, otherwise Allocate the Output to a Temporary
*/
/* Disk File that will be Viewed later. */

/*--------------------------------------------------------------------*/
DEFOUT:  Procedure Expose batch outddn
     Call 'BPXWDYN' 'INFO DD('outddn') INRTDSN(OUTDSN)'
     If outdsn \= '' Then Return 0  /* "outddn" Allocated */
     If batch Then
        'ALLOCATE DDNAME('outddn') REUSE SYSOUT'
     Else
        'ALLOCATE DDNAME('outddn') REUSE DSORG(PS) UNIT(SYSDA)',
           'RECFM(V,B) LRECL(255) SPACE(1,1) CYLINDER RELEASE'
     Return rc

/*------------------------------ BLDREC
------------------------------*/
/* Build output array, (rec.), one record at a time. */

/*--------------------------------------------------------------------*/
BLDREC:  Procedure Expose rec.
     n = rec.0 + 1
     rec.n = Arg(1)
     rec.0 = n
     Return

/*------------------------------- EXIT
-------------------------------*/
/* End of Program processing.  If running in Batch, just Exit. */
/* If not Batch, View the Output File and then Delete it. */

/*--------------------------------------------------------------------*/
EXIT:
     Arg src .
     If batch Then Exit src
     If ispf & src = 0 Then
        Do
           Address ISPEXEC
           'LMINIT DATAID(VIEWID) DDNAME('outddn')'
           'VIEW   DATAID('viewid')'
           'LMFREE DATAID('viewid')'
           Address TSO
        End
     'FREE DDNAME('outddn')'
     Exit src

Here is the CSI Common Code used by GDGINFO and other REXX programs I
have written:
/*----- Begin Catalog Search Interface (CSI) Common Subroutines
------*/
/*--------------------------- CSI_PROCESS
----------------------------*/
/* Call the Catalog Search Interface, (CSI), Module, (IGGCSI00), to */
/* Retrieve Entries for the specified Entry Type and Data Set Name. */
/* CSI is documented in the "Catalog Search Interface User's Guide" */
/* Chapter in the "DFSMS Managing Catalogs" Manual. */

/*--------------------------------------------------------------------*/
CSI_PROCESS:
     resume = 'Y'         /* Set Resume Flag to "Y" */
     pcsiename = ''       /* Previous Entry Name */
     Parse Value 0 With =1 totent =1 toterr =1 vvdsdsn .
     Do While resume = 'Y'
        Address LINKPGM 'IGGCSI00 CSIRSNRC CSIFIELD CSIWORK'  /* CSI */
        csirc = rc
        If csirc > 0 Then
           Do
              Call CSI_ERROR   /* Check Return Code/Reason Code */
              If result > 0 Then Exit result  /* Exit if Bad RC */
           End
        resume   = SubStr(csifield,150,1)    /* Resume Flag */
        csiusdln = C2D(SubStr(csiwork,9,4))  /* Work Area Used */
        ptr1 = hdrlen + 1           /* Starting Position (Skip Header)
*/
        Do While ptr1 < csiusdln
           csietype = SubStr(csiwork,ptr1+1,1)  /* Entry Type */
           If csietype = 0 Then
              Do
                 Call CSI_CATALOG_ENTRY  /* Process Catalog Entry */
                 ptr1 = ptr1 + catlen    /* Skip Catalog Entry */
                 Iterate  /* Do While ptr1 < csiusdln */
              End
           csieflag = SubStr(csiwork,ptr1,1)            /* Entry Flag
*/
           csiename = Strip(SubStr(csiwork,ptr1+2,44))  /* Entry Name
*/
           vvdsdsn  = (Left(csiename,10) = 'SYS1.VVDS.')
           totent   = totent + 1
           If BitAnd(csieflag,csienter) == csienter Then
              Do
                 Call ENTRY_ERROR
                 ptr1 = ptr1 + datlen + errlen     /* Next Entry */
                 Iterate  /* Do While ptr1 < csiusdln */
              End
           ptr1 = ptr1 + datlen     /* Skip Default Data Entry */
           csitotln = C2D(SubStr(csiwork,ptr1,2))  /* Data Length */
           n = WordPos(csietype,dtypeso)  /* Valid Entry Type ? */
           If n = 0 Then
              Do
                 Say msghdr 'Unknown Data Type for Entry: ' csiename
                 ptr1 = ptr1 + csitotln  /* Next Entry */
                 toterr = toterr + 1
                 Iterate  /* Do While ptr1 < csiusdln */
              End
           etypeo = Word(etypeso,n)  /* Convert Entry Type */
           Call PROCESS_ENTRY etypeo
           ptr1 = ptr1 + csitotln        /* Next Entry */
        End /* Do While ptr1 < csiusdln */
        If resume = 'Y' & pcsiename = csiename Then
           Do /* Exit if we have tried to process this entry twice */
              Say msghdr csiename 'cannot be Processed with the',
                         'Work Area Size provided - you must increase',
                         'the Work Area Size and Retry'
              Exit 40
           End
        pcsiename = csiename
     End /* Do While resume = 'Y' */
     Return

/*------------------------ CSI_CATALOG_ENTRY
-------------------------*/
/* Entry Returned from CSI is a Catalog.  This may indicate an error.
*/
/*--------------------------------------------------------------------*/
CSI_CATALOG_ENTRY:
     csicflg = SubStr(csiwork,ptr1,1)    /* Catalog Flag */
     Select /* Catalog Flag */
        When csicflg == bzero                     Then Nop  /* No Error
*/
        When BitAnd(csicflg,csinoent) == csinoent Then
           Do /* No Entries Found */
              Say msghdr 'No Entries Found for DSN: ' dsn ' Type: '
etype
              Exit 28
           End
     Otherwise
        csicname = Strip(SubStr(csiwork,ptr1+2,44))  /* Catalog Name */
        csicretn = SubStr(csiwork,ptr1+46,4)         /* Catalog Error
*/
        Say msghdr 'Error Processing CSI Request for Entry: ' dsn
        Say msghdr 'CSICNAME='csicname
        Say msghdr 'CSICFLG ='C2X(csicflg)    /* Catalog Flag */
        Call CSI_ERRCODE csicretn   /* Decode Catalog Error */
        Exit 32
     End /* Select Catalog Flag */
     Return

/*----------------------------- CSI_SET
------------------------------*/
/* Set CSI Variables and Build the CSI Parameter List. */

/*--------------------------------------------------------------------*/
CSI_SET:
     csifiltk  = Left(dsn,44)       /* Data Set Name Filter Key   */
     csicatnm  = Left(catname,44)   /* Catalog Name to Process    */
     csidtyps  = Left(dtypes,16)    /* Entry Types to be Returned */
     numflds   = Words(fldnames)    /* Number of Field Names      */
     csinumen  = D2C(numflds,2)     /* Number of Fields to Return */
     csifldnm  = ''                 /* List of 8 Byte Field Names */
     Do f = 1 to numflds
        csifldnm = csifldnm||Left(Word(fldnames,f),8)
     End /* Do f = 1 to numflds */

/*--------------------------------------------------------------------*/
/* Build the Selection Criteria Fields part of the Parameter List. */

/*--------------------------------------------------------------------*/
     csiopts   = csicldi  || csiresum || csis1cat || csioptns
     csifield  = csifiltk || csicatnm || csiresnm || csidtyps ||,
                 csiopts  || csinumen || csifldnm
     Return

/*----------------------------- CSI_INIT
-----------------------------*/
/* Initialize CSI Variables and Variables that need to be set once. */

/*--------------------------------------------------------------------*/
CSI_INIT:

/*--------------------------------------------------------------------*/
/* Initialize Device Type Codes, Entry Types, and Reason Messages. */

/*--------------------------------------------------------------------*/
     dasdlist  = '3010200F 3390   3010200E 3380   30102004 9345'
     tapelist  = '78048081 3490   78048083 3590-1 78048080 3480X ',
                 '78008080 3480   32108003 3400-6 32008003 3400-5',
                 '30C08003 3400-2 33008003 3400-9 34008003 3400-3'
     etypesi   = 'NONVSAM GDG CLUSTER AIX GDS PATH UCAT ALIAS',
                 'ATLLIB ATLVOL CATCBD'
     dtypesi   = 'A       B   C       G   H   R    U    X    ',
                 'L      W      Z     '
     etypeso   = etypesi 'DATA INDEX'
     dtypeso   = dtypesi 'D    I    '
     rsnmsg.   = 'Unknown Reason Code'
     rsnmsg.1  = 'Insufficent Storage for GETMAIN, Increase Region
Size.'
     rsnmsg.2  = 'Invalid Entry Type in CSIDTYPS.'
     rsnmsg.3  = 'Invalid Data/Index Option in CSICLDI, Should be "Y"',
                 'or Blank.'
     rsnmsg.4  = 'Invalid Resume Option in CSIRESUM, Should be "Y" or',
                 'Blank.'
     rsnmsg.5  = 'Invalid Search One Catalog Option in CSIS1CAT,
Should',
                 'be "Y" or Blank.'
     rsnmsg.6  = 'Invalid Number of Fields in CSINUMEN, Should be',
                 'between Zero and 100, Inclusive.'
     rsnmsg.7  = 'Invalid Work Area Length, Should be between 1024
and',
                 '8,388,608, Inclusive.'
     rsnmsg.8  = 'Invalid Length Option in CSIOPTNS, Should be "F" or',
                 'Blank.'
/*------------ Reason Codes  9 and 10 Added in z/OS V2.2.
------------*/
     rsnmsg.9  = 'Entry Type "Z" must be the only Entry Type in
CSIDTYPS.'
     rsnmsg.10 = 'Entry Type "Z" request contains an invalid Field
Name.'
/*------------ Reason Codes 11 and 12 Added in z/OS V2.3.
------------*/
     rsnmsg.11 = 'CSIRESUM is Set to "Y" and CSIRESNM is zeroes.'
     rsnmsg.12 = '"Z" Entry Field Names cannot be used with non-"Z"',
                 'Entry Type requests.'


/*--------------------------------------------------------------------*/
/* Initialize CSI Parameters. */

/*--------------------------------------------------------------------*/
     csirsnrc  = Left(' ',4)   /* CSI Module Return/Reason Code */
     catname   = Left(' ',44)  /* Catalog Name to Search        */
     csiresnm  = Left(' ',44)  /* Resume Data Set Name          */
     csicldi   = 'Y'           /* Return Data/Index for Cluster */
     csiresum  = ' '           /* Resume Flag (More Entries)    */
     csis1cat  = 'Y'           /* Search Only 1 Catalog         */
     csioptns  = ' '           /* Use Halfword Length Fields    */

/*--------------------------------------------------------------------*/
/* Initialize Flags and Length Variables. */

/*--------------------------------------------------------------------*/
     bzero     = '00'x         /* Binary Zero - No Errors       */
     csinticf  = '80'x         /* CSICFLG  - Non-ICF Catalog    */
     csinoent  = '40'x         /* CSICFLG  - No Entries Found   */
     csintcmp  = '20'x         /* CSICFLG  - Data not Complete  */
     csicerr   = '10'x         /* CSICFLG  - Catalog Error      */
     csicerrp  = '08'x         /* CSICFLG  - Catalog Error      */
     csipment  = '80'x         /* CSIEFLAG - Primary Entry      */
     csienter  = '40'x         /* CSIEFLAG - Entry Error        */
     csiedata  = '20'x         /* CSIEFLAG - Entry has Data     */

/*---- Work Area Max Size = 1MiB.  Inceased to 8MiB in z/OS V2.2
-----*/
     worklen   = 1*(1024*1024) /* Length of Work Area 1MiB      */
     hdrlen    = 14            /* Length of Work Area Header    */
     catlen    = 50            /* Length of Catalog Entry       */
     datlen    = 46            /* Length of Dataset Entry       */
     errlen    = 4             /* Length of Error   Entry       */
     If csioptns = ' ' Then
        fldlen = 2             /* Length of Field Length Entry  */
     Else
        fldlen = 4             /* Length of Field Length Entry  */

/*--------------------------------------------------------------------*/
/* Initialize and Build Work Area output part of the Parameter List.
*/
/*--------------------------------------------------------------------*/
     csiusrln  = D2C(worklen,4)
     csiwork   = csiusrln || Copies('00'x,worklen-4)
     Return

/*------------------------- CSI_ENTRY_ERROR
--------------------------*/
/* Process CSI Entry Errors. */

/*--------------------------------------------------------------------*/
CSI_ENTRY_ERROR:
     Say msghdr 'Error Processing CSI Request for Entry: ' csiename
     Say msghdr 'CSIEFLAG='C2X(csieflag)
     csiretn = SubStr(csiwork,ptr1+46,4)  /* Entry Error */
     Call CSI_ERRCODE csiretn       /* Decode Entry Error */
     Return

/*---------------------------- CSI_ERROR
-----------------------------*/
/* Check and Process the CSI Module Return Code and Reason Code. */
/* CSI Module Return Codes and Reason Codes are documented in Chapter
*/
/* "Catalog Search Interface User's Guide" in the "DFSMS Managing */
/* Catalogs" Manual. */

/*--------------------------------------------------------------------*/
CSI_ERROR:
     Call CSI_ERRCODE csirsnrc, 'QUIET'  /* Decode Module Error */
     Select /* Return Code */
        When csirc = 4 Then    /* Some Catalog Information Returned */
           Select /* retcode */
              When retcode = 100 Then    /* Catalog/DSN Error Detected
*/
                 Do
                    If rsncode = 4 Then Return 0   /* DSN Entry Error
*/
                    If rsncode = 8 Then Nop        /* Cat Entry Error
*/
                 End
              When retcode = 122 Then    /* Invalid Filter Key */
                 Do
                    Say msghdr 'Invalid CSI Filter Key',
                               '(Data Set Name): ' csifiltk
                    Call CSI_ERRCODE csirsnrc  /* Decode Module Error
*/
                    Return retcode
                 End
           Otherwise
              Nop
           End /* Select retcode */
        When csirc = 8 Then    /* CSI Failure */
           Do
              Say msghdr rsncode rsnmsg.rsncode    /* Reason Code Msg
*/
              Return csirc
           End
     Otherwise
        Nop
     End /* Select Return Code */

     Say msghdr 'Error' csirc 'from Call to CSI'
     Call CSI_ERRCODE csirsnrc      /* Decode Module Error */

     ptr3 = hdrlen + 1         /* Skip Header */
     csicflg  = SubStr(csiwork,ptr3,1)            /* Catalog Flag  */
     csicname = Strip(SubStr(csiwork,ptr3+2,44))  /* Catalog Name  */
     csicretn = SubStr(csiwork,ptr3+46,4)         /* Catalog Error */
     Say msghdr 'Catalog Entry Error Information:'
     Say msghdr 'CSICNAME='csicname
     Say msghdr 'CSICFLG ='C2X(csicflg)
     Call CSI_ERRCODE csicretn      /* Decode Catalog Error */

     ptr3 = ptr3 + catlen      /* Skip Catalog Entry */
     csieflag = SubStr(csiwork,ptr3,1)            /* Entry Flag  */
     csiename = Strip(SubStr(csiwork,ptr3+2,44))  /* Entry Name  */
     csiretn  = SubStr(csiwork,ptr3+46,4)         /* Entry Error */
     Say msghdr 'Dataset Entry Error Information:'
     Say msghdr 'CSIENAME='csiename
     Say msghdr 'CSIEFLAG='C2X(csieflag)
     Call CSI_ERRCODE csiretn       /* Decode Entry Error */
     Return csirc

/*--------------------------- CSI_ERRCODE
----------------------------*/
/* Decode Error Data into Module ID, Return Code, and Reason Code. */
/* CSI Return Codes and Reason Codes are documented in Message */
/* IDC3009I in one of the "MVS System Messages" Manuals. */

/*--------------------------------------------------------------------*/
CSI_ERRCODE:
     Parse Arg csicodes, parm, .
     Parse Var csicodes =1 modid +2 rsncode +1 retcode +1 .
     If modid << 'AA' | modid >> '99' Then modid = C2X(modid)
     retcode = C2D(retcode)
     rsncode = C2D(rsncode)
     If parm = 'QUIET' Then Return
     Say msghdr 'ModID='modid 'Return Code='retcode,
                'Reason Code='rsncode
     Return

/*----- End   Catalog Search Interface (CSI) Common Subroutines
------*/
I know this is long post, but I hope it will be helpful to the OP and
to
anyone else that wants to write REXX programs that extract Catalog
information using CSI.  If anyone has questions about the code, either
post
them here or email me directly.  If you want to see other examples, let
me
know that also.
FYI, we used the output from GDGINFO to help get rid of many unused
GDG
definitions!
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number
741598.
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6
3AU

----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN




Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number
741598.
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6 3AU


----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN

----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN

Reply via email to