Document revision date: 30 March 2001

## OpenVMS Utility Routines Manual

Previous | Contents | Index

### 18.2.1 Arguments to SOR Routines

For a sort operation, the arguments to the SOR routines provide SORT with file specifications, key information, and instructions about the sorting process. For a merge operation, the arguments to the SOR routines provide MERGE with the number of input files, input and output file specifications, record information, key information, and input routine information. To perform sort or merge operations, you must pass key information (key_buffer argument) to either the SOR$BEGIN_SORT or SOR$BEGIN_MERGE routine. The key_buffer argument is passed as an array of words. The first word of the array contains the number of keys to be used in the sort or merge. Each block of four words that follows describes one key (multiple keys are listed in order of their priority):

- The first word of each block describes the key data type.
- The second word determines the sort or merge order (0 for ascending, 1 for descending).
- The third word describes the relative offset of the key (beginning at position 0).
- The fourth word describes the length of the key in bytes.

There are both mandatory and optional arguments. The mandatory arguments appear first in the argument list. You must specify all arguments in the order in which they are positioned in the argument list, separating each with a comma. Pass a zero by value to specify any optional arguments that you are omitting from within the list. You can end the argument list any time after specifying all the mandatory and desired optional arguments.

### 18.2.2 Interfaces to SOR Routines

You can submit data to the SOR routines as complete files or as single records. When your program submits one or more files to SORT or MERGE, which then creates one sorted or merged output file, you are using the file interface. When your program submits records one at a time and then receives the ordered records one at a time, you are using the record interface.

You can combine the file interface with the record interface by submitting files on input and receiving the ordered records on output or by releasing records on input and writing the ordered records to a file on output. Combining the two interfaces provides greater flexibility. If you use the record interface on input, you can process the records before they are sorted; if you use the record interface on output, you can process the records after they are sorted.

The SOR routines used and the order in which they are called depend on the type of interface used in a sorting or merging operation. The following sections detail the calling sequence for each of the interfaces.

#### 18.2.2.1 Sort Operation Using File Interface

For a sort operation using the file interface, pass the input and output file specifications to SORT by calling SOR$PASS_FILES. You must call SOR$PASS_FILES for each input file specification. Pass the output file specification in the first call. If no input files are specified before the call to SOR$BEGIN_SORT, the record interface is used for input; if no output file is specified, the record interface is used for output.

Next, call SOR$BEGIN_SORT to pass instructions about keys and sort options. At this point, you must indicate whether you want to use your own key comparison routine. (This feature is not currently supported by the high-performance Sort/Merge utility.) SORT automatically generates a key comparison routine that is efficient for key data types; however, you might want to provide your own comparison routine to handle special sorting requirements. (For example, you might want names beginning with "Mc" and "Mac" to be placed together.) If you use your own key comparison routine, you must pass its address with the user_compare argument.

Call SOR$SORT_MERGE to execute the sort and direct the sorted records to the output file. Finally, call SOR$END_SORT to end the sort and release resources. The SOR$END_SORT routine can be called at any time to abort a sort or to merge and release all resources allocated to the sort or merge process.

#### 18.2.2.2 Sort Operation Using Record Interface

For a sort operation using the record interface, first call SOR$BEGIN_SORT. As in the file interface, this routine sets up work areas and passes arguments that define keys and sort options. Note that, if you use the record interface, you must use a record-sorting process (not a tag, address, or index process).

Next, call SOR$RELEASE_REC to release a record to SORT. Call SOR$RELEASE_REC once for each record to be released. After all records have been passed to SORT, call SOR$SORT_MERGE to perform the sorting.

After the sort has been performed, call SOR$RETURN_REC to return a record from the sort operation. Call this routine once for each record to be returned. Finally, call the last routine, SOR$END_SORT, to complete the sort operation and release resources.

#### 18.2.2.3 Merge Operation Using File Interface

