Sort:
PROCEDURE [data: AdobeCommon.Handle] = {
outputFileName: Rope.ROPE ¬ NIL;
sortKeySpecRef: REF SortKeySpec ¬ NEW[SortKeySpec ¬ NIL];
sortKeySpec: SortKeySpec ← NIL;
numberOfKeySpecsEntered: CARDINAL ¬ 0;
maxCharsAllStrings: CARDINAL ¬ 100; --will be reset later
headerLength, currentFileLength, maxFileLength: CARDINAL ¬ 0;
maxWordsThisString, maxWordsAllStrings:
CARDINAL ¬
SIZE[
StringBody];
sortStringBuffer: Rope.ROPE ¬ NIL; --String.MakeString[Heap.systemZone, 100];
sortKeyStringBuffer: Rope.ROPE ¬ NIL; --String.MakeString[Heap.systemZone, 100];
tempstring: Rope.ROPE ¬ NIL; --String.MakeString[data.heap, 10];
reportData: ReportData ¬ NIL;
instanceData: AdobeCommonInternal.InstanceDataHandle ¬
NARROW[data.instanceData];
WITH instanceData
SELECT
FROM
sortData: REF AdobeCommonInternal.InstanceData.sort => {
ENABLE {
UNWIND => {
IF sortData.inputSH #
NIL
THEN
sortData.inputSH ¬ CleanUpStream[sortData.inputSH];
IF sortData.outputSH #
NIL
THEN
sortData.outputSH ¬ CleanUpStream[sortData.outputSH];
IF sortData.sortKeysSH #
NIL
THEN
sortData.sortKeysSH ¬ CleanUpStream[
sortData.sortKeysSH];
Heap.systemZone.FREE[@sortStringBuffer];
Heap.systemZone.FREE[@sortKeyStringBuffer];
data.heap.FREE[@tempstring];
data.heap.FREE[@outputFileName];
IF sortKeySpecRef #
NIL
THEN
FreeSortKeySpec[data, sortKeySpecRef];
};
};
GetSortData:
PROCEDURE
RETURNS [repData: ReportData ¬
NIL] = {
rover: ReportData ¬ NIL;
nextLine: Rope.ROPE ¬ NIL;
nextLine ¬ SortKeysGetString[NIL];
WHILE nextLine #
NIL
DO
IF repData =
NIL
THEN {
repData ¬ NEW[ReportDataRec];
rover ¬ repData;
}
ELSE {
rover.next ¬ NEW[ReportDataRec];
rover ¬ rover.next;
};
rover.data ¬ nextLine;
nextLine ¬ SortKeysGetString[NIL];
ENDLOOP;
};
GetLink:
PROCEDURE [in:
REF
ANY]
RETURNS [
REF
ANY] = {
data: ReportData ¬ NARROW[in];
IF data =
NIL
THEN
RETURN[reportData]
};
SetLink:
PROCEDURE [from, to:
REF
ANY] = {
d1: ReportData ¬ NARROW[from];
d2: ReportData ¬ NARROW[to];
IF d1 #
NIL THEN
d1.next ¬ d2
};
Compare:
PROCEDURE [ref1, ref2:
REF
ANY]
RETURNS [TopoSort.PartialComparison] = {
h1: ReportData ¬ NARROW[ref1];
h2: ReportData ¬ NARROW[ref2];
p1: Rope.ROPE ¬ h1.data;
p2: Rope.ROPE ¬ h2.data;
index, count: CARDINAL ¬ 0;
keySpecPtr: SortKeySpec ¬ sortKeySpecRef;
DO
IF p1.Fetch[index] = Ascii.
NUL
AND p2.Fetch[index] = Ascii.
NUL
THEN {
index ¬ index + 1;
count ¬ count + 1;
keySpecPtr ¬ keySpecPtr.next;
IF count = numberOfKeySpecsEntered THEN RETURN[equal]} --0 means equal
ELSE {
IF p1.Fetch[index] = Ascii.
NUL
THEN {
IF keySpecPtr.ascending THEN RETURN[less]
ELSE RETURN[greater]}
ELSE
IF p2.Fetch[index] = Ascii.
NUL
THEN {
IF keySpecPtr.ascending THEN RETURN[greater]
ELSE RETURN[less]};
p1.Fetch[index] ← UpperCase[p1.Fetch[index]];
p2.Fetch[index] ← UpperCase[p2.Fetch[index]];
SELECT
TRUE
FROM
UpperCase[p1.Fetch[index]] < UpperCase[p2.Fetch[index]] =>
IF keySpecPtr.ascending THEN RETURN[less]
ELSE RETURN[greater];
UpperCase[p1.Fetch[index]] > UpperCase[p2.Fetch[index]] =>
IF keySpecPtr.ascending THEN RETURN[greater]
ELSE RETURN[less];
ENDCASE;
index ¬ index + 1};
ENDLOOP; --of DO
}; --of CompareStrings
SortKeysGetString:
PROCEDURE [sortKeyString: Rope.
ROPE]
RETURNS [data: Rope.
ROPE] = {
char: CHARACTER;
result: CARDINAL ¬ 0;
keySpec: SortKeySpec ¬ sortKeySpecRef;
out: REF Rope.ROPE ¬ NEW[Rope.ROPE ¬ NIL];
--put a single line of the sortkeys file into a buffer called sortStringBuffer
sortStringBuffer ¬ NIL;
sortKeyString ¬ NIL;
IF ~sortData.sortKeysSH.EndOf[]
THEN
char ¬ IO.GetChar[sortData.sortKeysSH];
WHILE ~sortData.sortKeysSH.EndOf[]
AND char # Ascii.
CR
AND char # Ascii.
LF
DO
sortStringBuffer ¬ ARAccess.AppendChar[sortStringBuffer, char];
char ¬ IO.GetChar[sortData.sortKeysSH];
ENDLOOP;
this creates a new string with the fields in sorted order
IF sortStringBuffer.Length = 0 THEN RETURN[NIL];
UNTIL keySpec =
NIL
DO
pos, index: CARDINAL ¬ 0;
finds the position of the field in the sortstringbuffer
WHILE keySpec.posInSortKeyFile # pos
DO
WHILE sortStringBuffer.Fetch[index] # Ascii.
NUL
DO
index ¬ index + 1; ENDLOOP;
pos ¬ pos + 1;
index ¬ index + 1;
ENDLOOP; --of while loop
WHILE sortStringBuffer.Fetch[index] # Ascii.
NUL
DO
sortKeyString ¬ ARAccess.AppendChar[
sortKeyString, sortStringBuffer.Fetch[index]];
index ¬ index + 1;
ENDLOOP; --of while loop;
sortKeyString ¬ ARAccess.AppendChar[sortKeyString, Ascii.NUL];
keySpec ¬ keySpec.next;
ENDLOOP; --of until loop
RETURN[sortKeyString];
}; --of SortKeysGetString
SortKeysPutString:
PROCEDURE [s: Rope.
ROPE, len:
CARDINAL] = {
count, index: CARDINAL ¬ 0;
c: CHAR;
i, pagePos, bytePos, lenPos: LONG CARDINAL ¬ 0;
GetString:
PROCEDURE
RETURNS [
LONG
CARDINAL ¬ 0] = {
tempstring ¬
NIL;
tempstring.length ← 0;
WHILE s.Fetch[index] # Ascii.
NUL
DO
tempstring ¬ ARAccess.AppendChar[tempstring, s.Fetch[index]];
String.AppendChar[tempstring, s[index]];
index ¬ index + 1;
ENDLOOP;
index ¬ index + 1;
RETURN[Convert.CardFromRope[tempstring, 10]];
RETURN[String.StringToLongNumber[tempstring, 10]];
}; --of GetString
pass the beginning of s until the position values are reached
x is number or character
n is a number
z is the nul character
s looks like x..xzx..xz...x..xzn..nzn..nzn..n
UNTIL count = numberOfKeySpecsEntered
DO
WHILE s.Fetch[index] # Ascii.NUL DO index ¬ index + 1; ENDLOOP;
count ¬ count + 1;
index ¬ index + 1;
ENDLOOP;
pagePos ¬ GetString[];
bytePos ¬ GetString[];
lenPos ¬ GetString[];
IF currentFileLength + lenPos > maxFileLength
THEN {
sortData.outputSH ¬ CleanUpStream[sortData.outputSH];
currentFileLength ¬ GetNextFileAndPutHeader[
data, outputFileName, headerLength];
sortData.fileNumber ¬ sortData.fileNumber + 1};
IO.SetIndex[sortData.inputSH, (adobeBytesPerPage * pagePos + bytePos)];
Stream.SetPosition[
sortData.inputSH,
(adobeBytesPerPage * pagePos + bytePos)];
FOR i
IN [1..lenPos]
DO
c ¬ IO.GetChar[sortData.inputSH];
IF c = Ascii.
LF
THEN
c ¬ Ascii.CR;
IO.PutChar[sortData.outputSH, c];
ENDLOOP; --of for loop
currentFileLength ¬ currentFileLength + lenPos;
}; --of SortKeysPutString
AdobeCommon.PostMessage[data, FALSE, "Sorting..."];
[currentFileLength, maxFileLength, headerLength,
numberOfKeySpecsEntered, outputFileName] ¬
InitializeSortVariables[data, sortKeySpecRef];
ReadFirstLine[sortData.sortKeysSH];
reportData ¬ GetSortData[];
WHILE maxWordsThisString # 0 DO
maxWordsThisString ← SortKeysGetString[sortKeyStringBuffer];
maxWordsAllStrings ← MAX[
maxWordsThisString, maxWordsAllStrings];
ENDLOOP;
maxCharsAllStrings ← 2 * maxWordsAllStrings;
sortStringBuffer ¬
NIL;
String.MakeString[Heap.systemZone, maxCharsAllStrings];
ReadFirstLine[sortData.sortKeysSH];
IF sortKeySpecRef =
NIL
THEN
CopyInputFileToOutputFile[
data, outputFileName, maxFileLength, tempstring,
headerLength]
no sorting necessary
ELSE {
TopoSort.ListSort[
alpha: NIL,
omega: NIL,
GetLink: GetLink,
SetLink: SetLink,
Compare: Compare];
maxCharsAllStrings ¬ 0;
WHILE reportData #
NIL
DO
SortKeysPutString[reportData.data, 0];
reportData ¬ reportData.next;
ENDLOOP;
};
GSort.Sort[
get: LOOPHOLE[SortKeysGetString],
put: LOOPHOLE[SortKeysPutString],
compare: LOOPHOLE[CompareStrings],
expectedItemSize: maxWordsAllStrings,
maxItemSize: maxWordsAllStrings, pagesInHeap: 127];
IF maxFileLength #
LAST[
LONG
CARDINAL]
THEN {
AdobeCommon.PostMessage[data, FALSE, "Output Files: "];
AdobeCommon.PostMessage[data, FALSE, outputFileName];
AdobeCommon.PostMessage[data, FALSE, "1.."];
AdobeCommon.PostMessage[data, FALSE, outputFileName];
AdobeCommon.PostNumber[data, TRUE, sortData.fileNumber - 1]};
free storage
Heap.systemZone.FREE[@sortStringBuffer];
Heap.systemZone.FREE[@sortKeyStringBuffer];
data.heap.FREE[@tempstring];
data.heap.FREE[@outputFileName];
IF sortKeySpecRef # NIL THEN FreeSortKeySpec[data, sortKeySpecRef];
sortData.sortKeysSH ¬ CleanUpStream[sortData.sortKeysSH];
sortData.inputSH ¬ CleanUpStream[sortData.inputSH];
sortData.outputSH ¬ CleanUpStream[sortData.outputSH];
};
ENDCASE;
}; --of Sort