-- Line sorting program to run in Laurel --
-- [Cherry]<Cholla>Laurel>LineSorter.mesa

-- Mike Schroeder, June 30, 1981 12:41 PM --
-- Edited by Brotz, November 19, 1981 3:56 PM --

DIRECTORY
BTreeDefs,
csD: FROM "CoreStreamDefs",
Inline,
IODefs,
String,
VMDefs;

LineSorter: PROGRAM
IMPORTS BTreeDefs, csD, Inline, IODefs, String, VMDefs =

BEGIN
OPEN IODefs, String;


MyLowerCase: PROCEDURE[c: CHARACTER] RETURNS [CHARACTER] = INLINE
BEGIN
RETURN[IF c IN [’A.. ’Z] THEN c - ’A + ’a ELSE c];
END; --MyLowerCase--


IsFirstGE: BTreeDefs.TestKeys --[a, b: DESC] RETURNS[BOOLEAN] -- =
BEGIN
aC: POINTER TO PACKED ARRAY OF CHARACTER = LOOPHOLE[BASE[a]];
bC: POINTER TO PACKED ARRAY OF CHARACTER = LOOPHOLE[BASE[b]];
FOR i: CARDINAL IN [0 .. 2*MIN[LENGTH[a], LENGTH[b]]) DO
IF MyLowerCase[aC[i]] < MyLowerCase[bC[i]] THEN RETURN[FALSE];
IF MyLowerCase[aC[i]] > MyLowerCase[bC[i]] THEN RETURN[TRUE];
ENDLOOP;
RETURN[LENGTH[a] >= LENGTH[b]];
END; -- of IsFirstGE --


AreTheyE: BTreeDefs.TestKeys --[a, b: DESC] RETURNS[BOOLEAN] -- =
BEGIN
aC: POINTER TO PACKED ARRAY OF CHARACTER = LOOPHOLE[BASE[a]];
bC: POINTER TO PACKED ARRAY OF CHARACTER = LOOPHOLE[BASE[b]];
IF LENGTH[a] = LENGTH[b] THEN
FOR i: CARDINAL IN [0 .. 2*LENGTH[a]) DO
IF MyLowerCase[aC[i]] # MyLowerCase[bC[i]] THEN EXIT;
REPEAT FINISHED => RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
END; -- of AreTheyE --


Run: PROCEDURE =
BEGIN
tree: BTreeDefs.BTreeHandle;
buffer: STRING = [48];
inputStr, outputStr: csD.StreamHandle ← NIL;

NextLine: PROCEDURE [s: STRING] RETURNS [ f: LONG CARDINAL, n: CARDINAL] =
BEGIN
c: CHARACTER;
s.length ← 0;
f ← csD.GetPosition[inputStr];
BEGIN ENABLE csD.EndOfStream => CONTINUE;
c ← csD.Read[inputStr];
UNTIL c # SP AND c # TAB DO c ← csD.Read[inputStr]; ENDLOOP;
UNTIL c = SP OR c = TAB OR c = CR DO
AppendChar[s, c ! StringBoundsFault => CONTINUE];
c ← csD.Read[inputStr];
ENDLOOP;
IF s.length/2 # 0 THEN AppendChar[s, SP];
UNTIL c = CR DO c ← csD.Read[inputStr]; ENDLOOP;
END; --enable--
n ← Inline.LowHalf[ csD.GetPosition[inputStr] - f];
END; --NextLine--

PutEntry: PROCEDURE [key: STRING, start: LONG CARDINAL, count: CARDINAL] =
BEGIN
keyWords: CARDINAL = (key.length+1)/2;
k: DESCRIPTOR FOR ARRAY OF WORD =
DESCRIPTOR [@(key.text), (keyWords + SIZE[LONG CARDINAL] + SIZE[CARDINAL])];
v: DESCRIPTOR FOR ARRAY OF WORD = DESCRIPTOR[NIL, 0];
Inline.COPY[from: @start, to: BASE[k] + keyWords, nwords: SIZE[LONG CARDINAL]];
Inline.COPY[from: @count, to: BASE[k]+keyWords+SIZE[LONG CARDINAL],
nwords: SIZE[CARDINAL]];
BTreeDefs.Insert[tree, k, v];
END; --PutEntry--

PrintingWork: BTreeDefs.Call
--PROCEDURE[k, v: DESCRIPTOR] RETURNS[more, dirty: BOOLEAN]-- =
BEGIN
first: LONG CARDINAL;
number: CARDINAL;
more ← TRUE; dirty ← FALSE;
IF LENGTH[k] = 0 THEN RETURN;
Inline.COPY[
from: BASE[k] + LENGTH[k] - SIZE[LONG CARDINAL] - SIZE[CARDINAL],
to: @first, nwords: SIZE[LONG CARDINAL]];
Inline.COPY[from: BASE[k] + LENGTH[k] - SIZE[CARDINAL], to: @number,
nwords: SIZE[CARDINAL]];
csD.SetPosition[inputStr, first];
csD.StreamCopy[inputStr, outputStr, LONG[number]];
END; --PrintingWork--

BEGIN --for EXITS --
tree ← BTreeDefs.CreateAndInitializeBTree[
fileH: LOOPHOLE[VMDefs.OpenFile[name: "DLMap.btree$", options: oldOrNew]],
initializeFile: TRUE, useDefaultOrderingRoutines: FALSE, isFirstGreaterOrEqual: IsFirstGE,
areTheyEqual: AreTheyE];
WriteChar[CR];
DO
WriteChar[CR];
WriteString["Type input file name: "L];
ReadID[buffer ! Rubout => LOOP];
IF buffer.length = 0 THEN GOTO cleanup;
inputStr ← csD.OpenFromName[buffer, byte, read
! VMDefs.Error, VMDefs.CantOpen => {WriteString["Can’t open input file."L]; LOOP}];
EXIT;
ENDLOOP;
DO
WriteChar[CR];
WriteString["Type output file name: "L];
ReadID[buffer ! Rubout => LOOP];
IF buffer.length = 0 THEN GOTO cleanup;
outputStr ← csD.OpenFromName[buffer, byte, overwrite
! VMDefs.Error, VMDefs.CantOpen => {WriteString["Can’t open output file."L]; LOOP}];
EXIT;
ENDLOOP;
WriteChar[CR];
WriteLine["Reading input file."L];
DO
start: LONG CARDINAL;
length: CARDINAL;
[start, length] ← NextLine[buffer
! VMDefs.Error => {WriteChar[CR]; WriteLine["File error."L]; GOTO cleanup}];
IF buffer.length = 0 THEN EXIT;
PutEntry[buffer, start, length];
ENDLOOP;
WriteLine["Writing output file."L];
BTreeDefs.EnumerateFrom[tree, DESCRIPTOR[NIL, 0], PrintingWork
! VMDefs.Error => {WriteChar[CR]; WriteLine["File error."L]; GOTO cleanup}];
GOTO cleanup;
EXITS
cleanup => BEGIN
IF inputStr # NIL THEN csD.Close[inputStr ! VMDefs.Error => CONTINUE];
IF outputStr # NIL THEN csD.Close[outputStr ! VMDefs.Error => CONTINUE];
VMDefs.AbandonFile[LOOPHOLE[BTreeDefs.ReleaseBTree[tree]]];
END;
END;
WriteLine["Done"L];
END; -- of Run --

Run[];

END. -- of LineSorter --