For a merge operation using the file interface, pass the input and output file specifications to MERGE by calling SOR$PASS_FILES. You can merge up to 10 input files. (The high-performance Sort/Merge utility allows you to merge up to 12 input files.) by calling SOR$PASS_FILES once for each file. Pass the file specification for the merged output file in the first call. If no input files are specified before the call to SOR$BEGIN_MERGE, the record interface is used for input; if no output file is specified, the record interface is used for output.

Next, to execute the merge, call SOR$BEGIN_MERGE to pass key information and merge options. At this point, you must indicate whether you want to use your own key comparison routine tailored to your data. (This feature is not currently supported by the high-performance Sort/Merge utility.) Finally, call SOR$END_SORT to release resources.

#### 18.2.2.4 Merge Operation Using Record Interface

For a merge operation using the record interface, first call SOR$BEGIN_MERGE. As in the file interface, this routine passes arguments that define keys and merge options. It also issues the first call to the input routine, which you must create, to begin releasing records to the merge.

Next, call SOR$RETURN_REC to return the merged records to your program. You must call this routine once for each record to be returned. SOR$RETURN_REC continues to call the input routine. MERGE, unlike SORT, does not need to hold all the records before it can begin returning them in the desired order. Releasing, merging, and returning records all take place in this phase of the merge.

Finally, after all the records have been returned, call the last routine, SOR$END_SORT, to clean up and release resources.

### 18.2.3 Reentrancy

The SOR routines are reentrant; that is, a number of sort or merge operations can be active at the same time. Thus, a program does not need to finish one sort or merge operation before beginning another. For example, reentrancy lets you perform multiple sorts on a file such as a mailing list and to create several output files, one with the records sorted by name, another sorted by state, another sorted by zip code, and so on.

The context argument, which can optionally be passed with any of the SOR routines, distinguishes among multiple sort or merge operations. When using multiple sort or merge operations, the context argument is required. On the first call, the context longword must be zero. It is then set (by SORT/MERGE) to a value identifying the sort or merge operation. Additional calls to the same sort or merge operation must pass the same context longword. The SOR$END_SORT routine clears the context longword.

## 18.3 Using the SOR Routines: Examples

This section provides examples of using the SOR routines for various operations including the following:

- Example 18-1 is a Compaq Fortran program that demonstrates a merge operation using a record interface.
- Example 18-2 is a Compaq Fortran program that demonstrates a sort operation using a file interface on input and a record interface on output.
- Example 18-3 is a Compaq Pascal program that demonstrates a merge operation using a file interface.
- Example 18-4 is a Compaq Pascal program that demonstrates a sort operation using a record interface.
- Example 18-5 is a Compaq C program that demonstrates a sort operation using the STABLE option and two text keys.

