NodeReaderImpl.mesa
Copyright Ó 1991, 1992 by Xerox Corporation. All rights reserved.
Doug Wyatt, March 27, 1992 4:52 pm PST
DIRECTORY
Basics USING [BoundsCheckInt, NonNegative],
Char USING [CharCode, CharSet, Make, XCHAR],
NodeReader USING [Ref, Rep, CharInfo],
Rope USING [ROPE, AppendChars, Size],
Rosary USING [ROSARY, ContainingRun, FetchContainingRun],
TextEdit USING [CharSetFromItem, LooksFromItem, PropListFromItem],
TextFind USING [CharMap, CharMapFromCase],
Tioga USING [Node, Looks, PropList];
NodeReaderImpl: CEDAR MONITOR
IMPORTS Basics, Char, Rope, Rosary, TextEdit, TextFind
EXPORTS NodeReader
= BEGIN
ROPE: TYPE ~ Rope.ROPE;
ROSARY: TYPE ~ Rosary.ROSARY;
Ref: TYPE ~ NodeReader.Ref;
Rep: TYPE ~ NodeReader.Rep;
CharInfo: TYPE ~ NodeReader.CharInfo;
CacheIndex: TYPE ~ [0..3);
cache: ARRAY CacheIndex OF Ref ¬ ALL[NIL];
CacheAlloc: ENTRY PROC RETURNS [reader: Ref ¬ NIL] = {
FOR i: CacheIndex IN CacheIndex DO
IF (reader ¬ cache[i])#NIL THEN { cache[i] ¬ NIL; EXIT };
ENDLOOP;
};
CacheFree: ENTRY PROC [reader: Ref] = {
FOR i: CacheIndex IN CacheIndex DO
IF cache[i]=reader THEN RETURN; -- don't cache it twice!
ENDLOOP;
FOR i: CacheIndex IN CacheIndex DO
IF cache[i]=NIL THEN { cache[i] ¬ reader; EXIT };
ENDLOOP;
};
New: PUBLIC PROC [node: Tioga.Node, oldReader: Ref ¬ NIL] RETURNS [reader: Ref] ~ {
reader ¬ oldReader;
IF reader=NIL THEN reader ¬ CacheAlloc[];
IF reader=NIL THEN reader ¬ NEW[Rep];
Set[reader, node];
};
Free: PUBLIC PROC [reader: Ref] ~ {
Set[reader, NIL];
CacheFree[reader];
};
textSize: NAT ~ 128;
Set: PUBLIC PROC [reader: Ref, node: Tioga.Node] ~ {
IF node#NIL
THEN SetParts[reader, node.rope, node.runs, node.charSets, node.charProps]
ELSE SetParts[reader, NIL, NIL, NIL, NIL];
};
SetParts: PUBLIC PROC [reader: Ref, rope: ROPE, runs, charSets, charProps: ROSARY] ~ {
text: REF TEXT ¬ reader.text;
IF text=NIL OR text.maxLength<textSize THEN text ¬ NEW[TEXT[textSize]];
reader­ ¬ [];
reader.text ¬ text;
reader.size ¬ Rope.Size[rope];
reader.rope ¬ rope;
reader.runs ¬ runs;
reader.charSets ¬ charSets;
reader.charProps ¬ charProps;
IF reader.size>0 THEN {
IF runs=NIL THEN reader.looksEnd ¬ reader.size; -- noLooks for all chars
IF charSets=NIL THEN reader.charSetEnd ¬ reader.size; -- 0 for all chars
IF charProps=NIL THEN reader.propsEnd ¬ reader.size; -- NIL for all chars
};
};
UpdateText: PROC [reader: Ref, index: INT] ~ {
start: INT ~ (Basics.BoundsCheckInt[index, reader.size]/textSize)*textSize;
text: REF TEXT ~ reader.text;
IF text.maxLength<textSize THEN ERROR;
text.length ¬ 0;
[] ¬ Rope.AppendChars[buffer: text, rope: reader.rope, start: start, len: textSize];
reader.textStart ¬ start;
reader.textEnd ¬ start+text.length;
};
UpdateLooks: PROC [reader: Ref, index: INT] ~ {
run: Rosary.ContainingRun ~ Rosary.FetchContainingRun[reader.runs, index];
reader.looks ¬ TextEdit.LooksFromItem[run.item];
reader.looksStart ¬ run.start;
reader.looksEnd ¬ run.end;
};
UpdateCharSet: PROC [reader: Ref, index: INT] ~ {
run: Rosary.ContainingRun ~ Rosary.FetchContainingRun[reader.charSets, index];
reader.charSet ¬ TextEdit.CharSetFromItem[run.item];
reader.charSetStart ¬ run.start;
reader.charSetEnd ¬ run.end;
};
UpdateProps: PROC [reader: Ref, index: INT] ~ {
run: Rosary.ContainingRun ~ Rosary.FetchContainingRun[reader.charProps, index];
reader.props ¬ TextEdit.PropListFromItem[run.item];
reader.propsStart ¬ run.start;
reader.propsEnd ¬ run.end;
};
Fetch: PUBLIC PROC [reader: Ref, index: INT] RETURNS [CharInfo] ~ {
IF index NOT IN [reader.textStart..reader.textEnd) THEN UpdateText[reader, index];
IF index NOT IN [reader.looksStart..reader.looksEnd) THEN UpdateLooks[reader, index];
IF index NOT IN [reader.charSetStart..reader.charSetEnd) THEN UpdateCharSet[reader, index];
IF index NOT IN [reader.propsStart..reader.propsEnd) THEN UpdateProps[reader, index];
RETURN[[char: Char.Make[reader.charSet, ORD[reader.text[index-reader.textStart]]],
looks: reader.looks, props: reader.props]];
};
FetchChar: PUBLIC PROC [reader: Ref, index: INT] RETURNS [Char.XCHAR] ~ {
IF index NOT IN [reader.textStart..reader.textEnd) THEN UpdateText[reader, index];
IF index NOT IN [reader.charSetStart..reader.charSetEnd) THEN UpdateCharSet[reader, index];
RETURN[Char.Make[reader.charSet, ORD[reader.text[index-reader.textStart]]]];
};
FetchCharSet: PUBLIC PROC [reader: Ref, index: INT] RETURNS [Char.CharSet] ~ {
IF index NOT IN [reader.charSetStart..reader.charSetEnd) THEN UpdateCharSet[reader, index];
RETURN[reader.charSet];
};
FetchCharCode: PUBLIC PROC [reader: Ref, index: INT] RETURNS [Char.CharCode] ~ {
IF index NOT IN [reader.textStart..reader.textEnd) THEN UpdateText[reader, index];
RETURN[ORD[reader.text[index-reader.textStart]]];
};
FetchLooks: PUBLIC PROC [reader: Ref, index: INT] RETURNS [Tioga.Looks] ~ {
IF index NOT IN [reader.looksStart..reader.looksEnd) THEN UpdateLooks[reader, index];
RETURN[reader.looks];
};
FetchProps: PUBLIC PROC [reader: Ref, index: INT] RETURNS [Tioga.PropList] ~ {
IF index NOT IN [reader.propsStart..reader.propsEnd) THEN UpdateProps[reader, index];
RETURN[reader.props];
};
Run: PUBLIC PROC [r1: Ref, pos1: INT, r2: Ref, pos2: INT, case: BOOL, len: INT]
RETURNS [count: INT ¬ 0] ~ {
rem1: INT ~ Basics.NonNegative[r1.size-Basics.NonNegative[pos1]];
rem2: INT ~ Basics.NonNegative[r2.size-Basics.NonNegative[pos2]];
maxCount: INT ~ MIN[len, rem1, rem2];
WHILE count<maxCount DO
i1: INT ~ pos1+count;
i2: INT ~ pos2+count;
IF i1 NOT IN [r1.charSetStart..r1.charSetEnd) THEN UpdateCharSet[r1, i1];
IF i2 NOT IN [r2.charSetStart..r2.charSetEnd) THEN UpdateCharSet[r2, i2];
IF r1.charSet#r2.charSet THEN EXIT;
IF i1 NOT IN [r1.textStart..r1.textEnd) THEN UpdateText[r1, i1];
IF i2 NOT IN [r2.textStart..r2.textEnd) THEN UpdateText[r2, i2];
{
map: TextFind.CharMap ~ TextFind.CharMapFromCase[case OR r1.charSet#0];
runLen: NAT ~ MIN[maxCount-count,
r1.textEnd-i1, r2.textEnd-i2, r1.charSetEnd-i1, r2.charSetEnd-i2];
base1: NAT ~ i1-r1.textStart;
base2: NAT ~ i2-r2.textStart;
FOR k: NAT IN[0..runLen) DO
IF map[r1.text[base1+k]]#map[r2.text[base2+k]] THEN RETURN[count+k];
ENDLOOP;
count ¬ count+runLen;
};
ENDLOOP;
};
END.