|© 1986-2017 GSF Software LLC.|
This document present assembler programs and macro-instructions to support an internal SORT. They are:
CALLSORT, VSESORT and VSAMSORT are not-free products; if you are interested, please contact us.
CALLSORT is a macro instruction designed in the 1980s to help assembler programmers implement an internal SORT in DOS/VSE programs in a way compatible with MVS, OS/390 and z/OS.
CALLSORT may be implemented manually in existing programs that LOAD/CALL SORT directly. CALLSORT replaces the LOAD macro, the SORT parameter list, the SORT control statements, and executes SORT. Under certain conditions, Prism-CS can automatically implement CALLSORT during the conversion of assembler programs.
The same version of CALLSORT works in VSE and MVS, depending on the default value for the &SYSTEM operand.
CALLSORT supports DOS-type E15 and E35 exits. The code generated with SYSTEM=OS includes interface routines that allow DOS-type exits to function properly with an OS-type SORT utility.
In 1991/1992, CALLSORT was used under the name LOADSORT in the UGI VSE/MVS conversion project in Pennsylvania. UGI applications included over 2500 assembler programs, 700 of them had an internal SORT, and a small number had several internal SORTs.
In another VSE/MVS project during the 1990s, CALLSORT was used under the name EXECSORT which the customer preferred.
The CALLSORT macro supports the most important operands of the SORT, RECORD, INPFIL, OUTFIL, OPTION and MODS control statements.
symbol CALLSORT FIELDS=sort_criteria FORMAT=BI|CH FILES=number|(reg) WORK=number|(reg) SIZE=number|(reg) CHKPT=NO|YES TYPE=F|V LENGTH=(record_length_descriptor) INPFIL=character_string OUTFIL=character_string PH1=branch_table|(phase,length,E15) PH2=branch_table|(phase,length,E35) OPTION='compatible_options' DOSOPT='DOS-only_options' LOADPNT=load_point|(reg) RETCODE=return_code ERRET=error_routine SYSTEM=DOS|OS
FIELDS is a required operand. It must be coded exactly as in a SORT control statement.
FORMAT is optional. It may be specified only as FORMAT=BI or FORMAT=CH.
FILES is optional; it may be coded as a single digit (1-9) or as a register within parentheses. If a register is specified, it must contain the number of input files in its low-order byte as a character (X'F1'-X'F9'). Any register may be used (including R14-R0). This operand is not used in MVS.
WORK is optional and may be coded following the same rules as FILES. This operand is not used in MVS.
SIZE is optional; it may be coded as numeric value or as a register within parentheses. If a register is specified, the value it contains is converted to EBCDIC and placed into the SORT statement.
CHKPT is optional and may be given a YES or NO value. Specifying CHKPT=YES generates a CHKPT option on the SORT statement.
TYPE is a required operand that defines the record format (fixed or variable). It must be coded as TYPE=F or TYPE=V
LENGTH is a required operand that indicates the record length. It must be coded following the same rules as for the RECORD statement. Examples:
INPFIL is an optional operand in VSE, ignored in MVS. It contains all of the key-words that would normally be coded on the INPFIL control statement, except EXIT, which may not be specified. If multiple key-words are specified, the string must be enclosed in single quotes. If PH1 is specified, INPFIL must be omitted, and INPFIL EXIT will automatically be generated. This is required for compatibility with the MVS SORT utility which ignores SORTIN when an E15 exit is used. Example:
INPFIL='BLKSIZE=16000,CLOSE=UNLD' (SORTINx are read)
OUTFIL is an optional operand in VSE, ignored in MVS. It contains all of the key-words that would normally be coded on the OUTFIL control statement, except EXIT, which may not be specified. If multiple key-words are specified, the string must be enclosed in single quotes. If PH1 is specified, OUTFIL must be omitted, and OUTFIL EXIT will automatically be generated. This is required for compatibility with the MVS SORT utility which ignores SORTOUT when an E35 exit is used. Example:
OUTFIL='SYSLST' (Print Sorted Records)
PH1 is an optional operand that indicates how to access the E15 exit. An E15 exit may be internal (already in virtual storage when CALLSORT is issued) or external (SORT must load it). If E15 is internal (PH1=(,,E15) on the MODS card), PH1 must be specified as an A-type symbol that points to the Phase 1 branch table. If E15 is external, PH1 must be specified as on a MODS statement. Note that, for compatibility with the OS SORT utilities, only the E15 exit is supported. Examples:
PH1=E11BR (phase 1 branch table) PH1=(PH1CDSRT,L10000,E15) (PH1 is a separate phase)
PH3 is an optional operand. It plays the same role for E35 as PH1 does for E15. Only E35 exits are supported.
OPTION is an optional operand. It may be used to specify VSE/MVS compatible key-words (such as EQUALS) that are valid on an OPTION statement both under DOS and under OS. To ensure compatibility, it is important not to use it for VSE-only options such as PRINT=CRITICAL or LABEL. Example:
DOSOPT is a DOS-only operand that may be used to specify environment-specific options such as LABEL or FILENM. This operand is ignored in the MVS expansion of the macro. Example:
LOADPNT is an optional and DOS-only operand that may specify the address at which the SORT utility should be loaded. By default, SORT is loaded at the address contained in COMRG+40, rounded up to a multiple of 8.
RETCODE is optional. It may be used to indicate the name of a half-word that is to receive the return-code from the SORT. If RETCODE is omitted, the return code from SORT is available in R15 upon completion of the SORT invocation.
ERRET is optional. It may be used to indicate the name of an error routine to be invoked if the return-code from the SORT is not zero. ERRET and RETCODE are mutually exclusive.
SYSTEM indicates whether LOAD should expand into DOS or OS code. This operand need not be specified because the appropriate value is set when CALLSORT is installed in the macro library.
CALLSORT FIELDS=(1,5,A),FORMAT=BI, X TYPE=V,LENGTH=(33,,44), X INPFIL='BLKSIZE=4000', X OUTFIL='BLKSIZE=12000', X DOSOPT='LABEL=(S,S,U),NOTPMK', X RETCODE=RCSORT
CALLSORT FIELDS=(5,46,BI,A), X WORK=4,SIZE=99999, X TYPE=V,LENGTH=(1024,,,51,1024), X PH1=PGL15,PH3=PGL35, X LOADPNT=HICORE, X RETCODE=RETURN
CALLSORT FIELDS=(1,5,CH,A), X WORK=(R3),SIZE=(R4),FILES=(R5), X TYPE=F,LENGTH=6, X OPTION='EQUALS', X INPFIL='VSAM,TOL', X PH3=(PH3CDSRT,L1500,E35), X ERRET=DUMPIT
The CALLSORT macro generates the assembler code required for three basic functions:
Implementing CALLSORT consists in replacing the existing code used for these functions with a single macro, as shown in this example:
--(old VSE code)-- LA R1,=C'SORT ' L R0,=A(HICORE) LOAD Point LOAD (1),(0) LOAD SORT Program LR R15,R1 Entry Point Address LA R1,ADCONS SORT Parameter List BALR R14,R15 <-- CALL SORT OC RETURN,RETURN Check SORT Return-Code BNZ DUMPIT Not Zero, Error EOJ SORT OK, EOJ . . . . . . . . DUMPIT DUMP ABEND With DUMP . . . . . . . . ADCONS DC A(SORT) DC A(RECRD) DC A(INPFIL) DC A(OUTFIL) DC A(OPTION) DC A(MODS) DC A(PGL15) DC A(0) DC A(PGL35) DC A(RETURN) . . . . . . . . SORT DC C'SORT FIELDS=(5,46,BI,A),WORK=2 ' RECRD DC C'RECORD TYPE=V,LENGTH=(1024,,,51,1024) ' INPFIL DC C'INPFIL EXIT ' OUTFIL DC C'OUTFIL EXIT ' OPTION DC C'OPTION PRINT=CRITICAL ' MODS DC C'MODS PH1=(,,E15),PH3=(,,E35) ' RETURN DC H'0' DS 0D HICORE EQU *+8000
--(new VSE/MVS code)-- CALLSORT FIELDS=(5,46,BI,A),WORK=2, X TYPE=V,LENGTH=(1024,,,51,1024), X PH1=PGL15,PH3=PGL35, X LOADPNT=HICORE, X RETCODE=RETURN OC RETURN,RETURN Check SORT Return-Code BNZ DUMPIT Not Zero, Error EOJ SORT OK, EOJ . . . . . . . . DUMPIT DUMP ABEND With DUMP . . . . . . . . *DCONS DC A(SORT) * DC A(RECRD) * DC A(INPFIL) * DC A(OUTFIL) * DC A(OPTION) * DC A(MODS) * DC A(PGL15) * DC A(0) * DC A(PGL35) * DC A(RETURN) . . . . . . . . *ORT DC C'SORT FIELDS=(5,46,BI,A),WORK=2 ' *ECRD DC C'RECORD TYPE=V,LENGTH=(1024,,,51,1024) ' *NPFIL DC C'INPFIL EXIT ' *UTFIL DC C'OUTFIL EXIT ' *PTION DC C'OPTION PRINT=CRITICAL ' *ODS DC C'MODS PH1=(,,E15),PH3=(,,E35) ' RETURN DC H'0' * DS 0D *ICORE EQU *+8000
In MVS, a SORT exit that issues GET or PUT must load R13 with the address of its own save area. It is a good idea to do this at the beginning of the exit code, right after setting the base registers.
The save area must be different from the one used by the CALLSORT macro. If the same module contains both an E15 and E35 exit (i.e., both PH1 and PH3 exits), they may use the same save area.
Be careful that an exit may use the fact that R13 points to the caller's save area to pick up the value that R1 contained upon entry to the exit. When this is the case, an additional instruction is required to point to the caller's save area.
In the following example, only R13 is saved into REG13SAV; this is useless, unless the contents of R13 are modified. In MVS, the GET macro will overlay the registers stored by the SAVE macro. A proper save-area environment must be established as shown:
(BEFORE) E11 DC F'0' E15 SAVE (14,12) BALR R8,0 USING *,R8 ST R13,REG13SAV . . . . . . . . . . . . GET CARDIN,CARD . . . . . . . . . . . . BCKTOSRT L R13,REG13SAV L R1,24(,R13) R1 on entry MVC 0(4,R1),=A(CARD) pass record address L R2,8(,R1) address of command word MVC 0(4,R2),=F'12' pass return code RETURN (14,12) . . . . . . . . . . . . REG13SAV DS F
(AFTER) E11 DC F'0' E15 SAVE (14,12) BALR R8,0 USING *,R8 *@POS ST R13,REG13SAV ST R13,EXITSAVE+4 caller's save area @POS LA R13,EXITSAVE my own save area @POS . . . . . . . . . . . . GET CARDIN,CARD . . . . . . . . . . . . *CKTOSRT L R13,REG13SAV BCKTOSRT L R13,EXITSAVE+4 caller's save area @POS L R1,24(,R13) R1 on entry MVC 0(4,R1),=A(CARD) pass record address L R2,8(,R1) address of command word MVC 0(4,R2),=F'12' pass return code RETURN (14,12) . . . . . . . . . . . . *EG13SAV DS F EXITSAVE DS 18F save area @POS
The VSESORT utility program is an alternative to the CALLSORT macro instruction. VSESORT can only be used in MVS to simulate standard VSE SORT programs (IBM, SYNCSORT, CA-SORT). VSESORT is more recent than CALLSORT with which it has several differences:
If you are interested with CALLSORT or VSESORT, please contact us.
Here is an example of how the VSESORT utility program can be used:
. . . *dos LOAD SORT -MVS *dos LR 15,1 A(SORT) -MVS LOAD EP=VSESORT +MVS LR 15,0 A(VSESORT) +MVS CALL (15), X (#SORT, 1 X #RECORD, 2 X #INPFIL, 3 X #OUTFIL, 4 X #OPTION, 5 X #MODS, 6 X #PHASE1, 7 X #PHASE2, 8 X #PHASE3, 9 X #RETCODE, 10 X #ALTSEQ, 11 (OPT) X #OUTREC, 12 (OPT) X #SUM, 13 (OPT) X #INCLUDE, 14 (OPT) X #ANALYZE, 15 (OPT) X #INREC) 16 (OPT) . . . #SORT DC C'SORT FIELDS=(1,80,A),EQUALS,FILES=6,FORMAT=BI ' #RECORD DC C'RECORD TYPE=F,LENGTH=80 ' #INPFIL DC C'INPFIL EXIT ' #OUTFIL DC C'OUTFIL EXIT ' #OPTION DC C'OPTION DUMP,EQUALS,STORAGE=200K ' #MODS DC C'MODS PH1=(,,E15),PH3=(,,E35) ' #PHASE1 DC A(0) E11 B #E15-#PHASE1(,R15) E15 DC 2A(0) E17,E18 #PHASE2 DC 3A(0) E21,E25,E27 #PHASE3 DC 2A(0) E31,E32 B #E35-#PHASE3(,R15) E35 DC 3A(0) E37,E38,E39 #RETCODE DS H RETURN CODE #ALTSEQ EQU 0 #OUTREC EQU 0 #SUM DC C'SUM FIELDS=NONE ' #INCLUDE EQU 0 #ANALYZE EQU 0 #INREC EQU 0
VSAMSORT is an E15/E35 Exit Routine written in assembler; it adds several VSAM capabilities to DFSORT:
VSAMSORT was written and enhanced years ago to solve several differences that existed between VSE and MVS SORT utilities. Note that DFSORT now supports VSAM "suicide sort" when PARM=RESET is specified.
RECORD TYPE=V,LENGTH=(. . .) MODS E15=(VSAME15V,0),E35=(VSAME35,0)
1. Multiple Input Files (Two VSAM, One NON-VSAM); Output is VSAM or NON-VSAM+RECFM=VB
//SORT EXEC PGM=SORT //SYSOUT DD SYSOUT=* SORT FIELDS=(5,8,CH,A) RECORD TYPE=V,LENGTH=84 MODS E15=(VSAME15V,0) //E15IN1 DD DSN=VSAM.FILE1,DISP=SHR //E15IN2 DD DSN=VSAM.FILE2,DISP=SHR //E15IN3 DD DSN=NONVSAM.FILE1,DISP=SHR //SORTOUT DD DSN=MY.OUTPUT.FILE,DISP=(,CATLG),SPACE=(TRK,100)
2. VSAM "Suicide SORT"; The same VSAM file is both Input and Output
//SORT EXEC PGM=SORT //SYSOUT DD SYSOUT=* SORT FIELDS=(1,8,CH,A) RECORD TYPE=F,LENGTH=80 MODS E15=(VSAME15F,0),E35=(VSAME35,0) //E15IN1 DD DSN=VSAM.FILE1,DISP=SHR //SORTIN DD DSN=VSAM.FILE2,DISP=SHR //E35OUT DD DSN=VSAM.FILE1,DISP=SHR
EASYSORT OPEN, X TYPE=F,LENGTH=84, X FIELDS=(1,22,CH,A), X OPTION='EQUALS,RESINV=500K' OPEN (INFILE,INPUT) *loop Pass records to SORT (E15) LOOP15 GET INFILE read input record, set R1 EASYSORT PUT,(R1) pass record to E15 B LOOP15 *endloop LOOP15X CLOSE INFILE INFILE EODAD FREEPOOL INFILE OPEN (OUTFILE,OUTPUT) *loop LOOP35 EASYSORT GET,SET=(R3), Get sorted records from E35 X EODAD=ENDSORT exit loop at EOF PUT OUTFILE,(R3) write output record B LOOP35 *endloop ENDSORT EASYSORT CLOSE close E35 CLOSE (OUTFILE) FREEPOOL OUTFILE . . . . . . . . . . INFILE DCB DSORG=PS,DDNAME=INFILE,MACRF=GL,RECFM=FB,LRECL=84, X EODAD=LOOP15X OUTFILE DCB DSORG=PS,DDNAME=OUTFILE,MACRF=PM,RECFM=FB,LRECL=84 YREGS R0-R15