Even before I created this site for Hercules, I had been maintaining a site which included programs I had written in the past, either in connection with my employment or just playing around. After I had MVT (and later MVS) running on my own computer under Hercules, I began finding reasons to pull some of these programs over and compile them under Hercules. It has occurred to me that some of them might be of interest to others, either for their intended function or as coding examples. So, I have added this page to contain them. I don't plan any grand scheme of organization for this page; I will just add programs as I get the time and the urge moves me. And now I find that there are useful programs written by other people that I have collected and have nowhere else on my site to place, so I have added another segment to this page to contain this type of program, properly attributed to the source.
Access PDS Members from COBOL
Comb Sort in COBOL
Dynamically Load Subprograms in MVT COBOL
Field Edit Routines
Generate DD Statements for Online DASD Devices
Issue Console Commands and Display Messages at Predefined Times
Prime VSAM Cluster
Pseudo-Random Number Generator
Report Step Completion Codes
Reset Dataset(s) to Empty
Retrieve JOB Card Information
Translate 3270 Buffer Addresses
(Assembler) I recently decided to try consolidating some programs I use to generate test data into a single run unit. The first hurdle was finding a suitable random number generator that I could implement under MVS 3.8. Unfortunately, the COBOL compiler we have available to us lacks those handy intrinsic functions, including RANDOM. I also found that there are not many solutions available in Assembler or COBOL. And those few I found (well, actually only a couple and they were very old) failed to built very random sets of numbers. I came up with a subroutine, written in Assembler, based on the Linear Congruential method (described in Knuth, Sedgewick, and in many places on the 'net). It isn't cryptographic quality, but will do for simulation and ad hoc sets of test numbers. I also wrote a COBOL program to do some analysis on the generated number sets. The jobstream contained in random.tgz [MD5: 2194283AC0C57ECCA347B1074E8788A7] will run the analysis program and illustrates how to link the Assembler routine to your own programs.
I recently had an inquiry regarding modifying this program to return the value in a format other than floating point. As a result, I have added instructions to the assembler routine to return the generated number in both the original floating point format and also the extracted fractional portion of the number as a fullword binary value. This version of the program is contained in random2.tgz [MD5: C0D8AECEDA0B3F08FA2A063D6575314B].
(Assembler) Back when Y2k was the buzzword of the day and everyone was doing remediation, I gathered together a lot of date manipulation routines I had written in prior years. They were originally written in COBOL, BASIC, and even Microsoft MASM. From this hodgepodge collection, I believe that I have put together a set of routines that will do just about anything one could want to do with a date. And when I rewrote them, they ended up in 370 Assembler.
I updated the installation procedure on September 2, 2003. So if you have an earlier version, and have checked back here and are worried that the version you got on an earlier date needs updating, relax. There have been no significant changes to the routines themselves, just an update to the jobstreams that load them onto your system.
The installation/verification jobstream is in y2k$load.tgz [MD5: 5cf2c71ad8ae7bfe3791069a6c0bb913]. This is an IEBUPDTE job that will create a PDS containing the assembler and COBOL source and three jobstreams, plus an index member ($INDEX). As configured for my system, the source/jobstream PDS is on a 3350, VOL=SER=SYSCPK, and is named SYSC.Y2K.SOURCE. You will probably want to change all of those parameters for your system. When the installation job runs, it will place the load modules into SYSC.LINKLIB (UNIT=3350,VOL=SER=SYSCPK)The source PDS and load librar are referenced in a number of DD cards in the jobstreams, so it would probably be easiest for you to use a text editor on your host OS (Linux/Windows/???) and make all the changes in the "reload" jobstream before you submit it to MVS.
Once the changes above are correct for your system, and you have created the source/JCL PDS, submit the jobstream: Y2K$ASM from the source/JCL PDS. This job assembles and link-edits all fourteen of the routines to the load library PDS. If you want to run the installation verification program, submit the jobstream: Y2K$IVP. This will compile and run a COBOL program which calls all the routines with a test data value.
Updated 04/2008 - I received a suggestion from Angel Luis Dominguez of slightly different code in the three places where I am determining a leap year. His code utilizes TM instructions on a binary field containing the four digit year instead of the original series of packed decimal divide instructions. On my Hercules' emulated system, 500,000 iterations saves 3.13 seconds of CPU time, so it could add up to some savings and is certainly cooler code. I am embarrassed to admit how long it took to update the source for the three programs affected, but it has now been completed. No other functionality is changed.
Update 04/2016 - I was working on COBOL versions of these programs for use on a Linux system (compiled with GNUCOBOL) and I needed to add code to the Installation Verification program to call Y2KESTR. While there I also updated the data file for the program to include the expected output in the input datastream to make verification of the results easier; then fed both changes back into this archive. Since I have modified my system to incorporate the source and load modules for these routines into SYSCPK, I did modify the jobstreams to reflect that environment.
(COBOL) The comb sort algorithm is an extended bubble sort that outperforms the basic bubble sort and is very simple to implement. This program reads in 10,000 records from SYSIN, sorts them, and prints the sort time and sorted records on SYSOUT. Under Hercules the times I saw were around 5/100ths of a second to sort the 10,000 randomly generated test records. The link to download the COBOL source is: combsort.tgz [MD5: 5501BBFD3B35AC4B49AE666D30663836]. (A slightly cleaner implementation with inline perform statements can be downloaded this link: combsort.cbl, but of course it will not compile with the MVT compiler).
(Assembler) I first started putting together this collection when I discovered BIF DEDIT didn't do much for fields entered into my CICS programs. But the collection first became a set, and also became re-entrant, back in 1993 when I had some spare time. The logic for the numbers to words routine (OFMTMONY) was originally in written in COBOL back in 1976 when another programmer told me I couldn't write the routine in COBOL efficiently enough to run in production.
I updated the installation procedure on September 3, 2003. So if you have an earlier version, and have checked back here and are worried that the version you got on an earlier date needs updating, relax. There have been no significant changes to the routines themselves, just an update to the jobstreams that load them onto your system. And I made a minor change to the Installation Verification COBOL program's report (the output for IFMTLJST was not printing the field returned from the assembler routine).
The installation/verification jobstream is in fmt$load.tgz [MD5: DF68D84AB0B125FB0797D25DCEF4254D]. This is an IEBUPDTE job that will create a PDS containing the assembler and COBOL source and three jobstreams, plus an index member ($INDEX). As configured for my system, the source/jobstream PDS is on a 3330, VOL=SER=JAY001, and is named JAY01.FORMAT.SOURCE. You will probably want to change all of those parameters for your system. When the installation jobs run, they will create a PDS load library. Again, on my system it is configured to reside on the same 3330 as the source library and is named JAY01.FORMAT.LOADLIB. These two datasets are referenced in a number of DD cards in the jobstreams, so it would probably be easiest for you to use a text editor on your host OS (Linux/Windows/???) and make all the changes in the "reload" jobstream before you submit it to MVS.
Once the changes above are correct for your system, and you have created the source/JCL PDS, submit the jobstream: FMT$INST from the source/JCL PDS. The first step of this job deletes the target load library so you can resubmit this job if you need to restart it or want to recreate the load library for any reason. The second step simply submits the jobstream: FMT$ASM from the source/JCL PDS. This job assembles and link-edits all eight of the routines to the load library PDS. If you want to run the installation verification program, submit the jobstream: FMT$IVP. This will compile and run a COBOL program which calls all the routines with a test data value.
(Assembler) I have been investigating 3270 Data Streams and wrote these two small programs that will translate a row and column to the equivalent 3270 Buffer Address (BA3270) and translate a 3270 Buffer Address to the equivalent row and column (BA3270R). They are quite simple to use:
To call from COBOL:000100 01 ROW-VALUE PIC 9(2). 000200 01 COLUMN-VALUE PIC 9(2). 000300 01 BUFFER-ADDRESS PIC X(2). 000400 000500 CALL 'BA3270' USING ROW-VALUE, COLUMN-VALUE, BUFFER-ADDRESS. 000600 CALL 'BA3270R' USING BUFFER-ADDRESS, ROW-VALUE, COLUMN-VALUE. 000700To call from Assembler:CALL BA3270,(ROW,COL,ADDRS) CALL BA3270R,(ADDRS,ROW,COL) ROW DS CL2 COL DS CL2 ADDRS DS CL2
Both programs are in the single archive: ba3270.tgz [MD5: E7D5242A949DA1BAE22EBA22545C77E3].
There are a number of utility programs that require a DD statement to be included for any DASD volume on which an action is to be performed - IEHPROGM and IEHDASDR are good examples. I stumbled upon a program that would do this on the Internet, but it would not work under MVS 3.8j. So I wrote a program that would provide this function for MVS 3.8j. The program scans the UCB table and generates a DD statement in the format:
//PUB002 DD UNIT=SYSDA,DISP=OLD,VOL=SER=PUB002 * DDDASD GENERATED
for each DASD type device that is mounted, placing the Volume Serial Number in the name field for the statement and in the VOL=SER= field.
The jobstream in dddasd.tgz [MD5: 549DD3CADC9449719A49AFA95F593D4C] will assemble/link the program into SYS2.LINKLIB. To execute the program, use the JCL:
// EXEC PGM=DDDASD //SYSUT1 DD DSN=<dataset to receive generated statements>, DCB=(RECFM=FB,LRECL=80,BLKSIZE=800), <other statements as required>
The following programs were not written by me, but lacking another existing page on which to include them and not wanting to create individual pages for a lot of miscellaneous programs, I am placing them here. I have been revisiting archives as I clean out a storage facility and some of the programs I have found there are too good not to share here. Perhaps someone else will find exactly the solution they have been searching for in this eclectic collection.
This assembler program was written by Steve Wentworth and solves the problem of opening an empty (newly created) VSAM cluster with a COBOL program for input/output. You will experience this even if you are using my VSAM I/O routines to open a newly created VSAM cluster as Input-Output and attempt to add a new record -- the write will fail because the HIGH-USED-RBA is 0. Steve's program will work with any KSDS cluster without modification; he uses SHOWCB/MODCB macros to tailor the key and record length to whatever is defined for the file pointed to by the DS DD at execution.
An installation jobstream with the source program and an execution jobstream are included in the archive: primevs.tgz [MD5: 57D64F0637EAD81DD2C132762FE6C0B8].
This assembler program will reset (empty) partitioned or sequential datasets in preparation for a reload. Datasets processed by this program will appear as though they have been deleted and re-allocated, however, the overhead of scratch/allocate and uncatalog/catalog is avoided. Additionally, datasets will still reside in the original location on the volume, which cannot be assured with scratch/allocate. This allows for permanent placement of datasets even though they may require reloading. Datasets to be reset are specified by one or more DD cards beginning RESET (the final three characters may be any legal DSName characters), so multiple datasets may be reset with each execution. No additional DD cards are required and no parameter information is necessary.
An installation jobstream with the source program and an execution jobstream are included in the archive: resetds.tgz [MD5: FABA6900B29CD15B992CF67938EEC0AC].
This assembler program allows high level access to PDS members from languages that may not have native means (COBOL, PL/I, etc). The source of the program is file #12 of the CBT Overflow tape. This file originated from UK GUIDE and the routine itself came from Smith International (North Sea) Ltd.
Update: It was reported to me by Vincent Coen that this routine abends with a S0C4 (addressing exception) when attempting to retrieve all records of a member when the member occupies more than a single block on the PDS. I had not personally used the routine to do more than read a few parameter card image records from a single member, so I had not experienced this, nor had I had this reported to me previously. Just prior to heading off into a dump to attempt to resolve it, I thought to check CBT to see if anyone else had already fixed the problem. Fortunately, Harold Zbiegien has fixed the problem and uploaded his corrected version to file #152 of the current CBT tape (#488). I have updated my installation jobstream, replacing the original version with Harold's version. Harold's version includes the addition of an additional parameter to facilitate modifying the DDNAME for the dataset to be utilized prior to opening the dataset, so I have modified my example program to match Harold's version of the subprogram.
I have also included a very simple example program in COBOL to illustrate the use of the program and to verify correct installation. Note that the documentation for the routine, embedded in the assembler source, is incorrect with regards to the return code obtained upon reaching the end of a member on a read command; the actual value returned is 4 rather than 8.
The installation jobstream - install.jcl - and the sample program - ivp.jcl - are contained in the archive: ncz93205.tgz [MD5: 884ab95523b30bf7fa78a40e93a3f436]. My jobstream installs the routine into SYS2.LINKLIB, which may be changed to suit your environment.
This assembler program runs as a started task, initially executed at IPL time. It automatically schedules itself to start every two hours, or at the time of the next scheduled event, if an event is scheduled to occur sooner than the next two hour "window". The scheduled events are read from a parameter member and may be either a message to display on the console or an MVS console command to be executed. A field in the event table designates the table entry as relevant to any machine or a specific machine based upon the System IDentification string.
I prefer to have automatically issued commands "echoed" to the console as well as executed so that there is a record of commands executed. The display code in the original version of this program placed displayed messages with DESC=(2) by default, which made them non-rollable. This is probably a desirable feature for critical messages, but not necessary to "echo" commands. So I duplicated the WTO code to provide both a high intensity, non-rollable message and regular intensity, rollable message facility, selectable by DSH or DSN on the schedule table entry. My installation jobstream creates both a procedure and parameter member for the program and there is an example of automatic commands with low-intensity displays in the jobstream.
I have also modified the code to retrieve the System IDentification from control blocks rather than scanning the SMF parameters every execution. The overhead saved by eliminating the file access is probably minimal, especially on the Hercules' platform, but it simply seems more efficient to me.
All of my modifications may be identified by the presence of the string '*JLM*' in the right margin of the line.
The jobstream to assemble and link-edit the program, plus install the procedure and parameter member is in ztimer.tgz [MD5: 4018FA80ED50877E45168CD2FEDAF4E1]. The program must be in an authorized library and the jobstream is set up with SYS2.LINKLIB as a target. SYS1.LINKLIB may be used if you do not have a SYS2.LINKLIB set up as an authorized library. The target for the procedure is SYS2.PROCLIB, but SYS1.PROCLIB may be substituted. The target for the parameter is SYS2.CONTROL, but SYS1.PARMLIB may be substituted (don't forget to change the procedure if you are not using SYS2.CONTROL). Also, you should place a START command for the program in your COMMAND member so that it will be started after each IPL.
DYNALOAD is one of several utilities written by Ed Liss. He has other useful utilities available on his site: http://clemporium.comli.com/hercules, but I will continue to provide DYNALOAD on this page and it will be included on the Compiler/Language/Tools Volume that I maintain as it provides an extremely desirable and needed function to programs compiled with the MVT COBOL compiler available for use under MVS 3.8.
In later versions of IBM COBOL compilers, depending upon compile time options and/or method of coding the CALL verb, execution of the called subprogram could be either Static or Dynamic.
In the Static case, the object code for the called subprogram was bound to the main program by the Link Editor at compile time. If the subprogram was later changed and recompiled, it was necessary to re-link the calling program in order to utilize the updated subprogram. In the case of large applications, where there might be many shared subprograms, a change to even a single subprogram might result in much re-linking and a huge system management task.
When Dynamic subprogram calling became available, subprograms were no longer bound to the main program by the Link Editor, but were compiled as separate load modules. At execution time, when a CALL statement was executed, the load module for the subprogram was loaded into memory and executed. It was no longer necessary to re-link every main program that called a subroutine when the subroutine was modified.
The MVT COBOL compiler predates the ability to have Dynamic CALLs. Ed Liss' DYNALOAD subprogram provides that functionality. His archive contains installation instructions, the Assembler DYNALOAD subprogram, and a couple of COBOL programs to demonstrate its use. Download the archive - dynaload.zip [MD5: 22E13CE145153B1D4A3371F4B5DF89E4] - from this site and follow the installation instructions in the readme file contained therein.
This subroutine will traverse MVS control blocks to extract information contained in fields on the JOB card and return them to the caller. The original program code is located in File #65 of the CBT overflow tape and is part of a collection from the Los Angeles User Group tape. I found that the JES Job Number field was not returned using the program as supplied and I believe that the reason is that the program is coded to retrieve the JES Job Number from a field maintained under JES3. So I left the original code intact and added code following it to retrieve the JES2 Job Number. My added lines are identified by *jlm* beginning in column 67 of each line.
Download the archive - jobcrd.zip [MD5: 858D14DEB322E0637D1AD7BED39635B6] - from this site. The archive contains two jobstreams:
The jobcrd$ jobstream places the load module for the subroutine in SYS2.OBJLIB, which is defined on my system to contain this type of module which is to be subsequently linked or called by another program. You will probably need to change the target to a library that is defined on your system. Likewise, the jobcrd@ jobstream uses an override in the link step to allow the link editor to access the subroutine from this library; you will need to change this override to match whatever change you make in the first jobstream.
Note: This archive and the jobstreams contained within were created on a Windows system. Each line is terminated by x'0d0a'. If you download them to a Linux system you will need to strip the x'0d' using a utility such as fromdos.
This program is executed as the final step of any batch job to send a report of the completion codes for all the preceding steps of the job to a dataset (SYSPRINT DD statement), one or more consoles (via ROUT parameter), and/or one or more TSO User IDs (via SEND). I found this on an old NASPA CD and I believe the originator of the program was Don Frasier at Western Atlas International in Houston, TX, but there is no attribution in the source and I have made this inference from other programs contained in the same location. As provided, there were some problems that prevented the program from assembling, which I have corrected. You can find my corrections by searching for *JLM* in column 67 of the source. The instructions are simple and stated well in the comments from the source:
THIS PROGRAM IS DESIGNED TO REPORT STEP COMPLETION CODES FOR BATCH JOBS. WHAT AND WHERE IT WRITES IS DETERMINED BY A PARAMETER LIST AND A DD STATEMENT. THE PROGRAM IS TO BE RUN AS ITS OWN JOBSTEP FOLLOWING ANY JOBSTEPS THAT IT IS TO REPORT ON. FOLLOWING IS A JCL EXAMPLE: //* //COMPCODE EXEC PGM=COMPCODE,COND=EVEN, // PARM='USER=(RWGV3),ROUT=(2,3,11),STEP=(ASMFCL.*,TESTER)' //SYSPRINT DD DSN=RWGV3.SYSPRINT,DISP=MOD //* (1) COND=EVEN SHOULD ALWAYS BE SPECIFIED SO THAT THE STEP WILL EXECUTE EVEN IF A PREVIOUS STEP HAS ABENDED. (2) VALID PARMS ARE AS FOLLOWS: (A) USER= SPECIFIES WHICH USER(S) ARE TO BE NOTIFIED BY COMPCODE. THIS PARAMETER IS OPTIONAL. THE USER LIST MUST BE ENCLOSED IN PARENTHESIS EVEN IF ONLY ONE USER IS SPECIFIED. EX. USER=(S001,S002) OR USER=(S001). THE MAXIMUM NUMBER OF USERS IS THREE. IF NO USERS ARE SPECIFIED, NO USERS WILL BE NOTIFIED. (B) ROUT= SPECIFIES THE ROUTE CODES THAT THE MESSAGE(S) ARE TO BE SENT TO. THIS PARAMETER IS OPTIONAL. THE ROUTCDE LIST MUST BE ENCLOSED IN PARENTHESIS EVEN IF ONLY ONE ROUTE CODE IS SPECIFIED. EX. ROUT=(1,2,3) OR ROUT=(3). VALID ROUTE CODES ARE 1-16. IF NO ROUTE CODES ARE SPECIFIED, NO MESSAGES WILL BE SENT TO OPERATOR CONSOLES. (C) STEP= SPECIFIES THE STEP(S) THAT COMPCODE IS TO REPORT ON. THIS PARAMETER IS OPTIONAL. IF OMITTED, ALL STEPS WILL BE REPORTED ON (EXCEPT FOR STEPS THAT HAVE NOT YET EXECUTED OR THE "COMPCODE" STEP, BOTH OF WHICH ARE NEVER LISTED). THE STEP LIST MUST BE ENCLOSED IN PARENTHESIS EVEN IF ONLY ONE STEP IS SPECIFIED. STEPS MUST BE INDICATED IN ONE OF THREE WAYS: (1) PROGRAM EXECUTION - WHERE THE EXEC CARD SPECIFIES PGM=. FOR //STEP1 DD PGM=IEBGENER, THE STEP PARM WOULD READ: STEP=(STEP1,ETC,ETC) (2) PROC EXECUTION(SINGLE STEP) - WHERE THE EXEC CARD SPECIFIES A PROC AND ONLY ONE STEP OF THE PROC IS TO BE REPORTED ON. FOR //ASMNLINK EXEC ASMFCL, TO GET ONLY THE LKED STEP, THE STEP PARM WOULD READ: STEP=(ASMNLINK.LKED,ETC,ETC) (3) PROC EXECUTION(ALL STEPS) - WHERE THE EXEC CARD SPECIFIES A PROC AND ALL STEPS FOR THE PROC ARE TO BE REPORTED ON. FOR //ASMNLINK EXEC ASMFCL, TO GET ALL STEPS, THE STEP PARM WOULD READ: STEP=(ASMNLINK.*,ETC,ETC) (3) SYSPRINT DD STATEMENT - IF A SYSPRINT DD STATEMENT IS INCLUDED, THE MESSAGE WILL BE WRITTEN INTO THE DATASET SPECIFIED IN ADDITION TO THE USER= AND ROUT= REPORTING. IF THE DATASET EXISTS AND HAS DCB ATTRIBUTES, THEY ARE NOT CHANGED. IF NO DCB ATTRIBUTES ARE SPECIFIED, THE DATA IS WRITTEN AS RECFM=FB,LRECL=133,BLKSIZE=6118. (4) SNAPDUMP DD STATEMENT - THIS DD STATEMENT IS TO BE USED FOR DIAGNOSTIC PURPOSES ONLY. IF INCLUDED, A SNAPDUMP OF THE PERTINENT CONTROL BLOCKS WILL BE DONE. NOTE THAT THE DCB ATTRIBUTES FOR THIS DCB ARE HARD-CODED TO RECFM=VBA,LRECL=125,BLKSIZE=1632, A RESTRICTION IMPOSED BY THE SNAP FACILITY. * NOTE: THAT THIS PROGRAM MUST RUN APF-AUTHORIZED IF THE "USER=" PARAMETER IS SPECIFIED.
Download the archive - compcode.tar.gz
[MD5: 9d2afb728b05c7c667300608ccf53a02] -
from this site. The archive contains the single jobstream to assemble and
link the load module. The target load library is SYS2.LINKLIB; if you do
not have a SYS2.LINKLIB, the load module may be placed in SYS1.LINKLIB.
The load module must be executed from an authorized load library if the USER=
parameter is employed.
Return to Site Home Page