Concatenating ISPF libraries —
This post has hints and tips for using ISPF-specific libraries, plus how to avoid a few common problems when concatenating ISPF libraries.
Most libraries used under TSO are concatenated, including TSO/ISPF-specific ones. So this could as well be called “Using ISPF Libraries”, but the fact is that a lot of the difficulties people have with the environment are related to concatenations. So the emphasis is on that. Plus somebody* asked me about it that way.
Let’s assume you’ve already read the post about Program Search Order and you understand that. Now you want to know about the search order for libraries specific to TSO and TSO/ISPF.
(Notice I’m using that blue-ish color to indicate where there’s a link you can click, as for Program Search Order there to refer you back to the earlier post on that if you missed it. There are also a bunch of links to IBM doc in here this time.)
Some libraries are used by both TSO/ISPF and native TSO. This includes some basic load libraries (loadlibs) containing programs in executable format (e.g., load modules), such as might be found on a STEPLIB DD statement in the TSO Logon JCL procedure.
It also includes the CLIST and REXX libraries allocated to ddnames SYSPROC and SYSUPROC as well as the REXX-only libraries allocated to SYSEXEC and SYSUEXEC (or other ddnames designated either by you or for you at your site).
If you are not yet familiar with using the CLIST and REXX facilities under TSO, there is a previous post introducing that also, called How to Write a CLIST
As you may also already know, perhaps from the post Take Control of Your TSO/ISPF Profile(s), you have an ISPF profile library that contains your personalized ISPF settings. The default ddname for that is ISPPROF.
Most of the other ISPF-specific dataset types have default ddnames of the form ISP?LIB, where the question mark (?) position is replaced by a character that indicates the library type: M for messages, T for tables, S for skeletons, P for panels. There are sometimes others, such as the loadlib ddname ISPLLIB which is checked prior to STEPLIB for fetching ISPF modules in executable format.
Beyond the ISP?LIB ddnames, you have the option of using LIBDEF to assign your own private test libraries to ddnames of the form ISP?USR, and the ISP?USR libraries will then be searched prior to their counterpart distribution versions on ISP?LIB.
ISPF Panels (screens)
After CLIST and REXX execs, the member type you are most likely to want to change is presumably panels, that is, screens. Screens in ISPF are called Panels (go figure), and in the simplest case they reside in ISPPLIB. If you plan to test your own new panels, or your own modified versions of distribution panels, you want to create your own panel library for use on ddname ISPPUSR.
You want to allocate your private test panel library with mostly the same attributes as the distribution ISPPLIB, but maybe a few tweaks.
For one thing, regardless of whether the distribution library is installed as a PDS or a PDSE, you’re probably better off if you make your own library a PDSE, that is, DSNTYPE=LIBRARY, so that you can replace members repeatedly without needing to do a compress.
Also, you probably want to use system-determined BLKSIZE, that is, do not copy the BLKSIZE from the distribution library, just leave it blank or specify zero and let the system decide what is best. I doubt you need to maintain backward compatibility with type 3330 disks – let your system decide what will work best for you.
Third tweak: You’ll want to modify the disk SPACE allocation to allow an amount of disk space appropriate to your anticipated testing, and to your system; but do yourself the favor of allocating in units of CYLinders (CYL,CYLS) rather than Tracks (TRK, TRKS), because if it is allocated in units of Cylinders then anything that comes along and releases unused space from your data set will only take away your unused space down to the nearest cylinder boundary, rather than paring it down to a track boundary. As you know, one cylinder is equal to fifteen tracks; Since a typical panel library member is relatively small, having those few extra tracks might allow you several more opportunities to type SAVE before you hit the wall.
The ISPF screens (panels) are, of course, in an ISPF-specific ISPF panel format. You can figure out a lot of the syntax just by looking at the screens in the distribution panel library(ies) and comparing the screens that are displayed with the members in the library. As you may remember, you use the ISPF command PANELID to get ISPF to start showing the name of the currently displayed panel in the upper left corner of every screen. Some of the syntax is pretty much beyond what you can figure out with that kind of guesswork method, though, so you’ll want to have access to the manual(s). Check out the Panel definition statement guide section in the ISPF Dialog Developer’s Guide. There’s a “References and Further Reading” list at (or near) the end of this post where you can find additional links.
You may have a need to issue ISPF-style messages. You may be tempted to create your own message members. In the short run, that is not strictly necessary. IBM has kindly provided catch-all messages where you can supply your own message text and have it be displayed using one of IBM's own message numbers.
You have available for your immediate use the message ISRZ001 (with variants ISRZ000 and ISRZ002) to allow you to supply the message text by assigning your message text string to a variable. Assuming you choose to use ISRZ001, you assign your short message text to variable name ZEDSMSG – this is the text that appears in the upper right hand corner of the screen whenever an error occurs. You assign your long message text to variable name ZEDLMSG – in general this text appears if someone presses the “HELP” key (F1 or F13) to try to get more information after seeing the short message. After setting those variables, you call SETMSG to save them for use on the next ISPF panel to be displayed and to set the next message number to ISRZ001. Of course some other process can still sneak in along the way back and call SETMSG again, and replace your messages, but in practice I have not yet seen that happen.
To use the generic message ISRZ001 with message text you supply, you put lines similar to the following into your CLIST:
SET ZEDSMSG = &STR(‘Oops, you goofed’)
SET ZEDLMSG = &STR(‘Longer explanatory message text’)
ISPEXEC SETMSG MSG(ISRZ001)
If you’re using REXX rather than CLIST, the approximate equivalent of the above in REXX is:
zedsmsg = ‘Oops, you goofed’
zedlmsg = ‘Longer explanatory message text’
Using SETMSG as shown in the above code snippet causes the message to appear on whatever ISPF screen is displayed next, so you don’t need to know exactly where you are, or are going to be.
Compatibility of record format
With CLIST concatenations and with ISPF library concatenations in general, one problem people occasionally bring on themselves is to combine FB and VB in the same concatenation, which causes problems when the system tries to interpret all members as either FB or VB. When libraries are concatenated, all of the libraries in the concatenation must have the same record format (RECFM). For CLIST, REXX, and ISPF-specific libraries this can be either FB or VB, that is, either fixed-length records or variable-length records. If the libraries are FB, then they must all have the same record length as well.
Apart from load libraries, IBM distributes the ISPF libraries as FB 80 by default, that is, every line in every member is fixed length 80 bytes. Many people prefer VB libraries because they can have longer lines, and so they reallocate copies of the distribution libraries as VB. Whatever distribution libraries you’re using, make sure any other libraries you concatenate with them have the same format.
If you do not have all the same format libraries in a concatenation, you may not see a problem initially. This is because all of the members being fetched happen to be coming from the same kind of library. Then one day you may (or some program you’re running behind the scenes may) try to use a member that resides in the library with the unmatching format. The member will probably be read successfully if the BLKSIZE is compatible, but then the contents of the member will be parsed incorrectly, according to the rules for the expected record format. Then whatever process is trying to use the member will complain about the syntax being wrong, if it gets that far. Possibly some other error will come first. Depends on what is actually read, and what was expected. This happens more often than one might think, and it can be harder to figure out than you might imagine too, because (a) the error message you end up getting bears no obvious relationship to the underlying problem, and (b) it may have appeared to be running successfully for a while prior to the failure simply because it did not happen to need to fetch anything from the incompatible library.
So: Be sure all the datasets in your concatenation have the same record format. If the format is FB (fixed length), make sure they all have the same record length as well.
Fifteen-Library Concatenation Limit
Warning: You can use a maximum of 15 libraries concatenated together onto any one of the ISP?USR ddnames (and perhaps some other ISPF ddnames you might come across depending on your luck). If you concatenate more than 15 libraries, you will not, in general, get an error message about it; but only the first 15 will be used, and any others will be ignored. I’ve seen this 15-library concatenation limit for other ddnames in TSO/ISPF previously, but as of z/OS 2.1 the only specific warning about it I’ve found mentions only the ISP?USR concatenations; and I have not done exhaustive experiments to be able to say otherwise. It is a limit I’ve run into before and we can expect to see again, so remember to be careful when you concatenate numerous libraries on one ddname under TSO/ISPF. For some cases, 15 is a magic limit. Okay, not magic, but it may as well be.
Replacing members in active libraries
There are also some problems that can happen when you replace members in ISPF libraries while ISPF is active, for example if you want to modify a message or a panel and then test the modification.
If you replace a member in an ISPF panel, message, or skeleton library while ISPF is running, do not expect ISPF to look for the replacement. If ISPF finds that it has an existing copy of the panel, message, or skeleton member already in storage, ISPF will keep reusing that old copy, and it will not automatically fetch your updated version. For panels and messages, however, you can tell ISPF not to act that way: You do this by specifying the TEST parameter when starting ISPF. Rather than just saying ISPF to get into ISPF, instead say : ISPF TEST
If the ISPF startup is done by a CLIST or REXX EXEC member, then the TEST parameter has to be specified within the CLIST or REXX member, on the line where the ISPF command itself is started. (You cannot just add the word TEST when invoking the CLIST – unless of course the CLIST has been written to allow that as an optional parameter, which you might think would be commonplace but it’s not.)
Caveat / Warning: Of course there is some overhead added when you use TEST.
This trick of using the TEST parameter may not work for changes to ISPF skeleton members. The skeleton members are the ones that contain bits and pieces of model JCL (in, of course, ISPF’s own unique skeleton syntax). Typically skeletons are used by programs when generating those jobs that seem to be created spontaneously on request under ISPF. IBM suggests you test skeleton changes by allocating the skeleton test library via LIBDEF; then, after updating any skeleton member(s), they suggest you reissue LIBDEFs as needed to force an OPEN for the ISPSLIB ddname (“Allocating required ISPF libraries” in the ISPF User’s Guide). Yes, you would really be using ddname ISPSUSR one would hope, but the logic is the same.
Active Libraries acquiring new disk extents
Another vulnerability particular to online systems such as TSO/ISPF is similar but worse. If any library within a concatenation acquires a new disk SPACE extent while the concatenation is open, that new area of space is invisible to the processes that fetch members for use by ISPF functions.
That problem arises because, for efficiency, the actual disk locations of data sets are checked only at OPEN time, and all of those disk addresses are remembered for later reference whenever members are to be fetched. Fetching runs much faster that way. But it means that any updated member placed into a subsequently obtained disk space extent cannot be found when an ISPF function wants to fetch it. Hence the member you've updated becomes invisible to ISPF for the duration of that execution. And this is true even if you’ve specified the TEST parameter to start ISPF. To be able to access the new extent you have to cause OPEN for the ddname to happen again. With ISPF libraries this means you need to exit ISPF and then start ISPF over again. You don’t actually need to logoff, just go back to READY mode and then start ISPF again.
Those are the main things you can trip over when concatenating ISPF libraries.
End of section on common problems.
End of article on Concatenating ISPF libraries.
* Thanks to Bob Banik for the idea for this post. . . . Not sure this is what he had in mind exactly of course . . . :-)
References, further reading
z/OS ISPF Dialog Developer's Guide and Reference, SC19-3619-00
ISPF test and trace modes
IBM Data Set Commander for z/OS User's Guide Ver 8.1
ISPF dialog development enhancements