|
OpenVMS Utility Routines Manual
Example 19-5 is a Compaq C program that demonstrates a sort operation
using the STABLE option and two test keys.
Example 19-5 Using SOR Routines to Sort
Records Using the STABLE Option and Two Text Keys in a Compaq C
Program |
/*
C Program Example
This program demonstrates the use of the STABLE option
with 2 ascending text keys to sort a file of names.
The names are sorted by the first 6 characters of the last
name and the first 6 characters of the first name.
The contents of the input file and resulting output file
are listed below. The associated C program code listing follows.
...................................................................
Input file: example.in
JONES DAVID
WARNER LIZZY
SMITTS JAMES
SMITH RANDY
BROWN TONY
GRANT JOSEPH
BROWN JAMES
JONES DAVID
BAKER PAMELA
SMART SHERYL
RUSSO JOSEPH
JONES DONALD
BROWN GORDON
...................................................................
Output file: example.out
BAKER PAMELA
BROWN GORDON
BROWN JAMES
BROWN TONY
GRANT JOSEPH
JONES DAVID
JONES DAVID
JONES DONALD
RUSSO JOSEPH
SMART SHERYL
SMITH RANDY
SMITTS JAMES
WARNER LIZZY
...................................................................
*/
/*
**=================================================================
**
** EXAMPLE.C code:
**
** Abstract: Example of using sort with the STABLE option and
** 2 text keys (both ascending).
**
**
** Input file: example.in
** Output file: example.out
**
**=================================================================
*/
/* ----------------------------------------------------------------------------
** Include files:
*/
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <descrip.h>
# include <ssdef.h>
# include <sor$routines.h>
/* ----------------------------------------------------------------------------
** Local macro definitions:
*/
# define MAX_REC_LEN 150
# define MAX_NUM_KEYS 10
/* ----------------------------------------------------------------------------
** Local structure definitions.
*/
/* Define the description for each key. */
typedef struct {
unsigned short type; /* Data type of key */
unsigned short order; /* Order of key */
unsigned short offset; /* Offset of key */
unsigned short len; /* Length of key */
} key_info;
struct {
unsigned short num; /* number of keys */
key_info key[MAX_NUM_KEYS];
} key_buffer;
/* ----------------------------------------------------------------------------
** External literals.
*/
globalvalue
int
SOR$M_STABLE;
/* ----------------------------------------------------------------------------
** Main entry point.
*/
main (int argc, char *argv[])
{
int i;
unsigned int options; /* Sort options */
unsigned int num_records_in;
unsigned int num_records_out;
unsigned int lrl; /* longest record length */
unsigned short size; /* record size from return_rec */
unsigned int status;
unsigned long int return_status;
FILE *infile; /* input file */
FILE *outfile; /* output file */
char record [MAX_REC_LEN];
$DESCRIPTOR (record_desc, record);
lrl = sizeof(record);
key_buffer.num = 2;
key_buffer.key[0].type = DSC$K_DTYPE_T;
key_buffer.key[0].order = 0; /* ascending */
key_buffer.key[0].offset = 0;
key_buffer.key[0].len = 6;
key_buffer.key[1].type = DSC$K_DTYPE_T;
key_buffer.key[1].order = 0; /* ascending */
key_buffer.key[1].offset = 7;
key_buffer.key[1].len = 6;
/* Open input and output files. */
if (argc != 3)
{
printf("Usage: example inputfile outputfile\n");
exit(-1);
}
infile = fopen(argv[1], "r");
if (infile == (FILE *) NULL)
{
printf("Can't open input file %s\n",argv[1]);
exit(-1);
}
outfile = fopen(argv[2], "w");
if (outfile == (FILE *) NULL)
{
printf("Can't create output file %s\n",argv[2]);
exit(-1);
}
/* Specify options. Initialize the sort and check for errors. */
options = SOR$M_STABLE;
return_status = SOR$BEGIN_SORT(&key_buffer, &lrl, &options, 0,0,0,0,0,0);
if (return_status != SS$_NORMAL)
{
printf ("Status from SOR$BEGIN_SORT: 0x%x\n", return_status);
exit(return_status);
}
/* Within a loop, get all the records from the input file. */
/* Exit if an error occurs. */
num_records_in = 0;
while (fgets( record, lrl, infile) != NULL)
{
record_desc.dsc$w_length = strlen(record)-1;
num_records_in++;
return_status = SOR$RELEASE_REC(&record_desc,0);
if (return_status != SS$_NORMAL)
{
printf ("Status from SOR$RELEASE_REC: 0x%x\n", return_status);
exit(return_status);
}
}
/* Sort all of the input records. */
/* Exit if an error occurs. */
return_status = SOR$SORT_MERGE(0);
if (return_status != SS$_NORMAL)
{
printf ("Status from SOR$SORT_MERGE: 0x%x\n", return_status);
exit(return_status);
}
/* Within a loop, write the sorted records to the output file. */
/* Exit if an error occurs, other than end-of-file. */
record_desc.dsc$w_length = lrl;
num_records_out = 0;
do
{
return_status = SOR$RETURN_REC(&record_desc,&size,0);
if (return_status == SS$_NORMAL)
{
num_records_out++;
status = fprintf (outfile,"%.*s\n", size, record);
if (status < 0 )
{
printf ("Error writing to output file, status = %d\n", status);
exit(status);
}
}
else
if (return_status != SS$_ENDOFFILE)
{
printf ("Status from SOR$RETURN_REC: 0x%x\n", return_status);
exit(return_status);
};
} while (return_status != SS$_ENDOFFILE);
/* Sanity check - assure number of input and output records match. */
if (num_records_out != num_records_in)
{
printf("Number of records out is not correct. # in = %d, # out = %d\n",
num_records_out, num_records_in);
exit(status);
}
/* Successful completion. Close input and output files. End program. */
return_status = SOR$END_SORT(0);
if (return_status != SS$_NORMAL)
{
printf ("Status from SOR$END_SORT: 0x%x\n", return_status);
exit(return_status);
}
fclose (infile);
fclose (outfile);
}
|
19.4 SOR Routines
This section describes the individual SOR routines.
SOR$BEGIN_MERGE
The SOR$BEGIN_MERGE routine initializes the merge operation by opening
the input and output files and by providing the number of input files,
the key specifications, and the merge options.
Format
SOR$BEGIN_MERGE [key-buffer] [,lrl] [,options] [,merge_order]
[,user_compare] [,user_equal] [,user_input] [,context]
RETURNS
OpenVMS usage: |
cond_value |
type: |
longword (unsigned) |
access: |
write only |
mechanism: |
by value |
Longword condition value. Most Sort/Merge utility routines return a
condition value in R0. Condition values that this routine can return
are listed under Condition Values Returned.
Arguments
key_buffer
OpenVMS usage: |
vector_word_unsigned |
type: |
word (unsigned) |
access: |
read only |
mechanism: |
by reference |
Array of words describing the keys on which you plan to merge. The
key_buffer argument is the address of an array
containing the key descriptions.
The first word of this array contains the number of keys described (up
to 255). Following the first word, each key is described (in order of
priority) in blocks of four words. The four words specify the key's
data type, order, offset, and length, respectively.
The first word of the block specifies the key's data type. The
following data types are accepted:
DSC$K_DTYPE_Z
|
Unspecified (uninfluenced by collating sequence)
|
DSC$K_DTYPE_B
|
Byte integer (signed)
|
DSC$K_DTYPE_BU
|
Byte (unsigned)
|
DSC$K_DTYPE_W
|
Word integer (signed)
|
DSC$K_DTYPE_WU
|
Word (unsigned)
|
DSC$K_DTYPE_L
|
Longword integer (signed)
|
DSC$K_DTYPE_LU
|
Longword (unsigned)
|
DSC$K_DTYPE_Q
|
Quadword integer (signed)
|
DSC$K_DTYPE_QU
|
Quadword (unsigned)
|
DSC$K_DTYPE_O+
|
Octaword integer (signed)
|
DSC$K_DTYPE_OU+
|
Octaword (unsigned)
|
DSC$K_DTYPE_F
|
Single-precision floating
|
DSC$K_DTYPE_D
|
Double-precision floating
|
DSC$K_DTYPE_G
|
G-format floating
|
DSC$K_DTYPE_H+
|
H-format floating
|
DSC$K_DTYPE_FS++
|
IEEE single-precision S floating
|
DSC$K_DTYPE_FT++
|
IEEE double-precision T floating
|
DSC$K_DTYPE_T
|
Text (may be influenced by collating sequence)
|
DSC$K_DTYPE_NU
|
Numeric string, unsigned
|
DSC$K_DTYPE_NL
|
Numeric string, left separate sign
|
DSC$K_DTYPE_NLO
|
Numeric string, left overpunched sign
|
DSC$K_DTYPE_NR
|
Numeric string, right separate sign
|
DSC$K_DTYPE_NRO
|
Numeric string, right overpunched sign
|
DSC$K_DTYPE_NZ+
|
Numeric string, zoned sign
|
DSC$K_DTYPE_P
|
Packed decimal string
|
+Data type is not currently supported by the high-performance
Sort/Merge utility.
++Data type is Alpha specific.
The OpenVMS Programming Interfaces: Calling a System Routine manual describes each of these data types.
The second word of the block specifies the key order: 0 for
ascending order, 1 for descending order. The third word of the
block specifies the relative offset of the key in the record. (Note
that the first byte in the record is at position 0.) The
fourth word of the block specifies the key length in bytes (in digits
for packed decimal---DSC$K_DTYPE_P).
If you do not specify the key_buffer argument, you
must pass either a key comparison routine or use a specification file
to define the key.
lrl
OpenVMS usage: |
word_unsigned |
type: |
word (unsigned) |
access: |
read only |
mechanism: |
by reference |
Length of the longest record that will be released for merging. The
lrl (longest record length) argument is the address of
a word containing the length. If the input file is on a disk, this
argument is not required. It is required when you use the record
interface. For Vertical Format Control (VFC) records, this length must
include the length of the fixed-length portion of the record.
options
OpenVMS usage: |
mask_longword |
type: |
longword (unsigned) |
access: |
read only |
mechanism: |
by reference |
Flags that identify merge options. The options
argument is the address of a longword bit mask whose settings determine
the merge options selected.
The following table lists and describes the bit mask values available:
Flag |
Description |
SOR$M_STABLE
|
Keeps records with equal keys in the same order as they appeared on
input.
|
SOR$M_EBCDIC
|
Orders ASCII character keys according to EBCDIC collating sequence. No
translation takes place.
|
SOR$M_MULTI
|
Orders character keys according to the multinational collating
sequence, which collates the international character set.
|
SOR$M_NOSIGNAL
|
Returns a status code instead of signaling errors.
|
SOR$M_NODUPS
|
Omits records with duplicate keys. You cannot use this option if you
specify your own equal-key routine.
|
SOR$M_SEQ_CHECK
|
Requests an "out of order" error return if an input file is
not already in sequence. By default, this check is not done. You must
request sequence checking if you specify an
equal-key routine.
|
All other bits in the longword are reserved and must be zero.
merge_order
OpenVMS usage: |
byte_unsigned |
type: |
byte (unsigned) |
access: |
read only |
mechanism: |
by reference |
Number of input streams to be merged. The merge_order
argument is the address of a byte containing the number of files (1
through 10) to be merged. (The high-performance Sort/Merge utility
allows you to specify 1 through 12 files.) When you use the record
interface on input, this argument is required.
user_compare
OpenVMS usage: |
procedure |
type: |
procedure value |
access: |
function call |
mechanism: |
by reference |
Routine that compares records to determine their merge order. (This
routine is not currently supported by the high-performance Sort/Merge
utility.) The user_compare argument is the address of
the procedure value for this user-written routine. If you do not
specify the key_buffer argument or if you define key
information in a specification file, this argument is required.
MERGE calls the comparison routine with five reference
arguments---ADRS1, ADRS2, LENG1, LENG2, CNTX---corresponding to the
addresses of the two records to be compared, the lengths of these two
records, and the context longword.
The comparison routine must return a 32-bit integer value:
- --1 if the first record collates before the second
- 0 if the records collate as equal
- 1 if the first record collates after the second
user_equal
OpenVMS usage: |
procedure |
type: |
procedure value |
access: |
function call |
mechanism: |
by reference |
Routine that resolves the merge order when records have duplicate keys.
(This routine is not currently supported by the high-performance
Sort/Merge utility.) The user_equal argument is the
address of the procedure value for this user-written routine. If you
specify SOR$M_STABLE or SOR$M_NODUPS in the options
argument, do not use this argument.
MERGE calls the duplicate key routine with five reference
arguments---ADRS1, ADRS2, LENG1, LENG2, CNTX---corresponding to the
addresses of the two records that compare equally, the lengths of the
two records that compare equally, and the context longword.
The routine must return one of the following 32-bit condition codes:
Code |
Description |
SOR$_DELETE1
|
Delete the first record from the merge.
|
SOR$_DELETE2
|
Delete the second record from the merge.
|
SOR$_DELBOTH
|
Delete both records from the merge.
|
SS$_NORMAL
|
Keep both records in the merge.
|
Any other failure value causes the error to be signaled or returned.
Any other success value causes an undefined result.
user_input
OpenVMS usage: |
procedure |
type: |
procedure value |
access: |
function call |
mechanism: |
by reference |
Routine that releases records to the merge operation. The
user_input argument is the address of the procedure
value for this user-written routine. SOR$BEGIN_MERGE and SOR$RETURN_REC
call this routine until all records have been passed.
This input routine must read (or construct) a record, place it in a
record buffer, store its length in an output argument, and then return
control to MERGE.
The input routine must accept the following four arguments:
- A descriptor of the buffer where the routine must place the record
- A longword, passed by reference, containing the stream number from
which to input a record (the first file is 1, the second 2, and so on)
- A word, passed by reference, where the routine must return the
actual length of the record
- The context longword, passed by reference
The input routine must also return one of the following status values:
- SS$_NORMAL or any other success status causes the merge operation
to continue.
- SS$_ENDOFFILE indicates that no more records are in the file. The
contents of the buffer are ignored.
- Any other error status terminates the merge operation and passes
the status value back to the caller of SOR$BEGIN_MERGE or
SOR$RETURN_REC.
context
OpenVMS usage: |
context |
type: |
longword (unsigned) |
access: |
modify |
mechanism: |
by reference |
Value that distinguishes between multiple, concurrent SORT/MERGE
operations. The context argument is the address of a
longword containing the context value. When your program makes its
first call to a SORT/MERGE routine for a particular sort or merge
operation, the context longword must equal zero.
SORT/MERGE then stores a value in the longword to identify the
operation just initiated. When you make subsequent routine calls for
the same operation, you must pass the context value that was supplied
by SORT/MERGE.
Description
The SOR$BEGIN_MERGE routine initializes the merge process by passing
arguments that provide the number of input streams, the key
specifications, and any merge options.
You must define the key by passing either the key buffer address
argument or your own comparison routine address. (You can also define
the key in a specification file and call the SOR$SPEC_FILE routine.)
The SOR$BEGIN_MERGE routine initializes the merge process in the file,
record, and mixed interfaces. For record interface on input, you must
also pass the merge order, the input routine address, and the longest
record length. For files not on disk, you must pass the longest record
length.
Some of the following condition values are used with different
severities, depending on whether SORT/MERGE can recover. Thus, you
should use LIB$MATCH_COND if you want to check for a specific status.
Condition Values Returned
SS$_NORMAL
|
Success.
|
SOR$_BADDTYPE
|
Invalid or unsupported CDD data type.
|
SOR$_BADLENOFF
|
Length and offset must be multiples of 8 bits.
|
SOR$_BADLOGIC
|
Internal logic error detected.
|
SOR$_BADOCCURS
|
Invalid OCCURS clause.
|
SOR$_BADOVRLAY
|
Invalid overlay structure.
|
SOR$_BADPROTCL
|
Node is an invalid CDD object.
|
SOR$_BAD_KEY
|
Invalid key specification.
|
SOR$_BAD_LRL
|
Record length
n greater than specified longest record length.
|
SOR$_BAD_MERGE
|
Number of input files must be between 0 and 10. (For the
high-performance Sort/Merge utility, the maximum number is 12.)
|
SOR$_BAD_ORDER
|
Merge input is out of order.
|
SOR$_BAD_SRL
|
Record length
n is too short to contain keys.
|
SOR$_BAD_TYPE
|
Invalid sort process specified.
|
SOR$_CDDERROR
|
CDD error at node
name.
|
SOR$_CLOSEIN
|
Error closing
file as input.
|
SOR$_CLOSEOUT
|
Error closing
file.
|
SOR$_COL_CHAR
|
Invalid character definition.
|
SOR$_COL_CMPLX
|
Collating sequence is too complex.
|
SOR$_COL_PAD
|
Invalid pad character.
|
SOR$_COL_THREE
|
Cannot define 3-byte collating values.
|
SOR$_ENDDIAGS
|
Completed with diagnostics.
|
SOR$_ILLBASE
|
Nondecimal base is invalid.
|
SOR$_ILLLITERL
|
Record containing symbolic literals is unsupported.
|
SOR$_ILLSCALE
|
Nonzero scale invalid for floating-point data item.
|
SOR$_INCDIGITS
|
Number of digits is not consistent with the type or length of item.
|
SOR$_INCNODATA
|
Include specification references no data, at line
n.
|
SOR$_INCNOKEY
|
Include specification references no keys, at line
n.
|
SOR$_IND_OVR
|
Indexed output file must already exist.
|
SOR$_KEYAMBINC
|
Key specification is ambiguous or inconsistent.
|
SOR$_KEYED
|
Mismatch between SORT/MERGE keys and primary file key.
|
SOR$_KEY_LEN
|
Invalid key length, key number
n, length
n.
|
SOR$_LRL_MISS
|
Longest record length must be specified.
|
SOR$_MISLENOFF
|
Length and offset required.
|
SOR$_MISS_PARAM
|
A required subroutine argument is missing.
|
SOR$_MULTIDIM
|
Invalid multidimensional OCCURS.
|
SOR$_NODUPEXC
|
Equal-key routine and no-duplicates option cannot both be specified.
|
SOR$_NOTRECORD
|
Node
name is a name, not a record definition.
|
SOR$_NUM_KEY
|
Too many keys specified.
|
SOR$_NYI
|
Not yet implemented.
|
SOR$_OPENIN
|
Error opening
file as input.
|
SOR$_OPENOUT
|
Error opening
file as output.
|
SOR$_READERR
|
Error reading
file.
|
SOR$_RTNERROR
|
Unexpected error status from user-written routine.
|
SOR$_SIGNCOMPQ
|
Absolute Date and Time data type represented in 1-second units.
|
SOR$_SORT_ON
|
Sort or merge routines called in incorrect order.
|
SOR$_SPCIVC
|
Invalid collating sequence specification at line
n.
|
SOR$_SPCIVD
|
Invalid data type at line
n.
|
SOR$_SPCIVF
|
Invalid field specification at line
n.
|
SOR$_SPCIVI
|
Invalid include or omit specification at line
n.
|
SOR$_SPCIVK
|
Invalid key or data specification at line
n.
|
SOR$_SPCIVP
|
Invalid sort process at line
n.
|
SOR$_SPCIVS
|
Invalid specification at line
n.
|
SOR$_SPCIVX
|
Invalid condition specification at line
n.
|
SOR$_SPCMIS
|
Invalid merge specification at line
n.
|
SOR$_SPCOVR
|
Overridden specification at line
n.
|
SOR$_SPCSIS
|
Invalid sort specification at line
n.
|
SOR$_SRTIWA
|
Insufficient space. The specification file is too complex.
|
SOR$_STABLEEX
|
Equal-key routine and stable option cannot both be specified.
|
SOR$_SYSERROR
|
System service error.
|
SOR$_UNDOPTION
|
Undefined option flag was set.
|
SOR$_UNSUPLEVL
|
Unsupported core level for record
name.
|
SOR$_WRITEERR
|
Error writing
file.
|
|