CALLSORT - Assembler Macro Instruction to invoke SORT in VSE and MVS

CALLSORT - Assembler Macro Instruction to invoke SORT in VSE and MVS

                 

This document present assembler programs and macro-instructions to support an internal SORT. They are:

  1. The CALLSORT Macro-Instruction
  2. The VSESORT program which is easier to implement and has fewer limitations than CALLSORT
  3. The VSAMSORT Exit Routine which adds VSAM capabilities to DFSORT
  4. The EASYSORT Macro-Instruction (Freeware)

CALLSORT, VSESORT and VSAMSORT are not-free products; if you are interested, please contact us.

1.0 CALLSORT

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.

1.1 Syntax

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.

Examples:

 FIELDS=(1,80,CH,A)

 FIELDS=(1,8,A,32,11,D) 

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.

Examples:

 FILES=1

 FILES=(R2) 

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.

Examples:

 SIZE=1234567

 SIZE=(R14) 

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:

 LENGTH=80

 LENGTH=(34,,56,,87) 

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:

 OPTION='EQUALS' 

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:

 DOSOPT='LABEL=(S,,N),PRINT=CRITICAL' 

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.

1.2 Coding Examples:

         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 

1.3 Implementation

The CALLSORT macro generates the assembler code required for three basic functions:

  1. calculate the load address, load SORT, invoke it via BALR and test (or store) the return code
  2. generate a SORT parameter list (a set of A-type addresses)
  3. generate a set of SORT control statements such as SORT, RECORD, etc.

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 

1.4 Programming notes:

1.5 Fixing R13 problems in PH1/PH3 exits

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 

2.0 VSESORT Utility Program

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 

3.0 VSAMSORT - VSAM E15/E35 Exit Routine

VSAMSORT is an E15/E35 Exit Routine written in assembler; it adds several VSAM capabilities to DFSORT:

  1. Multiple VSAM input data sets
  2. Mixed VSAM/non-VSAM input
  3. 99 input files (like SYNCSORT)
  4. Empty VSAM input data set
  5. VSAM "suicide sort" (same input and output)

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.

Input data sets

  1. specify ddnames "E15IN1" thru "E15IN9" or "E15IN01" thru "E15IN99";
  2. each ddname points to a separate data set.
  3. sequence numbers do not have to be contiguous
  4. the RECFM of non-VSAM data sets must match the type specification
  5. ddname "SORTIN" may also be specified in the JCL, it is read directly by the SORT utility.

Output data set

  1. if VSAME35 is used, specify ddname "E35OUT"
  2. if VSAME35 is not used, specify ddname "SORTOUT".

Implementation

Examples

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 

4.0 EASYSORT Assembler Macro Instruction

EASYSORT is a macro instruction freely available in FILE183.PDS and OSVS238J.TXT. EASYSORT only works in MVS, as shown in this example:

       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