MainframeSupports
tip week 6/2011:

About two and a half year ago I wrote a tip about how you can validate the existence of a dataset from COBOL, PL/I or REXX by using CSI (Catalog Subsystem Interface). I also mentioned that CSI may be used to create lists of dataset names. I have used quite a lot of time to extent the pretty simple code from the tip in order to make it create a list. Therefore I thought that you might be interested in the result, because it is rather difficult to create a list.

I have chosen to write the example in COBOL. I hope you are able to translate it into PL/I or REXX if you prefer one of these languages. I will start with the required definitions in working-storage:

01 oldCsiresnm pic x(44).
01 entryPos pic s9(9) binary.
01 hexCsiReason pic x(8).
01 moreWork pic x(1).
01 iggcsi00 pic x(8) value 'IGGCSI00'.
01 csiReason pic x(4).
01 csiInput.
  02 csifiltk pic x(44).
  02 csicatnm pic x(44).
  02 csiresnm pic x(44).
  02 csidtyps pic x(16).
  02 csiopts.
    03 csicldi pic x(1).
    03 csiresum pic x(1).
    03 csis1cat pic x(1).
    03 csioptns pic x(1).
  02 csinumen pic s9(4) comp.
  02 csifldnm pic x(8).
01 csiOutput.
  02 csiPrefixArea.
    03 csiusrln pic s9(9) comp.
    03 csireqln pic s9(9) comp.
    03 csiusdln pic s9(9) comp.
    03 csinumfd pic s9(4) comp.
  02 csiDataArea pic x(108000).
01 csiCatalogEntry.
  02 csicflg pic x(1).
  02 csictype pic x(1).
  02 csicname pic x(44).
  02 csicretn pic x(4).
01 csiVolumeEntry.
  02 csiNameInfo.
    03 csieflg pic x(1).
    03 csietype pic x(1).
    03 csiename pic x(44).
  02 csiOtherInfo.
    03 csitotln pic s9(4) comp.
    03 csifill pic x(2).
    03 csilenf1 pic s9(4) comp.
    03 csivolser pic x(6).

And here is a piece of COBOL code that creates and prints the list on SYSOUT:

initialize csiReason csiInput csiOutput
move 'SYS1.*' to csifiltk
move 1 to csinumen
move 'VOLSER' to csifldnm
move length of csiOutput to csiusrln
move 'Y' to moreWork
perform until moreWork not = 'Y'
  move csiresnm to oldcsiresnm
  call iggcsi00 using csiReason csiInput csiOutput
  if csiresnm = oldcsiresnm and csiresum = 'Y'
  or return-code not = 0
    if return-code = 0
      display 'Entry > csiDataArea. Please increase'
    else
      if return-code = 4 and csiReason(4:1) = X'7A'
        display 'Filter invalid: ' csifiltk
      else
        display 'return-code = ' return-code
        perform reason2hex
        display 'reason-code = ' hexCsiReason
      end-if
    end-if
    move 'N' to moreWork
  else
    compute entryPos = length of csiPrefixArea + 1
    perform until entryPos > csiusdln
      if csiOutput(entryPos + 1:1) = '0'
        add length of csiCatalogEntry to entryPos
      else
        move csiOutput(entryPos:length of csiVolumeEntry)
          to csiVolumeEntry
        display csiename ' ' csietype ' ' csivolser
        add length of csiNameInfo to entryPos
        add csitotln to entryPos
      end-if
    end-perform
    move csiResum to moreWork
  end-if
end-perform

In the example I have chosen to print all dataset names matching the filter SYS1.*. It is important to notice that * is the wildcard for exactly one qualifier while ** is the wildcard for zero to many qualifiers. I have also added some code for error handling. As you will notice it requires special coding to detect an invalid filter. On the other hand I found out that it is hard to provoke this error. A blank filter is considered invalid while other combinations that I consired being invalid were accepted by CSI.

In working-storage I have allocated 108000 bytes to the dataset list. If the filter matches more dataset names than there is room for in 108000 bytes CSI sets the field CSIRESUM to Y and the call is repeated in order to retrieve the remaining dataset names. Note the test of whether variable CSIRESNM has changed value since last call. This condition may be true if your filter matches a GDG dataset with a lot of generations as each generation is not treated as a new dataset name, but as a part of a single GDG entry. Because of this you must ensure that variable CSIDATAAREA can contain the dataset names of all generations once. If not you may end up in a loop. I have not tested this situation, so I am not sure whether the return-code continues to be zero or not.

You will quite fast discover that CSI is an extremely fast interface that is able to produce long lists of dataset in no time. Actually it is much faster than both DSLIST and LISTCAT. These two programs of course uses CSI, but they also do a lot of other stuff which slows them down. In the manual (use link in earlier tip) it is described how you can retrieve a lot of other information than just the volume serial as in this tip. If you want to select other information than the volume serial you must carefully study how data is built in the dataset list and change the working-storage variables and the coding accordingly. It is not simple, but I wish you good luck.

Previous tip in english        Sidste danske tip        Tip list