DIRECTORY Basics USING [DoubleAnd, DoubleNot, DoubleOr], PrincOpsUtils USING [LongCopy], TextLooks USING [BaseRuns, CreateRun, FetchLooks, FlatMax, Looks, MaxLen, noLooks, 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 = BEGIN Looks: TYPE ~ TextLooks.Looks; Runs: TYPE ~ TextLooks.Runs; RunsBody: TYPE ~ TextLooks.RunsBody; ReplaceByRun: PUBLIC PROC [dest: Runs, start, len, runLen, destSize: INT, inherit: BOOL, looks: Looks] RETURNS [Runs] = { merge: BOOL _ FALSE; mergeLooks: Looks; split, numruns: NAT; flat: TextLooks.BaseRuns; c, numRuns, oldPos, size: INT; Count: PROC [start, len: INT] RETURNS [INT] = { 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 [INT] = { c _ IF merge AND mergeLooks=looks THEN 0 ELSE 1; merge _ TRUE; mergeLooks _ looks; RETURN [numRuns_numRuns+c]; }; Extract: PROC [start, len: INT] = { IF len > 0 THEN split _ ExtractRuns[flat, dest, start, len, split]; }; TryFlatAppendRun: PROC [base: Runs] RETURNS [Runs] = { flat: TextLooks.BaseRuns; size: INT; [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: INT _ start+runLen; replace, new: Runs; WHILE dest # NIL DO WITH dest SELECT FROM x: REF RunsBody.node.replace => { xnewPos: INT _ x.newPos; xstart: INT _ 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: INT _ 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: Runs, start, len: INT, limit: INT _ TextLooks.MaxLen, merge: BOOL _ FALSE, firstLooks: Looks _ TextLooks.noLooks] RETURNS [count: INT, nonempty: BOOL, lastLooks: Looks] = { c: INT; 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: INT _ x.pos; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xpos THEN { subLen: INT _ 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: INT _ x.start; xnew: INT _ x.newPos; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xstart THEN { subLen: INT _ 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: INT _ start - xstart; subLen: INT _ 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: INT _ x.start; xend, subLen: INT; 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: Runs, start, len: INT, 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: INT; 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: INT _ x.pos; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xpos THEN { subLen: INT _ 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: INT _ x.start; xnew: INT _ x.newPos; len _ MIN[len, TextLooksSupport.CheckLongSub[x.size, start]]; IF start < xstart THEN { subLen: INT _ 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: INT _ start - xstart; subLen: INT _ 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: INT _ x.start; xend, subLen: INT; 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: INT, lower: NAT _ 0, upper: NAT _ LAST[NAT]] RETURNS [NAT] = { len: NAT; size: INT; 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: INT, looks: Looks, index: NAT] RETURNS [NAT] = { -- value is next index IF index=0 THEN { base[0] _ [len, looks]; index _ 1 } ELSE { loc: INT _ 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: INT] 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: INT, first, last: NAT] RETURNS [firstLen, lastLen: INT] = { IF first=last THEN RETURN[len, len]; RETURN[x[first].after-start, start+len-x[last-1].after] }; And: PROC [a, b: Looks] RETURNS [Looks] ~ INLINE { RETURN[LOOPHOLE[Basics.DoubleAnd[LOOPHOLE[a], LOOPHOLE[b]]]]; }; Or: PROC [a, b: Looks] RETURNS [Looks] ~ INLINE { RETURN[LOOPHOLE[Basics.DoubleOr[LOOPHOLE[a], LOOPHOLE[b]]]]; }; Not: PROC [a: Looks] RETURNS [Looks] ~ INLINE { RETURN[LOOPHOLE[Basics.DoubleNot[LOOPHOLE[a]]]]; }; LooksAND: PUBLIC PROC [looks1, looks2: Looks] RETURNS [Looks] ~ { RETURN[And[looks1, looks2]]; }; LooksOR: PUBLIC PROC [looks1, looks2: Looks] RETURNS [Looks] ~ { RETURN[Or[looks1, looks2]]; }; LooksNOT: PUBLIC PROC [looks: Looks] RETURNS [Looks] ~ { RETURN[Not[looks]]; }; ModifyLooks: PUBLIC PROC [old, remove, add: Looks] RETURNS [Looks] = { RETURN[Or[And[old, Not[remove]], add]]; }; MergeChanges: PUBLIC PROC [oldrem, oldadd, rem, add: Looks] RETURNS [newrem, newadd: Looks] = { RETURN[newrem: Or[oldrem, rem], newadd: Or[And[oldadd, Not[rem]], add]]; }; END. TextLooksBasicImpl.mesa Copyright c 1985, 1986 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 Michael Plass, April 8, 1985 3:33:49 pm PST Doug Wyatt, September 3, 1986 1:08:08 pm PDT 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œ7™BKšœ%™%Kšœ™Kšœ ™ Kšœ$™$Kšœ+™+Kšœ,™,—K™šΟk ˜ Kšœžœ"˜.Kšœžœ ˜ Kšœ žœ|˜‹Kšœžœ[˜q—K˜KšΟnœžœž˜!Kšžœ3˜:Kšžœ˜#Kšœž˜K˜Kšœžœ˜Kšœžœ˜Kšœ žœ˜$K˜š Ÿ œžœžœ,žœ žœžœ ˜yKšœžœžœ˜Kšœ˜Kšœžœ˜K˜Kšœžœ˜š Ÿœžœžœžœžœ˜/Kšžœžœžœ ˜˜K˜J—Kšžœ˜K˜—šŸœžœžœžœ˜Kš œžœžœžœžœ˜0Kšœžœ˜!Kšžœ˜K˜—šŸœžœžœ˜#Kšžœ žœ4˜CK˜—šŸœžœžœ ˜6K˜Kšœžœ˜ K˜`Kš žœžœžœžœžœ˜PK˜8K˜,K˜.Kšžœžœžœ˜Kšžœ%žœžœ˜2Kšžœ˜K˜—K•StartOfExpansion†[base: TextLooks.Runs, start: INT, len: INT, replace: TextLooks.Runs, baseSize: INT, repSize: INT, tryFlat: BOOL _ TRUE]š žœ žœžœAžœ+žœ˜šžœ žœΟc˜.Kšžœžœžœ ˜/šžœ$˜(Kšžœ žœ  ˜9Kšžœžœžœ ˜3Kšžœ ˜)—K˜—Kš žœžœžœžœžœžœ˜9K˜<šžœ%žœžœ4žœ˜‚Kšœžœ˜Kšœ˜šžœžœž˜šžœžœž˜šœžœ˜!Kšœ žœ ˜Kšœžœ ˜šžœžœžœ˜/Kšœ™KšœFžœ˜LK˜—Kšžœžœ ˜7šžœ%žœžœ˜2K˜&K˜Kšœ[™[K˜—K˜—šœžœ ,˜MKšœžœ ˜Kšžœ žœžœ˜šœ!žœžœžœ˜2šžœ!˜$K˜%——K˜—Kšžœ˜—Kšžœ˜Kšžœ˜—Kš žœ žœžœ0žœž˜JK˜+Kšžœžœžœ+˜;KšžœžœS˜^K˜—Kšžœ žœžœžœ˜K˜CK˜K˜.K˜!Kšžœžœžœ˜Kšžœžœžœ˜+Kšžœ˜K˜K˜—šŸ œžœžœžœ žœžœžœ)žœ žœ žœ˜ΚKšœ!™!KšœF™FKšœžœ˜K˜ šžœ˜Kšžœžœžœ˜1šžœžœžœ˜Kš œžœžœžœžœ˜