|
OpenVMS Utility Routines Manual
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.
|
|