Example 18-1 Using SOR Routines to Perform a Merge Using Record Interface in a Compaq Fortran Program

            Fortran Program
    C...
    C...    This program demonstrates the Fortran calling sequences
    C...    for the merge record interface.
    C...
    C
    C       THE INPUT FILES ARE LISTED BELOW.
    C
    C               INFILE1.DAT
    C
    C 1 BBBBBBBBBB REST OF DATA IN RECORD................................END OF RECORD
    C 2 UUUUUUUUUU REST OF DATA IN RECORD................................END OF RECORD
    C
    C               INFILE2.DAT
    C
    C 1 AAAAAAAAAA REST OF DATA IN RECORD................................END OF RECORD
    C 2 TTTTTTTTTT REST OF DATA IN RECORD................................END OF RECORD
    C
    C               INFILE3.DAT
    C
    C 1 TTTTTTTTTT REST OF DATA IN RECORD................................END OF RECORD
    C 2 BBBBBBBBBB REST OF DATA IN RECORD................................END OF RECORD
    C
    C               FOROUT.DAT
    C
    C 1 AAAAAAAAAA REST OF DATA IN RECORD................................END OF RECORD
    C 1 BBBBBBBBBB REST OF DATA IN RECORD................................END OF RECORD
    C 1 TTTTTTTTTT REST OF DATA IN RECORD................................END OF RECORD
    C 2 BBBBBBBBBB REST OF DATA IN RECORD................................END OF RECORD
    C 2 TTTTTTTTTT REST OF DATA IN RECORD................................END OF RECORD
    C 2 UUUUUUUUUU REST OF DATA IN RECORD................................END OF RECORD
    C
    C
    C.................................................................................
    C
    C

            IMPLICIT INTEGER (A-Z)

            CHARACTER*80 REC                        ! A record.

            EXTERNAL READ_REC                       ! Routine to read a record.
            EXTERNAL KOMPAR                         ! Routine to compare records.
            EXTERNAL SS$_ENDOFFILE                  ! System end-of-file value

            INTEGER*4 SOR$BEGIN_MERGE               ! SORT/MERGE function names
            INTEGER*4 SOR$RETURN_REC
            INTEGER*4 SOR$END_SORT
            INTEGER*4 ISTAT                         ! storage for SORT/MERGE function value
            INTEGER*4 LENGTH                        ! length of the returned record
            INTEGER*2 LRL                           ! Longest Record Length (LRL)

            LOGICAL*1 ORDER                         ! #files to merge (merge order)

            DATA ORDER,LRL/3,80/                    ! Order of the merge=3,LRL=80
    C...
    C...    First open all the input files.
    C...
            OPEN (UNIT=10, FILE='INFILE1.DAT',TYPE='OLD',READONLY,
         *  FORM='FORMATTED')
            OPEN (UNIT=11, FILE='INFILE2.DAT',TYPE='OLD',READONLY,
         *  FORM='FORMATTED')
            OPEN (UNIT=12, FILE='INFILE3.DAT',TYPE='OLD',READONLY,
         *  FORM='FORMATTED')
    C
    C...    Open the output file.
    C
            OPEN (UNIT=8, FILE='TEMP.TMP', TYPE='NEW')
    C...
    C...    Initialize the merge.  Pass the merge order, the largest
    C...    record length, the compare routine address, and the
    C...    input routine address.
    C...
            ISTAT = SOR$BEGIN_MERGE (,LRL,,ORDER,
         *  KOMPAR,,READ_REC)
            IF (.NOT. ISTAT) GOTO 10        ! Check for error.

    C...
    C...    Now loop getting merged records.  SOR$RETURN_REC will
    C...    call READ_REC when it needs input.
    C...
    5       ISTAT = SOR$RETURN_REC (REC, LENGTH)
            IF (ISTAT .EQ. %LOC(SS$_ENDOFFILE)) GO TO 30    ! Check for end of file.
            IF (.NOT. ISTAT) GO TO 10       ! Check for error.

            WRITE(8,200) REC                        ! Output the record.
    200     FORMAT(' ',A)
            GOTO 5                                  ! And loop back.
    C...
    C...    Now tell SORT that we are all done.
    C...

    30      ISTAT = SOR$END_SORT()
            IF (.NOT. ISTAT) GOTO 10        ! Check for error.
            CALL EXIT

    C...
    C...    Here if an error occurred.  Write out the error status
    C...    and exit.
    C...
    10      WRITE(8,201)ISTAT
    201     FORMAT(' ?ERROR CODE', I20)
            CALL EXIT
            END

            FUNCTION READ_REC (RECX, FILE, SIZE)
    C...
    C...    This routine reads a record from one of the input files
    C...    for merging.  It will be called by SOR$BEGIN_MERGE and by
    C...    SOR$RETURN_REC.
    C...    Parameters:
    C...
    C...            RECX.wcp.ds     character buffer to hold the record after
    C...                            it is read in.
    C...
    C...            FILE.rl.r       indicates which file the record is
    C...                            to be read from.  1 specifies the
    C...                            first file, 2 specifies the second
    C...                            etc.
    C...
    C...            LENGTH.wl.r     is the actual number of bytes in
    C...                            the record.  This is set by READ_REC.
    C...
            IMPLICIT INTEGER (A-Z)

            PARAMETER MAXFIL=10                     ! Max number of files.

            EXTERNAL SS$_ENDOFFILE                  ! End of file status code.
            EXTERNAL SS$_NORMAL                     ! Success status code.

            LOGICAL*1 FILTAB(MAXFIL)
            CHARACTER*(80) RECX                     ! MAX LRL =80

            DATA FILTAB/10,11,12,13,14,15,16,17,18,19/ ! Table of I/O unit numbers.

            READ_REC = %LOC(SS$_ENDOFFILE)         ! Give end of file return
            IF (FILE .LT. 1 .OR. FILE .GT. MAXFIL) RETURN   !   if illegal call.

            READ (FILTAB(FILE), 100, ERR=75, END=50) RECX   ! Read the record.
    100     FORMAT(A)

            READ_REC = %LOC(SS$_NORMAL)             ! Return success code.
            SIZE = LEN (RECX)                       ! Return size of record.
            RETURN

    C...    Here if end of file.
    50      READ_REC = %LOC(SS$_ENDOFFILE)          ! Return "end of file" code.
            RETURN

    C...    Here if error while reading
    75      READ_REC = 0
            SIZE = 0
            RETURN
            END

            FUNCTION KOMPAR (REC1,REC2)
    C...
    C...    This routine compares two records.  It returns -1
    C...    if the first record is smaller than the second,
    C...    0 if the records are equal, and 1 if the first record
    C...    is larger than the second.
    C...
            PARAMETER KEYSIZ=10

            IMPLICIT INTEGER (A-Z)

            LOGICAL*1 REC1(KEYSIZ),REC2(KEYSIZ)

            DO 20 I=1,KEYSIZ
            KOMPAR = REC1(I) - REC2(I)
            IF (KOMPAR .NE. 0) GOTO 50
    20      CONTINUE

            RETURN

    50      KOMPAR = ISIGN (1, KOMPAR)
            RETURN
            END

