MVS TOOLS AND TRICKS OF THE TRADE MARCH 2000 Sam Golob MVS Systems Programmer P.O. Box 906 Tallman, New York 10982 Sam Golob is a Senior Systems Programmer. He also participates in library tours and book signings with his wife, author Courtney Taylor. Sam can be contacted at sbgolob@cbttape.org. Information about the CBT MVS Tapes can be found on the web, at http://www.cbttape.org. ASSEMBLER MACRO COLLECTIONS - PART 2 IBM has built an enormous amount of flexibility into the macro expansion facility of its S390 Assembler Language, which is now embodied in the High Level Assembler (HLASM). You can code an assembler macro to generate just about anything on an OS/390 system, after that macro has been assembled. You can even code one macro to generate a complete assembler program, or to PUNCH a large JCL stream. For example, you may remember the old SYSGEN process, which generated all the JCL necessary to put together the principal MVS operating system load libraries. A SYSGEN was coded entirely from assembler macros. You'd code the "Stage 1" SYSGEN entirely out of the IBM-supplied "SYSGEN macros" from SYS1.GENLIB or SYS1.AGENLIB. These then had to be assembled. The output of the assembly would be a huge JCL stream. This was the "Stage 2" of the SYSGEN, which was a complex assembly and linkedit jobstream, that was run against the IBM-supplied DLIBs (Distribution Libraries) of new modules, to create a newly tailored copy of the working operating system libraries. The Assembler macro facility is so versatile, that even a roomful of books can't describe all the possibilities of structures you can create with it. Today, we'll touch on several of the programming wonders, simple and complex, that have been created out of assembler macros by users like you and me. As we mentioned last month, a good source of user-written macro examples is the CBT MVS Utilities Tape, which, along with the CBT Overflow Tape, is a vast conglomeration of MVS system programmer's "goodies". This collection is now online. Though the collection has its own URL, it can currently also be reached through the "Members Only" section of www.naspa.net. In this column, we'll refer to various "files" from the CBT MVS Tape collection, as sources for some of the macros. These files (which are actually MVS pds'es) can be individually downloaded from the CBT Tape web site. A good book to learn macro coding from, and also to learn many techniques of Assembler Language programming, is: "Advanced Assembler Language and MVS Interfaces" by Carmine Cannatello (Second Edition - 1999) from John Wiley and Sons, Inc. ISBN: 0-471-36176-3. Carmine has graciously donated his machine-readable coding examples to the CBT Tape collection (File 069), for the benefit of everyone. Carmine's "Second Edition" coding examples may be found on Version 423 of the CBT Tape, and higher. Before Version 423 comes out, you can get them at: ftp://ftp.cbttape.org/pub/cbttape/adhoc/CBT069.zip . MACRO EXAMPLES - MESSAGING MACROS One of the more common uses of macros in assembler programs, is for writing messages. I've often seen home-grown messaging macros which make the formatting of an informational message very easy. Usually, coding the message, and having it routed to the proper place, only involves one line, or at most two, when a macro is being used for the purpose. On the other hand, to code all the logic necessary for all details of properly routing the message, without using a macro, might require five, or even more than ten lines, of complicated coding and calculation. If you have to repeat such message coding many times in a program, it obviously makes for much simplification to invoke one macro repeatedly, rather than code each message in "longhand". An IBM message invocation macro that is commonly used, is WTO, or "Write to Operator". A user program can invoke WTO in a very simple manner, coding: WTO 'message text' . When this macro is coded in a program, the program writes a message that is sent to the operator consoles. It is usually quite simple to invoke the WTO macro in a program. However, when expanded, this macro's "generated code" is not particularly simple at all. But the macro has achieved its purpose by making the coding in the program very easy. Use of the WTO macro, or the WTOR macro (Write to Operator with Reply) is described in the manual: OS/390 MVS Programming: Assembler Services Reference (GC28-1910), or MVS/ESA Assembler Programming Reference (GC28-1642). As an example of a program which uses a home-grown message macro, I can cite the COPYFILE program from File 316 of the CBT Tape. The purpose of the COPYFILE program is to copy selected standard labeled files from one tape to another. For example, using COPYFILE, you can copy SL files 7, 8 and 22 from tape volume TAPEAA to files 5, 6, and 7 of tape volume TAPEBB. In Figure 1, we see a graphic illustration of COPYFILE's use of the MSG macro, which formats the tape file copy report, and which simplifies the assembler code in the COPYFILE program very much. Please note carefully, what the MSG macro is doing. The MSG macro takes, as input, program variables such as the tape file number and the tape volume serial name. From these, the MSG macro constructs a composite message, which it loads into the MSGWRITE subroutine. The MSGWRITE subroutine, in turn, puts that message text out to the //MSG ddname, so it can be displayed to the user of the program. In my travels, I've found an even more sophisticated macro than the MSG macro and the MSGWRITE subroutine of CBT Tape File 316. This is Gilbert Saint-flour's STRING macro, which is used in many of his programs on CBT Tape File 183. Gilbert's STRING macro is functionally similar to the COBOL DISPLAY, or the PL/I PUT EDIT instructions. Using STRING, you can concatenate any number of fields, edit each of them if necessary, and get the result into the work area you specify. Much of STRING's flexibility lies in the fact that it can reformat numeric and date fields in a great number of different ways, before creating message text out of them. How does STRING work? STRING contains quite a few subprograms that are coded within it. Each of these subprograms performs a specific type of numeric conversion. You always code the STRING macro in two different ways. First, you invoke the STRING macro to format messages, perhaps many times within a program. Then you invoke it again at the end, using its GENERATE parameter. The GENERATE invocation of STRING looks at all the other invocations, and determines which kinds of numeric conversion need to be performed, and therefore which subroutines need to be called. GENERATE then calls up only the subroutines specifically needed by the first invocations of STRING, and puts only their code into the assembled program. GENERATE also constructs all the literals that are needed by the other invocations of the STRING macro in that program. You can easily see that STRING is very sophisticated and versatile, while making assembler coding much easier. ANOTHER MACRO USE - PROGRAM OPTION PACKAGING Large program packages often have hundreds of default options, many (or all) of which can be changed at installation time. The vendors of these packages have noticed that customers can get very confused, if they are forced to make hundreds of decisions, each time they install the product. The writers of these packages thus have the problem of simplifying the decision making during their installation process. Most customer installations will install a given software package in a "typical" way. That is, they'll keep most of the many options in a default state, only changing very few of them. Bruce Leland, one of the authors of the STARTOOL product, told me that he uses the assembler macro facility to simplify the customization of STARTOOL, which has hundreds of defaults that can potentially be changed by its customers. STARTOOL determines most of its option choices by consulting a certain load module, which contains all its defaults and their alternatives. This load module is assembled at STARTOOL installation time. Its assembly code is generated by coding installation macros. If a customer site decides to change options that are typically changed, these (relatively few) common choices are shown in Bruce's sample installation invocation. All the rest of the choices are taken care of by the macro coding internally, and are generally not noticed by a typical customer. However, if an installation wants to adjust one of the uncommonly changed defaults, its macro adjustment is listed as a comment in the sample "options gen", below the main coding. This arrangement has been reported to be well-received by STARTOOL's customer base, and STARTOOL's installation process is quite simple. I'd like to point out one of the very subtle things that's done "under the covers" by Bruce Leland's STARTOOL installation macros. Every time an installation will change a STARTOOL default, the macro will make a note of it, and will generate some message text. Upon invocation of the STARTOOL subcommand: 'CONTROL DEFAULTS', this text is displayed on the screen. So an installation can instantly determine the STARTOOL defaults that it has changed. This "magic" was all done by the installation macros at option assembly time. See how useful and clever, macro coding can be? At this point, I wish to express the hope that all of you will take some time to study a macro or two, to see how they are constructed. Macros generally make heavy use of the "conditional assembly" capability of the Assembler. This means that a macro can make many "decisions", depending on how it was initially coded, and also based on variable values within the invoking program. For example, conditional assembly defines "global" or "local" variables of three types: arithmentic, binary, or character, with GLBA, GLBB, or GLBC, LCLA, LCLB, or LCLC statements. The values of these variables are set, using SETA, SETB, or SETC statements. Conditional and unconditional branches, making judgments as to whether certain sections of code will be assembled or not, are controlled by AIF and AGO statements. String values, of precise lengths, can be carefully set and tested within the internal coding of a macro. The IBM manual: High Level Assembler - Language Reference (SC26-4940) has a wealth of information, in several chapters, about the details of macro coding. For now, I have to say goodbye until next month. I hope this month's discussion was useful to you, and I'm looking forward to seeing all of you again. * * * * * * * * * * * * * * * * * * * * * * * Figure 1. Illustration of COPYFILE message formatting. It uses the MSG macro, which invokes the MSGWRITE sub-program, that in turn, writes the formatted message to the //MSG ddname. The following is the //MSG file of a COPYFILE program invocation: ***SELECTED FILES ARE BEING COPIED FROM VOL=SER=TAPEAA TO VOL=SER=TAPEBB FILE 7 WAS COPIED TO FILE 5 DSN=TAPEAA.FILE0007 FILE 8 WAS COPIED TO FILE 6 DSN=TAPEAA.FILE0008 FILE 22 WAS COPIED TO FILE 7 DSN=TAPEAA.FILE0022 This message resulted from the following invocations of the MSG macro in the COPYFILE program. The MSG macro constructs the text of the message from program variables, and invokes the MSGWRITE subroutine that is linkedited into the COPYFILE program load module. MSGWRITE writes the formatted message, constructed by the MSG macro, into the print file defined by the //MSG DD card. The following MSG macro invocation: MSG '***SELECTED FILES ARE BEING COPIED FROM VOL=SER=',C'1', X (C,INVOL1,6,4),' TO VOL=SER=',(C,OUTVOL1,6,4) formats the report header. While the next invocation: MSG 'FILE ',(D,INFILE,3),' WAS COPIED TO FILE ',(D,OUTFILE,3),X ' DSN=',(C,DSN) documents which file from the input SL tape was copied to which file of the output SL tape, and what its dataset name was. For the record, this output has resulted from the following COPYFILE control cards: //SYSIN DD * 7/5 8 22 /* whereby file 7 of volume TAPEAA is to be copied into file 5 of TAPEBB, file 8 of TAPEAA goes into the next file (file 6) of TAPEBB and file 22 of TAPEAA goes into the next file (file 7) of TAPEBB.