DIRECTORY Basics USING [BITAND, BITNOT, BITOR], PrincOpsUtils USING [LongCopy], TextLooks USING [BaseRuns, CreateRun, FetchLooks, FlatMax, Looks, MaxOffset, noLooks, Offset, Replace, Run, Runs, RunsBody, Size, Tconcat, Treplace], TextLooksSupport USING [CheckLongSub, CountRunsAfterChanges, ExtractRunsAfterChanges, MakeRun, Short, TbaseSize]; TextLooksBasicImpl: CEDAR PROGRAM IMPORTS Basics, PrincOpsUtils, TextLooks, TextLooksSupport EXPORTS TextLooks, TextLooksSupport = { RunsBody: TYPE ~ TextLooks.RunsBody; ReplaceByRun: PUBLIC PROC [dest: TextLooks.Runs, start, len, runLen, destSize: TextLooks.Offset, inherit: BOOL, looks: TextLooks.Looks] RETURNS [TextLooks.Runs] = { merge: BOOL _ FALSE; mergeLooks: TextLooks.Looks; split, numruns: NAT; flat: TextLooks.BaseRuns; c, numRuns, oldPos, size: TextLooks.Offset; Count: PROC [start, len: TextLooks.Offset] RETURNS [TextLooks.Offset] = { IF len=0 THEN RETURN[numRuns]; [c, merge, mergeLooks] _ CountRuns[dest, start, len, TextLooks.FlatMax-numRuns, merge, mergeLooks]; RETURN [numRuns_numRuns+c]; }; AddIt: PROC RETURNS [TextLooks.Offset] = { c _ IF merge AND mergeLooks=looks THEN 0 ELSE 1; merge _ TRUE; mergeLooks _ looks; RETURN [numRuns_numRuns+c]; }; Extract: PROC [start, len: TextLooks.Offset] = { IF len > 0 THEN split _ ExtractRuns[flat, dest, start, len, split]; }; TryFlatAppendRun: PROC [base: TextLooks.Runs] RETURNS [TextLooks.Runs] = { flat: TextLooks.BaseRuns; size: TextLooks.Offset; [numRuns, merge, mergeLooks] _ CountRuns[base, 0, size_TextLooks.Size[base], TextLooks.FlatMax]; IF numRuns > TextLooks.FlatMax OR AddIt[] > TextLooks.FlatMax THEN RETURN [NIL]; flat _ NewBase[numruns_TextLooksSupport.Short[numRuns]]; split _ ExtractRuns[flat, base, 0, size, 0]; split _ InsertRun[flat, runLen, looks, split]; IF split # numruns THEN ERROR; IF flat[numruns-1].after # size+runLen THEN ERROR; RETURN [flat]; }; IF runLen=0 THEN RETURN [TextLooks.Replace[base: dest, start: start, len: len, replace: NIL, baseSize: destSize, repSize: 0, tryFlat: TRUE]]; IF inherit THEN {-- get looks from destination IF destSize = 0 THEN NULL -- take from arg list ELSE looks _ TextLooks.FetchLooks[dest, IF start > 0 THEN start-1 -- take from before replacement ELSE IF len=destSize THEN 0 -- replacing everything ELSE len]; -- take from after replacement }; IF dest=NIL AND looks=TextLooks.noLooks THEN RETURN[NIL]; numRuns _ 0; oldPos _ start+len; size _ destSize-len+runLen; IF Count[0, start] > TextLooks.FlatMax OR AddIt[] > TextLooks.FlatMax OR Count[oldPos, destSize-oldPos] > TextLooks.FlatMax THEN { newPos: TextLooks.Offset _ start+runLen; replace, new: TextLooks.Runs; WHILE dest # NIL DO WITH dest SELECT FROM x: REF RunsBody.node.replace => { xnewPos: TextLooks.Offset _ x.newPos; xstart: TextLooks.Offset _ x.start; IF start <= xstart AND oldPos >= xnewPos THEN { oldPos _ x.oldPos+(oldPos-xnewPos); dest _ x.base; len _ oldPos-start; LOOP; } ELSE IF start = xnewPos -- appending to the replacement AND (new _ TryFlatAppendRun[x.replace])#NIL THEN { start _ xstart; oldPos _ x.oldPos+len; dest _ x.base; replace _ new; } }; x: REF RunsBody.node.concat => { -- try to append to first part of the concat xpos: TextLooks.Offset _ x.pos; IF start=xpos AND len=0 AND (new _ TryFlatAppendRun[x.base])#NIL THEN RETURN [ NEW[TextLooks.Tconcat _ [node[concat [size, new, x.rest, xpos+runLen]]]]]; }; ENDCASE; EXIT; ENDLOOP; IF replace=NIL AND (replace _ TextLooks.CreateRun[runLen, looks])=NIL THEN replace _ TextLooksSupport.MakeRun[runLen]; IF dest=NIL THEN dest _ TextLooksSupport.MakeRun[destSize]; RETURN [NEW[TextLooks.Treplace _ [node[replace[size, dest, replace, start, oldPos, newPos]]]]] }; IF numRuns=0 THEN RETURN[NIL]; flat _ NewBase[numruns_TextLooksSupport.Short[numRuns]]; split _ 0; Extract[0, start]; split _ InsertRun[flat, runLen, looks, split]; Extract[oldPos, destSize-oldPos]; IF split # numruns THEN ERROR; IF flat[numruns-1].after # size THEN ERROR; RETURN [flat] }; CountRuns: PUBLIC PROC [runs: TextLooks.Runs, start, len: TextLooks.Offset, limit: TextLooks.Offset _ TextLooks.MaxOffset, merge: BOOL _ FALSE, firstLooks: TextLooks.Looks _ TextLooks.noLooks] RETURNS [count: TextLooks.Offset, nonempty: BOOL, lastLooks: TextLooks.Looks] = { c: TextLooks.Offset; count _ 0; DO nonempty _ merge; IF len=0 THEN { lastLooks _ firstLooks; RETURN }; IF runs=NIL THEN { c _ IF merge AND firstLooks=TextLooks.noLooks THEN 0 ELSE 1; RETURN [count+c, TRUE, TextLooks.noLooks] }; WITH runs SELECT FROM x: REF RunsBody.base => { first, last: NAT; len _ MIN[len, TextLooksSupport.CheckLongSub[TextLooksSupport.TbaseSize[x], start]]; [first, last] _ FindBaseRuns[x, start, len]; c _ last-first+1; IF merge AND firstLooks=x[first].looks THEN c _ c-1; RETURN [count+c, TRUE, x[last].looks] }; x: REF RunsBody.node.substr => { len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; start _ start + x.start; runs _ x.base; LOOP }; x: REF RunsBody.node.concat => { xpos: TextLooks.Offset _ x.pos; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xpos THEN { subLen: TextLooks.Offset _ xpos - start; IF len <= subLen THEN { runs _ x.base; LOOP }; [c, merge, firstLooks] _ CountRuns[ x.base, start, subLen, limit, merge, firstLooks]; count _ count+c; IF c > limit THEN RETURN; limit _ limit-c; start _ xpos; len _ len-subLen; }; start _ start-xpos; runs _ x.rest; LOOP }; x: REF RunsBody.node.replace => { xstart: TextLooks.Offset _ x.start; xnew: TextLooks.Offset _ x.newPos; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xstart THEN { subLen: TextLooks.Offset _ xstart - start; IF len <= subLen THEN {runs _ x.base; LOOP}; [c, merge, firstLooks] _ CountRuns[ x.base, start, subLen, limit, merge, firstLooks]; count _ count+c; IF c > limit THEN RETURN; limit _ limit-c; start _ xstart; len _ len-subLen; }; IF start < xnew THEN { st: TextLooks.Offset _ start - xstart; subLen: TextLooks.Offset _ xnew - start; IF len <= subLen THEN { start _ st; runs _ x.replace; LOOP }; [c, merge, firstLooks] _ CountRuns[ x.replace, st, subLen, limit, merge, firstLooks]; count _ count+c; IF c > limit THEN RETURN; limit _ limit-c; start _ xnew; len _ len-subLen }; start _ start - xnew + x.oldPos; runs _ x.base; LOOP }; x: REF RunsBody.node.change => { xstart: TextLooks.Offset _ x.start; xend, subLen: TextLooks.Offset; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xstart THEN { IF len <= (subLen _ xstart-start) THEN {runs _ x.base; LOOP}; [c, merge, firstLooks] _ CountRuns[ x.base, start, subLen, limit, merge, firstLooks]; count _ count+c; IF c > limit THEN RETURN; limit _ limit-c; start _ xstart; len _ len-subLen; }; IF start < (xend _ xstart+x.len) THEN { subLen _ MIN[xend-start, len]; [c, merge, firstLooks] _ TextLooksSupport.CountRunsAfterChanges[ x.base, start, subLen, limit, x.remove, x.add, merge, firstLooks]; count _ count+c; IF c > limit THEN RETURN; limit _ limit-c; start _ xend; len _ len-subLen; }; runs _ x.base; LOOP }; ENDCASE => ERROR; ENDLOOP; }; ExtractRuns: PUBLIC PROC [base: TextLooks.BaseRuns, ref: TextLooks.Runs, start, len: TextLooks.Offset, index: NAT _ 0] RETURNS [NAT] = TRUSTED { -- value is next index DO IF len=0 THEN RETURN [index]; IF ref=NIL THEN -- treat as noLooks RETURN [InsertRun[base, len, TextLooks.noLooks, index]]; WITH ref SELECT FROM x: REF RunsBody.base => { firstLen, lastLen, xloc, next, loc: TextLooks.Offset; first, last: NAT; len _ MIN[len, TextLooksSupport.CheckLongSub[TextLooksSupport.TbaseSize[x], start]]; [first, last] _ FindBaseRuns[x, start, len]; [firstLen, lastLen] _ BaseRunLengths[x, start, len, first, last]; IF index=0 THEN { -- this is the first run to be extracted loc _ firstLen; base[0] _ [loc, x[first].looks]; index _ 1; } ELSE { loc _ base[index-1].after + firstLen; IF base[index-1].looks=x[first].looks -- merge runs THEN base[index-1].after _ loc ELSE { base[index] _ [loc, x[first].looks]; index _ index+1 } }; IF first=last THEN RETURN [index]; IF (xloc _ x[first].after) = loc THEN { -- can simply copy runs numRuns: NAT; IF (numRuns _ last-first-1) > 0 THEN { CopyRuns[to:base, toLoc:index, from:x, fromLoc:first+1, nRuns: numRuns]; index _ index+numRuns; loc _ base[index-1].after } } ELSE FOR i: NAT IN (first..last) DO loc _ loc + (next _ x[i].after) - xloc; xloc _ next; base[index] _ [loc, x[i].looks]; index _ index+1; ENDLOOP; base[index] _ [loc+lastLen, x[last].looks]; RETURN [index+1] }; x: REF RunsBody.node.substr => { len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; start _ start + x.start; ref _ x.base; LOOP }; x: REF RunsBody.node.concat => { xpos: TextLooks.Offset _ x.pos; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xpos THEN { subLen: TextLooks.Offset _ xpos - start; IF len <= subLen THEN { ref _ x.base; LOOP }; index _ ExtractRuns[base, x.base, start, subLen, index]; start _ xpos; len _ len-subLen }; start _ start-xpos; ref _ x.rest; LOOP }; x: REF RunsBody.node.replace => { xstart: TextLooks.Offset _ x.start; xnew: TextLooks.Offset _ x.newPos; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xstart THEN { subLen: TextLooks.Offset _ xstart - start; IF len <= subLen THEN {ref _ x.base; LOOP}; index _ ExtractRuns[base, x.base, start, subLen, index]; start _ xstart; len _ len-subLen }; IF start < xnew THEN { st: TextLooks.Offset _ start - xstart; subLen: TextLooks.Offset _ xnew - start; IF len <= subLen THEN { start _ st; ref _ x.replace; LOOP }; index _ ExtractRuns[base, x.replace, st, subLen, index]; start _ xnew; len _ len-subLen }; start _ start - xnew + x.oldPos; ref _ x.base; LOOP }; x: REF RunsBody.node.change => { xstart: TextLooks.Offset _ x.start; xend, subLen: TextLooks.Offset; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xstart THEN { IF len <= (subLen _ xstart-start) THEN {ref _ x.base; LOOP}; index _ ExtractRuns[base, x.base, start, subLen, index]; start _ xstart; len _ len-subLen }; IF start < (xend _ xstart+x.len) THEN { subLen _ MIN[xend-start, len]; index _ TextLooksSupport.ExtractRunsAfterChanges[ base, x.base, x.remove, x.add, start, subLen, index]; start _ xend; len _ len-subLen }; ref _ x.base; LOOP }; ENDCASE => ERROR; ENDLOOP }; NewBase: PUBLIC PROC [runs: NAT] RETURNS [TextLooks.BaseRuns] = { RETURN [NEW[base TextLooks.RunsBody[runs]]]; }; BaseRun: PUBLIC PROC [x: TextLooks.BaseRuns, index: TextLooks.Offset, lower: NAT _ 0, upper: NAT _ LAST[NAT]] RETURNS [NAT] = { len: NAT; size: TextLooks.Offset; IF index = 0 THEN RETURN [0]; IF (len_x.length) <= 1 THEN RETURN [0]; IF index+1 >= (size_TextLooksSupport.TbaseSize[x]) THEN RETURN[len-1]; IF upper >= len THEN upper _ len-1; IF lower > 0 AND x[lower-1].after > index THEN lower _ 0; DO -- always know index is in run between lower and upper inclusive run: NAT _ (upper+lower)/2; IF index < x[run].after THEN upper _ run ELSE lower _ run+1; IF upper=lower THEN RETURN[upper]; ENDLOOP }; CopyRuns: PUBLIC PROC [to, from: TextLooks.BaseRuns, toLoc, fromLoc, nRuns: NAT] = TRUSTED { RunsOffset: NAT = SIZE[base TextLooks.RunsBody[0]]; nLeft: NAT; IF nRuns=0 THEN RETURN; IF fromLoc >= from.length OR toLoc >= to.length THEN ERROR; nLeft _ nRuns-1; to[toLoc+nLeft] _ from[fromLoc+nLeft]; -- bounds check PrincOpsUtils.LongCopy[ from: LOOPHOLE[from, LONG POINTER]+fromLoc*SIZE[TextLooks.Run]+RunsOffset, to: LOOPHOLE[to, LONG POINTER]+toLoc*SIZE[TextLooks.Run]+RunsOffset, nwords: nLeft*SIZE[TextLooks.Run]] }; InsertRun: PUBLIC PROC [base: TextLooks.BaseRuns, len: TextLooks.Offset, looks: TextLooks.Looks, index: NAT] RETURNS [NAT] = { -- value is next index IF index=0 THEN { base[0] _ [len, looks]; index _ 1 } ELSE { loc: TextLooks.Offset _ base[index-1].after + len; IF base[index-1].looks=looks -- merge runs THEN base[index-1].after _ loc ELSE { base[index] _ [loc, looks]; index _ index+1 } }; RETURN [index] }; FindBaseRuns: PUBLIC PROC [x: TextLooks.BaseRuns, start, len: TextLooks.Offset] RETURNS [first, last: NAT] = { first _ BaseRun[x, start]; last _ IF len>1 THEN BaseRun[x, start+len-1, first] ELSE first }; BaseRunLengths: PUBLIC PROC [x: TextLooks.BaseRuns, start, len: TextLooks.Offset, first, last: NAT] RETURNS [firstLen, lastLen: TextLooks.Offset] = { IF first=last THEN RETURN[len, len]; RETURN[x[first].after-start, start+len-x[last-1].after] }; Lks: TYPE = ARRAY [0..1] OF CARDINAL; ModifyLooks: PUBLIC PROC [old, remove, add: TextLooks.Looks] RETURNS [TextLooks.Looks] = { oldlks: Lks _ LOOPHOLE[old]; addlks: Lks _ LOOPHOLE[add]; remlks: Lks _ LOOPHOLE[remove]; newlks: Lks; newlks[0] _ Basics.BITOR[addlks[0], Basics.BITAND[Basics.BITNOT[remlks[0]], oldlks[0]]]; newlks[1] _ Basics.BITOR[addlks[1], Basics.BITAND[Basics.BITNOT[remlks[1]], oldlks[1]]]; RETURN [LOOPHOLE[newlks]]; }; MergeChanges: PUBLIC PROC [oldrem, oldadd, rem, add: TextLooks.Looks] RETURNS [newrem, newadd: TextLooks.Looks] = { oldaddlks: Lks _ LOOPHOLE[oldadd]; oldremlks: Lks _ LOOPHOLE[oldrem]; remlks: Lks _ LOOPHOLE[rem]; addlks: Lks _ LOOPHOLE[add]; newremlks, newaddlks: Lks; newremlks[0] _ Basics.BITOR[oldremlks[0], remlks[0]]; newremlks[1] _ Basics.BITOR[oldremlks[1], remlks[1]]; newaddlks[0] _ Basics.BITOR[addlks[0], Basics.BITAND[Basics.BITNOT[remlks[0]], oldaddlks[0]]]; newaddlks[1] _ Basics.BITOR[addlks[1], Basics.BITAND[Basics.BITNOT[remlks[1]], oldaddlks[1]]]; RETURN [LOOPHOLE[newremlks], LOOPHOLE[newaddlks]]; }; }. φTextLooksBasicImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. written by Bill Paxton, February 1981 Bill Paxton, 7-Dec-81 11:33:25 Maxwell, January 5, 1983 3:55 pm Russ Atkinson, July 25, 1983 3:41 pm Doug Wyatt, March 3, 1985 2:56:07 pm PST Michael Plass, April 8, 1985 3:33:49 pm PST replacing the replacement Exit the loop from here; len and runLen are not needed anymore, so don't upate the values. stops counting when exceeds limit if merge is true, then doesn't count first run if its looks=firstLooks now extract the runs modified looks are == (old & ~remove) v add ((lks & ~oldrem) v oldadd) & ~rem) v add == lks & ~(oldrem v rem)) v ((oldadd & ~rem) v add thus, newrem _ oldrem v rem, newadd _ (oldadd & ~rem) v add ΚΙ˜codešœ™Kšœ Οmœ1™