Example 18-2 is a Compaq Fortran program that demonstrates a sort operation using a file interface on input and a record interface on output.

Example 18-2 Using SOR Routines to Sort Using Mixed Interface in a Compaq Fortran Program

    Program

            PROGRAM CALLSORT
    C
    C
    C       This is a sample Fortran program that calls the SOR
    C       routines using the file interface for input and the
    C       record interface for output.  This program requests
    C       a record sort of the file 'R010SQ.DAT'  and  writes
    C       the records to SYS$OUTPUT.  The key is  an  80-byte
    C       character ascending  key starting in  position 1 of
    C       each record.
    C
    C       A short version of the input and output files follows:
    C
    C                       Input file R010SQ.DAT
    C 1 BBBBBBBBBB REST OF DATA IN RECORD................................END OF RECORD
    C 2 UUUUUUUUUU REST OF DATA IN RECORD................................END OF RECORD
    C 1 AAAAAAAAAA REST OF DATA IN RECORD................................END OF RECORD
    C 2 TTTTTTTTTT REST OF DATA IN RECORD................................END OF RECORD
    C 1 TTTTTTTTTT REST OF DATA IN RECORD................................END OF RECORD
    C 2 BBBBBBBBBB REST OF DATA IN RECORD................................END OF RECORD
    C 1 QQQQQQQQQQ REST OF DATA IN RECORD................................END OF RECORD
    C 2 AAAAAAAAAA REST OF DATA IN RECORD................................END OF RECORD
    C 1 UUUUUUUUUU REST OF DATA IN RECORD................................END OF RECORD
    C 2 QQQQQQQQQQ REST OF DATA IN RECORD................................END OF RECORD
    C
    C                       Output file SYS$OUTPUT
    C
    C 1 AAAAAAAAAA REST OF DATA IN RECORD...............................END OF RECORD
    C 1 BBBBBBBBBB REST OF DATA IN RECORD...............................END OF RECORD
    C 1 QQQQQQQQQQ REST OF DATA IN RECORD...............................END OF RECORD
    C 1 TTTTTTTTTT REST OF DATA IN RECORD...............................END OF RECORD
    C 1 UUUUUUUUUU REST OF DATA IN RECORD...............................END OF RECORD
    C 2 AAAAAAAAAA REST OF DATA IN RECORD...............................END OF RECORD
    C 2 BBBBBBBBBB REST OF DATA IN RECORD...............................END OF RECORD
    C 2 QQQQQQQQQQ REST OF DATA IN RECORD...............................END OF RECORD
    C 2 TTTTTTTTTT REST OF DATA IN RECORD...............................END OF RECORD
    C 2 UUUUUUUUUU REST OF DATA IN RECORD...............................END OF RECORD
    C
    C-----------------------------------------------------------------------------
    C
    C       Define external functions and data.
    C
            CHARACTER*80 RECBUF
            CHARACTER*10 INPUTNAME          !Input file name
            INTEGER*2 KEYBUF(5)             !Key definition buffer
            INTEGER*4 SOR$PASS_FILES        !SORT function names
            INTEGER*4 SOR$BEGIN_SORT
            INTEGER*4 SOR$SORT_MERGE
            INTEGER*4 SOR$RETURN_REC
            INTEGER*4 SOR$END_SORT
            INTEGER*4 ISTATUS               !Storage for SORT function value
            EXTERNAL SS$_ENDOFFILE
            EXTERNAL DSC$K_DTYPE_T
            EXTERNAL SOR$GK_RECORD
            INTEGER*4 SRTTYPE

    C
    C       Initialize data -- first the file names, then the key buffer for
    C       one 80-byte character key starting in position 1, 3 work files,
    C       and a record sort process.
    C
            DATA INPUTNAME/'R010SQ.DAT'/
            KEYBUF(1) = 1
            KEYBUF(2) = %LOC(DSC$K_DTYPE_T)
            KEYBUF(3) = 0
            KEYBUF(4) = 0
            KEYBUF(5) = 80
            SRTTYPE = %LOC(SOR$GK_RECORD)

    C
    C       Call the SORT -- each call is a function.
    C
    C
    C       Pass SORT the file names.
    C
            ISTATUS = SOR$PASS_FILES(INPUTNAME)
            IF (.NOT. ISTATUS) GOTO 10
    C
    C       Initialize the work areas and keys.
    C
            ISTATUS = SOR$BEGIN_SORT(KEYBUF,,,,,,SRTTYPE,%REF(3))
            IF (.NOT. ISTATUS) GOTO 10
    C
    C       Sort the records.
    C
            ISTATUS = SOR$SORT_MERGE( )
            IF (.NOT. ISTATUS) GOTO 10
    C
    C       Now retrieve the individual records and display them.
    C
    5       ISTATUS = SOR$RETURN_REC(RECBUF)
            IF (.NOT. ISTATUS) GOTO 6
            ISTATUS = LIB$PUT_OUTPUT(RECBUF)
            GOTO 5
    6       IF (ISTATUS .EQ. %LOC(SS$_ENDOFFILE)) GOTO 7
            GOTO 10
    C
    C       Clean up the work areas and files.
    C
    7       ISTATUS = SOR$END_SORT()
            IF (.NOT. ISTATUS) GOTO 10
            STOP 'SORT SUCCESSFUL'
    10      STOP 'SORT UNSUCCESSFUL'
            END

