Sorting using V119 (TB#38) (Functions/Subroutines/Programs)
Created at 01 OCT 1996 04:35PM
Sorting using V119
This technical bulletin documents the functionality of the system routine V119, the generic sort routine of Advanced Revelation. In addition, Figure 1 illustrates a sample program that demonstrates various calls to the V119 program.
V119 Basics
V119 is an Assembly Language commuter module that supports eight different types of operations depending on the first parameter passed. V119 can be used to:
_ sort a sequence of logical records in a single dynamic array up to about 64K.
_ perform multi-level sorting against two or more fields in the logical records.
_ perform multi-level sorting with different justification and sort direction (ascending, descending) for each field.
_ (in multiple separate operations) initialize, load, merge, sort, read, and delete an operating system file used to sort data strings longer than about 64K.
In essence, V119 is a string sort utility. The substrings to be sorted are delimited with record marks (@RM ASCII 255), and are thus logical records. The records usually contain only the data to be sorted. Each separate sort element (logical field) is separated from the previous one with a field mark (@FM ASCII 254).
Data that is not part of the sort string (called satellite data) can be included at the end of the fields to be sorted. The most common example of satellite data is a record key.
Sorting Large Strings
V119 can sort strings up to a total string length of 65,533 bytes. If the data to be sorted exceeds this length, V119 can be used to create and merge individual blocks of sort data. The blocks are temporarily stored in an operating system file.
The process of using blocks of data requires a series of discrete operations: initializing a sort file, loading it with blocks of data to be sorted, merging the blocks, sorting the blocks, extracting the sorted data, and deleting the temporary file. Each of these operations requires a separate call to V119.
You can choose any operating system file you wish to hold blocks of data. However, the system function GET.SORT.FILE( ) can be used to return a unique filename for this purpose. GET.SORT.FILE( ) uses the environment setting for the sort path, and creates a temporary sort filename that includes the station number.
Calling V119
V119 accepts a total of six parameters. The first parameter is a one-letter code that determines what V119 is to do. It is the only parameter that is always required. The general syntax for V119 is:
V119(FUNCTION_CODE, SORT_FILE, BYS, JUSTS, WORK, FLAG)
Rather than explain each parameter individually, this technical bulletin explains each of the eight operations in turn and what the parameters are for each.
Sort
To sort an array of records the FUNCTION_CODE for V119 is S. Other arguments are:
SORT_FILE null.
BYS A or D for each sort field. A represents an ascending sort for the field and D descending. For example, if BYS equals ADA, V119 does an ascending sort on the first field in WORK, descending on the second field, and ascending on the third field even though there may be satellite data.
JUSTS works the same way as BYS but refers to the justification of each sort field and consequently whether an alpha or numeric sort is performed. L and R are the valid characters representing left and right justification, respectively.
WORK a dynamic array of data to be sorted. Each piece of data to sort is separated by a record mark (ASCII 255). A final record mark is required, but not a beginning one.
If a multiple level sort is to be performed, fields are defined within each record separated by field marks (ASCII 254). The first field is sorted first (the primary sort), the second field is sorted next, and so forth.
There may be fields in the record that are not sorted (satellite data), because only as many fields will be sorted as there are characters in the BYS or JUSTS parameters. All sort fields must be contiguous at the beginning of each record. All satellite data must be contiguous at the end of each record. There is no way to skip the sorting of a field.
WORK returns in the same format as it was passed, but the records are in
sorted order.
FLAG null.
Extract
A FUNCTION_CODE of E indicates an extract operation to return satellite data from the sort array. This is useful when the sort operation has been performed with record keys as satellite data. A list of record keys is then returned.
SORT_FILE null.
BYS null.
JUSTS null.
WORK a dynamic array in the same format as in the sort operation. WORK returns the last fields of each record separated by field marks.
FLAG null.
Initialize
A FUNCTION_CODE of I initializes an operating system file that is used to hold sort data temporarily while sorting.
SORT_FILE set to the drive, path, and filename of the operating system file.
BYS null.
JUSTS null.
WORK null.
FLAG zero if there was a problem in file i/o and non-zero if the operation was successful.
Write
A FUNCTION_CODE of W indicates a write operation. This is used to write a block of sort data to the temporary sort file.
SORT_FILE the drive, path, and filename of the operating system file.
BYS null.
JUSTS null.
WORK a dynamic array to write. This is most likely the return value of WORK from a sort operation. Thus, the external sort file becomes a series of sorted blocks of data.
FLAG returns zero if there was a problem in file i/o and non-zero if the operation was successful.
Merge
A FUNCTION_CODE of M indicates a merge operation. This operation is used to fully sort the external sort file after all of the sorted blocks of data have been written to it.
SORT_FILE the drive, path, and filename of the external sort file.
BYS the same value as when the data was sorted during the Sort operation.
JUSTS the same value as when the data was sorted during the Sort operation.
WORK null.
FLAG zero if there was a problem in file i/o and non-zero if the operation was successful.
Note: This operation immediately doubles the size of the operating system file. If disk space is tight, this is the most vulnerable operation.
List
A FUNCTION_CODE of L indicates a list operation. This operation is similar to the Extract operation. This operation gets the keys back from the merged external sort file in blocks of 32K.
SORT_FILE the drive, path, and filename of the external sort file.
BYS null.
JUSTS null.
WORK passed null. Returns a 32K block of field mark delimited of keys.
FLAG zero if there was a problem in file i/o or non-zero upon success.
Values
A FUNCTION_CODE of V denotes a value operation. This operation is like the List operation in that it returns data in 32K blocks from an external sort file after it has been merged. However, the data returned is like that of a sort operation rather than an extract operation.
SORT_FILE the drive, path, and filename of the external sort file.
BYS null.
JUSTS null.
WORK null when passed. Returns a 32K block of sorted records by whatever criteria were specified when the external sort file was merged.
FLAG Returns zero if there was any problem in file i/o or non-zero upon success.
Delete
A D FUNCTION_CODE will cause the external sort file to be deleted. All other parameters are the same as for the initialize operation.
Figure 1
* SSORT
*
* TCL Syntax: SSORT filename fieldname
*
* purpose: to sort a file by one real field and write as a saved-list in
* the LISTS file under same name as the file.
*
* version: Advanced Revelation 1.x
EQU MAXLEN$ TO 65533
EQU NOT_ATTACHED$ TO 201
EQU TRUE$ TO 1
EQU FALSE$ TO 0
DECLARE FUNCTION GET.SORT.FILE
DECLARE SUBROUTINE MSG, V119
!
* M A I N
!
*
* initialization
*
FILENAME = FIELD(@SENTENCE, ' ', 2)
FIELDNAME = FIELD(@SENTENCE, ' ', 3)
IF FIELDNAME AND FILENAME ELSE
MSG('Syntax is: |SSORT filename fieldname', ,
, )
STOP
END
SORT_FILE = GET.SORT.FILE()
EXTERNAL_SORT_FLAG = FALSE$
DONE = FALSE$
WORK =
FLAG =
OPEN 'LISTS' TO LISTS_FILE ELSE
MSG(NOT_ATTACHED$,
, , 'LISTS')
FLAG = TRUE$
END
OPEN FILENAME TO FILE ELSE
MSG(NOT_ATTACHED$,
, , FILENAME)
FLAG = TRUE$
END
* get field number and justification of the field
OPEN 'DICT.':FILENAME TO @DICT THEN
READ @RECORD FROM @DICT, FIELDNAME THEN
JUSTS = @RECORD<9>
FNO = @RECORD<2>
IF FNO AND JUSTS ELSE
TEXT = Field %1% is not valid for SSORT.
TEXT←1> = It needs to be type 'F' and have a justification.
MSG(TEXT,
, , FIELDNAME)
FLAG = TRUE$
END
END ELSE
TEXT = 'Field %1% does not exist in dictionary.'
MSG(TEXT,
, , FIELDNAME)
FLAG = TRUE$
END
END ELSE
MSG(NOT_ATTACHED$, , , 'DICT.':FILENAME)
FLAG = TRUE$
END
IF FLAG ELSE
SELECT FILE
*
* main loop
*
LOOP
READNEXT @ID ELSE DONE = TRUE$
UNTIL DONE
READV @RECORD FROM FILE, @ID, FNO THEN
CNT = COUNT(@RECORD, @VM) 1
FOR J = 1 TO CNT
TEMP = @RECORD<1, J> : @FM : @ID :@VM: J: @RM
IF LEN(TEMP) LEN(WORK) LT MAXLEN$ THEN
WORK := TEMP
END ELSE
IF EXTERNAL_SORT_FLAG ELSE GOSUB INITIALIZE_SORTFILE
GOSUB SORT
WORK = TEMP
END
NEXT
END
REPEAT
*
* wrap up
*
GOSUB SORT
IF EXTERNAL_SORT_FLAG THEN
GOSUB MERGE
GOSUB DELETE_SORTFILE
END ELSE
V119('E',
, ,
, WORK, )
IF WORK[-1, 1] EQ @FM THEN WORK[-1, 1] =
WRITE WORK ON LISTS_FILE, FILENAME
END
END
STOP
!
* I N T E R N A L R O U T I N E S
!
INITIALIZE_SORTFILE:
V119('I', SORT_FILE, ,
, , FLAG)
IF FLAG ELSE
TEXT = Error initializing sort file.
MSG(TEXT, , , )
STOP
END
EXTERNAL_SORT_FLAG = TRUE$
RETURN
!
SORT:
V119('S',
, 'A', JUSTS, WORK, )
IF EXTERNAL_SORT_FLAG THEN
V119('W', SORT_FILE,
, , WORK, FLAG)
IF FLAG ELSE
TEXT = Error writing to sort file.
MSG(TEXT, , , )
GOSUB DELETE_SORTFILE
STOP
END
END
RETURN
!
MERGE:
V119('M', SORT_FILE, 'A', JUSTS,
, FLAG)
IF FLAG THEN
CNTR = 0
LOOP
V119('L', SORT_FILE, ,
, WORK, FLAG)
IF FLAG ELSE
TEXT = Error extracting from sort file.
MSG(TEXT, , , )
END
UNTIL WORK EQ OR NOT(FLAG)
IF WORK[-1, 1] EQ @FM THEN WORK[-1, 1] =
IF CNTR THEN
WRITE WORK ON LISTS_FILE, FILENAME:'*':CNTR
CNTR = 1
END ELSE
WRITE WORK ON LISTS_FILE, FILENAME
CNTR = 2
END
REPEAT
END ELSE
TEXT = Error during sort file merge.
MSG(TEXT, , , )
END
RETURN
!
DELETE_SORTFILE:
V119('D', SORT_FILE, ,
, , FLAG)
IF FLAG ELSE
TEXT = Error deleting sort file %1%
MSG(TEXT,
, '', SORT_FILE)
END
RETURN