How to print the output? "Printing" is usually easy. You usually use the PUT macro.
What's hard is preparing output to print. Every programmer develops methods to do this. These methods are often incomprehensible to other programmers, even programmers of similar skill levels.
1970s - During the 1970s I made one important decision.
All print type output would go to data sets with variable length records. This decision was based on the observation that most print records were much shorter than the maximum length print record. By using variable length records I would not have to bother with blanks at the right of the record, and, usually, the output data set would be smaller. I have seen no reason to waver from this decision.
1980s - In the early 1980s I wrote a program that formatted lists of linked data areas. There were a large number of these data areas, with a number of different fields. I realized when I started in on this that doing this the "usual" way would entail code that did very simple formatting many times over. Being a lazy sort I decided that the formatting could be done by preparing a format
element that described the type of input, the length of the output, and the offset in data area being formatted. This worked quite well. A couple of years later I wrote a new version of the program. The tables had changed, and the method to link that table entries together had changed, so modifying the old program was not a good idea. The formatting subroutine, on the other hand, stayed, though the formats had evolved to some extent. One big change is the formats allowed for imbedded text strings. I discovered I was using the format routine to prepare single use error type messages, which was never the original intent. A couple of years later I decided to investigate a more generalized format routine. I realized I was generating two types of messages; tabular messages with fixed width fields, and error type messages with variable length fields that demanded two format routines and two types of formats.
1990s - I rewrote the two 1980s routines because I had lost the source. As I used the two routines through the 1990s I made a significant change in the error message format routine; data area pointers were changed from address constants to use S-type address constants.
2000s - I started out by rewriting the error message format with the idea of imbedding the S-type address constants in the formats rather than in a remote address list. I suddenly reaiized that by tweaking the data element format to specify an output length I could write a common routine to generate both tabular reports as well as error messages. A typical format looks like this.
FMT01 DC AL1(L'FMT01A)
FMT01A DC C' UNABLE TO OPEN '
DC AL.2(3),AL.6(0),AL1(L'DCBDDNAM,0),SL2(DCBDDNAM)
DC X'FF'
This format has three elements
- An imbedded text sting, " UNABLE TO OPEN ", preceded by its length.
- A data string, in this case the string is located in DCBDDNAM. The first bit in the AL.2 indicates the format element is for data. The second bit indicates the data address is an S-type constant. If the bit is off, the data area address is a true address constant. The remaining 6 bits indicate the type of data; 0 indicates character data. The next byte indicates the data length, in this case the length the DD name area in a DCB. The next byte indicates the output data length. The 0 indicates trailing blanks in the data are not copied to the output. Next is either an S-type address or a 4 byte true address.
- An end of format, either X'FF' or X'00'
2010S - i rewrote the format programs. Actually there are two versions
- A subset version that is designed to be made a part of a program.
- A "full" version. The "full" version can format date and time data, either the system date and time or date and time stored as data. It has other capabiliies that are mainly of interest to a system programmer. The "full" version will process any format the subset version will process and produce identical output.
Having used these routines for more than 10 years, I can say the formats are not easy to write, especially the extended functions, but I can whip out the basic formats, like the one in the example, from memory. The 2010 version has not been touched since, well, 2010. They have ABENDed many times, but the root cause of the ABEND has always been a bad format, or a bad base register for an S-type address. There have been some surprises along the way.
- Binary data in a register when the format program is called can be formatted by using an S-type address constant to point to the register area in the save area active when the format program is called.
- The contents of register 0 can be used as a base register. Actually, I've never tried this, but I think it will work.