Example 18-3 is a Compaq Pascal program that demonstrates a merge operation using a file interface.

Example 18-3 Using SOR Routines to Merge Three Input Files in a Compaq Pascal Program

    Program

    (* This program merges three input files, (IN_FILE.DAT,
     IN_FILE2.DAT IN_FILE3.DAT), and creates one merged output file.  *)

    program mergerecs( output, in_file1, in_file2, in_file3, out_file );

    CONST
       SS$_NORMAL = 1;
       SS$_ENDOFFILE = %X870;
       SOR$GK_RECORD = 1;
       SOR$M_STABLE = 1;
       SOR$M_SEQ_CHECK = 4;
       SOR$M_SIGNAL = 8;
       DSC$K_DTYPE_T = 14;

    TYPE
       $UBYTE = [BYTE] 0..255;
       $UWORD = [WORD] 0..65535;

    const
        num_of_keys = 1;
        merge_order = 3;
        lrl         = 131;

        ascending   = 0;
        descending  = 1;

    type
        key_buffer_block=
            packed record
            key_type:       $uword;
            key_order:      $uword;
            key_offset:     $uword;
            key_length:     $uword;
            end;

       key_buffer_type=
            packed record
            key_count:      $uword;
            blocks:         packed array[1..num_of_keys] of key_buffer_block;
            end;

       record_buffer =      packed array[1..lrl] of char;

       record_buffer_descr =
            packed record
            length: $uword;
            dummy:  $uword;
            addr:   ^record_buffer;
            end;

    var
       in_file1,
       in_file2,
       in_file3,
       out_file:    text;
       key_buffer:  key_buffer_type;
       rec_buffer:  record_buffer;
       rec_length:  $uword;
       status:      integer;
       i:           integer;

    function sor$begin_merge(
            var buffer:     key_buffer_type;
            lrl:            $uword;
            mrg_options:    integer;
            merge_order:    $ubyte;
            %immed cmp_rtn: integer := 0;
            %immed eql_rtn: integer := 0;
            %immed [unbound] function
                read_record(
                    var rec:        record_buffer_descr;
                    var filenumber: integer;
                    var recordsize: $uword): integer
            ): integer; extern;

    function sor$return_rec(
            %stdescr rec:   record_buffer;
            var rec_size:   $uword
            ): integer; extern;

    function sor$end_sort: integer; extern;

    procedure sys$exit( %immed status : integer ); extern;

    function read_record(
            var rec:        record_buffer_descr;
            var filenumber: integer;
            var recordsize: $uword
            ): integer;

    procedure readone( var filename: text );
    begin
    recordsize := 0;
    if eof(filename)
    then
        read_record := ss$_endoffile
    else
        begin
        while not eoln(filename) and (recordsize < rec.length) do
            begin
            recordsize := recordsize + 1;
            read(filename,rec.addr^[recordsize]);
            end;
        readln(filename);
        end;
    end;

    begin
    read_record := ss$_normal;
    case filenumber of
        1: readone(in_file1);
        2: readone(in_file2);
        3: readone(in_file3);
        otherwise
            read_record := ss$_endoffile;
        end;
    end;

    procedure initfiles;
    begin
    open( in_file1, 'infile1.dat', old );
    open( in_file2, 'infile2.dat', old );
    open( in_file3, 'infile3.dat', old );
    open( out_file, 'temp.tmp' );
    reset( in_file1 );
    reset( in_file2 );
    reset( in_file3 );
    rewrite( out_file );
    end;

    procedure error( status : integer );
    begin
    writeln( 'merge unsuccessful.  status=%x', status:8 hex );
    sys$exit(status);
    end;
    begin

    with key_buffer do
        begin
        key_count := 1;
        with blocks[1] do
            begin
            key_type := dsc$k_dtype_t;
            key_order := ascending;
            key_offset := 0;
            key_length := 5;
            end;
        end;

    initfiles;

    status := sor$begin_merge( key_buffer, lrl,
            sor$m_seq_check + sor$m_signal,
            merge_order, 0, 0, read_record );

    repeat
        begin
        rec_length := 0;
        status := sor$return_rec( rec_buffer, rec_length );
        if odd(status)
        then
            begin
            for i := 1 to rec_length do write(out_file, rec_buffer[i]);
            writeln(out_file);
            end;
        end
    until not odd(status);

    if status <> ss$_endoffile then error(status);

    status := sor$end_sort;
    if not odd(status) then error(status);

    writeln( 'merge successful.' );

    end.

