MainframeSupports
tip uge 33/2008:

For mere end 4 år siden i starten af 2004 skrev jeg et tip om, hvordan man fra COBOL, PL/1 eller REXX kan kontrollere om et dataset findes ved hjælp af CSI (Catalog Subsystem Interface). Jeg skrev også, at CSI kan bruges til at danne lister med datasetnavne. Efter selv at have brugt en del tid på at omskrive den ret simple kode i tippet til at kunne danne en liste, så tænkte jeg, at du måske vil have glæde af mine anstrengelser, for det er ikke helt simpelt.

Jeg har valgt at give dig eksemplet i COBOL. Jeg håber, at du er i stand til at omskrive det til PL/1 eller REXX, hvis en af disse sprog er at foretrække for dig. Først de nødvendige variable i 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).

Her er så den stump kode, som danner og udskriver listen på 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

I eksemplet har jeg valgt at udskrive alle datasets, der matcher filteret SYS1.*. Det er vigtigt at bemærke, at * er wildcard for netop een qualifier, mens ** er wildcard for 0 til mange qualifiers. Jeg har også lagt kode ind til den nødvendige fejlbehandling. Som det fremgår er det lidt specielt at finde ud af, at filteret er invalidt. Det er til gengæld ret svært at fremprovokere denne fejl. Et blankt filter giver fejlen, men andre sjove kombinationer, som du sikkert vil opfatte som invalide, accepterer CSI i fin stil.

I working-storage har jeg afsat 108000 bytes til dataset-listen. Hvis filteret matcher flere dataset-navne end der kan være i 108000 bytes, så sættes CSIRESUM til Y og kaldet gentages for at få fat i de resterende dataset-navne. Læg mærke til den underlige test på om variablen CSIRESNM har skiftet værdi siden sidste kald. Denne betingelse kan du risikere at opfylde, hvis dit filter matcher et GDG-dataset med rigtig mange generationer, da en generation af et GDG ikke opfattes som et entry, med som en del af et GDG-entry. Derfor skal der i variablen CSIDATAAREA være plads til dataset-navnene på alle generationer på een gang. I modsat fald ændrer CSIRESNM ikke værdi, og uden testen risikerer du et uendeligt loop. Jeg har ikke afprøvet netop denne test, så jeg er ikke sikker på om return-code er 0 i denne situation.

Du vil hurtigt opdage, at CSI er et fantastisk hurtigt interface, der er i stand til at producere rigtig lange lister over datasets i løbet af ingen tid. Faktisk er det langt hurtigere end både DSLIST og LISTCAT. Disse to produkter kalder selvfølgelig CSI, men de gør også en masse andet, som koster tid. I manualen (se link i tidligere tip) er der beskrevet, hvordan du får fat i en masse andre informationer end lige volume-navnet, som jeg har brugt i dette tip. Hvis du vil hente andre informationer, så skal du nøje læse hvordan storage i dataset-listen opbygges og ændre working-storage variablene og ovenstående kode i overensstemmelse hermed. Det er ikke enkelt, desværre, men held og lykke.

Forrige danske tip        Last tip in english        Tip oversigten