Example 18-4 is a Compaq Pascal program that demonstrates a sort operation using a record interface.

Example 18-4 Using SOR Routines to Sort Records from Two Input Files in a Compaq Pascal Program

    Pascal Program

    PROGRAM FILETORECORDSORT (OUTPUT,SORTOUT);

    (*      This program calls SOR routines to read and sort records from
            two input files, (PASINPUT1.DAT and PASINPUT2.DAT) and to return
            sorted records to this program to be written to the output file,
            (TEMP.TMP).  *)

    (*      Declarations for external status codes, and data structures, such as
            the types $UBYTE (an unsigned byte) and $UWORD (an unsigned word). *)

    CONST
       SS$_NORMAL = 1;
       SS$_ENDOFFILE = %X870;
       SOR$GK_RECORD = 1;
       SOR$M_STABLE = 1;
       SOR$M_SEQ_CHECK = 4;
       SOR$M_SIGNAL = 8;
       DSC$K_DTYPE_T = 14;

    TYPE
       $UBYTE = [BYTE] 0..255;
       $UWORD = [WORD] 0..65535;

    CONST
       Numberofkeys = 1 ;   (* Number of keys for this sort *)
       LRL = 131 ;          (* Longest Record Length for output records *)

    (* Key orders *)

       Ascending = 0 ;
       Descending = 1 ;

    TYPE
       Keybufferblock= packed record
                       Keytype : $UWORD ;
                       Keyorder : $UWORD ;
                       Keyoffset : $UWORD ;
                       Keylength : $UWORD
                       end ;

    (* The keybuffer. Note that the field buffer is a one-component array in
       this program. This type definition would allow a multikeyed sort. *)

       Keybuffer= packed record
                  Numkeys : $UWORD ;
                  Blocks : packed array[1..Numberofkeys] OF Keybufferblock
                  end ;

    (* The record buffer. This buffer will be used to hold the returned
            records from SORT. *)

       Recordbuffer = packed array[1..LRL] of char ;

    (* Name type for input and output files. A necessary fudge for %stdescr
       mechanism.  *)

       nametype= packed array[1..13] of char ;

    VAR
       Sortout : text ;             (* the output file *)
       Buffer : Keybuffer ;         (* the actual keybuffer *)
       Sortoptions : integer ;      (* flag for sorting options *)
       Sorttype : $UBYTE ;          (* sorting process *)
       Numworkfiles : $UBYTE ;      (* number of work files *)
       Status : integer ;           (* function return status code *)
       Rec : Recordbuffer ;         (* a record buffer *)
       Recordlength : $UWORD ;      (* the returned record length *)
       Inputname:  nametype ;       (* input file name *)
       i : integer ;                (* loop control variable *)

    (* function and procedure declarations *)

    (* Declarations of SORT functions *)
    (* Note that the following SORT routine declarations
            do not use all of the possible routine parameters. *)
    (* The parameters used MUST have all preceding parameters specified,
            however. *)

    FUNCTION SOR$PASS_FILES
       (%STDESCR Inname : nametype )
       : INTEGER ; EXTERN ;

    FUNCTION SOR$BEGIN_SORT(
        VAR Buffer : Keybuffer ;
        Lrlen : $UWORD ;
        VAR Sortoptions : INTEGER ;
        %IMMED Filesize : INTEGER ;
        %IMMED Usercompare : INTEGER ;
        %IMMED Userequal : INTEGER ;
        VAR Sorttype : $UBYTE ;
        VAR Numworkfiles : $UBYTE )
        : INTEGER ; EXTERN ;

    FUNCTION SOR$SORT_MERGE
       : INTEGER ; EXTERN ;

    FUNCTION SOR$RETURN_REC(
       %STDESCR  Rec : Recordbuffer ;
       VAR Recordsize : $UWORD )
       : INTEGER ; EXTERN ;

    FUNCTION SOR$END_SORT
       : INTEGER ; EXTERN ;

    (* End of the SORT function declarations *)

    (* The CHECKSTATUS routine checks the return status for errors. *)
    (* If there is an error, write an error message and exit via sys$exit *)
    PROCEDURE CHECKSTATUS( var status : integer ) ;

            procedure sys$exit( status : integer ) ; extern ;

    begin           (* begin checkstatus *)
       if odd(status) then
            begin
            writeln( ' SORT unsuccessful. Error status = ', status:8 hex ) ;
            SYS$EXIT( status ) ;
            end ;
    end ;           (* end checkstatus *)

    (* end function and routine declarations *)

    BEGIN   (* begin the main routine *)

    (* Initialize data for one 8-byte character key, starting at record
       offset 0, 3 work files, and the record sorting process *)

    Inputname := 'PASINPUT1.DAT' ;
    WITH Buffer DO
       BEGIN
       Numkeys := 1;
       WITH Blocks[1] DO
          BEGIN
          Keytype := DSC$K_DTYPE_T ;        (* Use OpenVMS descriptor data types to
                                                    define SORT data types. *)
          Keyorder := Ascending ;
          Keyoffset := 0 ;
          Keylength := 8 ;
          END;
       END;

    Sorttype := SOR$GK_RECORD ;             (* Use the global SORT constant to
                                                 define the sort process. *)
    Sortoptions := SOR$M_STABLE ;           (* Use the global SORT constant to
                                                 define the stable sort option. *)
    Numworkfiles := 3 ;

    (* call the sort routines as a series of functions *)

    (* pass the first filename to SORT *)
    Status := SOR$PASS_FILES( Inputname ) ;

    (* Check status for error. *)
    CHECKSTATUS( Status ) ;

    (* pass the second filename to SORT *)
    Inputname := 'PASINPUT2.DAT' ;

    Status := SOR$PASS_FILES( Inputname ) ;

    (* Check status for error. *)
    CHECKSTATUS( Status ) ;

    (* initialize work areas and keys *)
    Status := SOR$BEGIN_SORT( Buffer, 0, Sortoptions, 0, 0, 0,
                                    Sorttype, Numworkfiles ) ;

    (* Check status for error. *)
    CHECKSTATUS( Status ) ;

    (* sort the records *)
    Status := SOR$SORT_MERGE ;

    (* Check status for error. *)
    CHECKSTATUS( Status ) ;

    (* Ready output file for writing returned records from SORT. *)
    OPEN( SORTOUT, 'TEMP.TMP' ) ;
    REWRITE( SORTOUT ) ;

    (* Now get the sorted records from SORT. *)
    Recordlength := 0 ;
    REPEAT
       Status := SOR$RETURN_REC( Rec, Recordlength ) ;

       if odd( Status )
       then                 (* if successful, write record to output file. *)
            begin
            for i := 1 to Recordlength do
               write( sortout, Rec[i] ) ;   (* write each character *)
            writeln (sortout) ;                     (* end output line *)
            end;
    UNTIL not odd( Status ) ;

    (* If there was just no more data to be returned (eof) continue, otherwise
            exit with an error. *)
    if Status <> SS$_ENDOFFILE then
       CHECKSTATUS( Status ) ;

    (* The sort has been successful to this point. *)

    (* Close the output file *)
    CLOSE( sortout ) ;

    (* clean up work areas and files *)
    Status := SOR$END_SORT ;

    (* Check status for error. *)
    CHECKSTATUS( Status );

    WRITELN ('SORT SUCCESSFUL') ;

    END.

Previous | Next | Contents | Index

| privacy and legal statement |
4493PRO_055.HTML