DIRECTORY AbbrevExpand, Atom, CIFS, EditSpan, Inline, IO, PutGet, RefTab, Rope, RopeEdit, RopeReader, TextEdit, TiogaLooks, TiogaNode, TiogaNodeOps; AbbrevExpandImpl: CEDAR MONITOR IMPORTS Atom, CIFS, EditSpan, Inline, IO, PutGet, RefTab, Rope, RopeEdit, RopeReader, TextEdit, TiogaNodeOps EXPORTS AbbrevExpand = BEGIN OPEN AbbrevExpand; dictTable: RefTab.Ref _ RefTab.Create[]; Entry: TYPE = REF EntryRec; EntryRec: TYPE = RECORD [ next: Entry, hash: CARDINAL, keyRope: ROPE, node: RefTextNode, commands: LIST OF REF ANY ]; Load: PUBLIC PROC [fileName, dictName: ROPE, start: Offset _ 0, len: Offset _ MaxLen, okToMapFile: BOOLEAN _ FALSE] RETURNS [count: NAT] = { rdr: RopeReader.Ref; dict: ATOM = GetDictAtom[dictName]; root: RefBranchNode; count _ 0; [] _ RefTab.Store[dictTable, dict, NoDictAtom]; -- clears the dictionary root _ PutGet.FromFile[fileName, start, len, okToMapFile]; rdr _ RopeReader.GetRopeReader[]; FOR n: Ref _ TiogaNodeOps.BranchChild[root], TiogaNodeOps.Next[n] UNTIL n=NIL DO node: RefTextNode _ TiogaNodeOps.NarrowToTextNode[n]; IF node=NIL OR node.rope=NIL THEN LOOP; AddToDict[root, node, dict, rdr]; count _ count+1; ENDLOOP; RopeReader.FreeRopeReader[rdr] }; AddToDict: ENTRY PROC [ root: RefBranchNode, node: RefTextNode, dictAtom: ATOM, rdr: RopeReader.Ref _ NIL] = { ENABLE UNWIND => NULL; dict: Entry _ GetDict[dictAtom]; keyRope: ROPE _ node.rope; keyStart: Offset = 0; hash: CARDINAL; entry: Entry; keyLen: NAT; freeRdr: BOOLEAN _ FALSE; resultStart: Offset; commands: LIST OF REF ANY; IF rdr=NIL THEN { rdr _ RopeReader.GetRopeReader[]; freeRdr _ TRUE }; keyLen _ FindKeyLen[keyRope,rdr]; IF keyLen=0 THEN { IF freeRdr THEN RopeReader.FreeRopeReader[rdr]; RETURN }; -- not an entry hash _ KeyHash[keyRope,keyStart,keyLen,rdr]; entry _ LookupInternal[dict,hash,keyRope,keyStart,keyLen,rdr]; IF entry = NIL THEN { -- add new entry entry _ NEW[EntryRec]; IF dict # NIL THEN { entry.next _ dict.next; dict.next _ entry } ELSE [] _ RefTab.Store[dictTable,dictAtom,entry] }; entry.hash _ hash; entry.keyRope _ RopeEdit.Substr[keyRope,keyStart,keyLen]; entry.node _ node; [resultStart,commands] _ ParseCommands[keyRope,keyStart+keyLen,rdr]; entry.commands _ commands; TextEdit.DeleteText[root,node,0,resultStart]; IF freeRdr THEN RopeReader.FreeRopeReader[rdr]; }; ParseCommands: PROC [keyRope: ROPE, start: Offset, rdr: RopeReader.Ref] RETURNS [end: Offset, commands: LIST OF REF ANY] = { OPEN RopeReader; ENABLE ReadOffEnd => GOTO Bad; blank: BOOLEAN; SetPosition[rdr, keyRope, start]; IF RopeEdit.BlankChar[Peek[rdr]] THEN { blank _ TRUE; [] _ Get[rdr] } ELSE blank _ FALSE; IF Peek[rdr] = '( THEN { -- parse command list h: IO.Handle _ IO.CreateInputStreamFromRope[RopeEdit.Substr[keyRope,start _ GetIndex[rdr]]]; commands _ NARROW[IO.GetRefAny[h]]; start _ start+IO.GetIndex[h]; IO.Close[h]; SetPosition[rdr, keyRope, start]; IF RopeEdit.BlankChar[Peek[rdr]] THEN { blank _ TRUE; [] _ Get[rdr] } ELSE blank _ FALSE; }; IF Peek[rdr] = '= THEN { -- check for blank [] _ Get[rdr]; IF blank AND Peek[rdr] = ' THEN [] _ Get[rdr]; -- skip blank after = if there was one before end _ GetIndex[rdr]; } ELSE end _ RopeEdit.Size[keyRope]; EXITS Bad => RETURN [RopeEdit.Size[keyRope],commands]; }; Clear: PUBLIC ENTRY PROC [dictName: ROPE] = { ENABLE UNWIND => NULL; [] _ RefTab.Store[dictTable, GetDictAtom[dictName], NIL] }; IllFormedDef: PUBLIC ERROR = CODE; GetDictAtom: PROC [dictName: ROPE] RETURNS [dict: ATOM] = { force: SAFE PROC RETURNS [c: CHAR] = CHECKED { IF (c _ Rope.Fetch[dictName,i]) IN ['A..'Z] THEN c _ c-'A+'a; i _ i+1 }; i: INT _ 0; RETURN [Atom.MakeAtom[Rope.FromProc[Rope.Size[dictName],force]]]; }; Expand: PUBLIC PROC [keyNode: RefTextNode, keyEnd: Offset, dict: ROPE, event: Event _ NIL] RETURNS [foundIt: BOOLEAN, keyDeterminesDict: BOOLEAN, keyStart, keyLen, resultLen: Offset, commands: LIST OF REF ANY] = { NodeFormat: PROC [n: TiogaNode.Ref] RETURNS [TiogaNode.Name] = INLINE { RETURN[IF n=NIL THEN TiogaNode.nullName ELSE n.format]}; FindEntry: PROC [dictAtom: ATOM] RETURNS [BOOLEAN] = { dict: Entry _ GetDict[dictAtom]; IF dict#NIL THEN entry _ Lookup[dict,hash,keyRope,keyStart,kLen,rdr]; RETURN [entry # NIL] }; rdr: RopeReader.Ref; dictAtom: ATOM = GetDictAtom[dict]; keyRope: ROPE _ keyNode.rope; kLen: NAT; kStart: Offset; hash: CARDINAL; entry: Entry; foundIt _ keyDeterminesDict _ FALSE; resultLen _ 0; rdr _ RopeReader.GetRopeReader[]; keyEnd _ MAX[0,MIN[keyEnd,RopeEdit.Size[keyRope]]]; kStart _ keyStart _ FindKeyStart[keyRope,keyEnd,rdr]; kLen _ keyLen _ keyEnd-keyStart; hash _ KeyHash[keyRope,keyStart,keyEnd,rdr]; RopeReader.SetPosition[rdr,keyRope,keyStart]; IF keyStart > 0 AND RopeReader.Backwards[rdr]='. THEN { nameStart: Offset _ FindKeyStart[keyRope,keyStart-1,rdr]; IF nameStart < keyStart-1 THEN { dictName: ATOM _ Atom.MakeAtom[RopeEdit.Substr[keyRope,nameStart,keyStart-1-nameStart]]; [] _ FindEntry[dictName]; keyDeterminesDict _ TRUE; keyLen _ keyEnd - (keyStart _ nameStart) }}; IF entry = NIL THEN [] _ FindEntry[dictAtom]; IF entry = NIL THEN { RopeReader.FreeRopeReader[rdr]; RETURN }; { -- do it CheckCaps: PROC = INLINE { allcaps _ FALSE; RopeReader.SetPosition[rdr,keyRope,kStart]; initialcap _ RopeReader.Peek[rdr] IN ['A..'Z]; FOR i:Offset IN [0..kLen) DO IF RopeReader.Get[rdr] NOT IN ['A..'Z] THEN RETURN; ENDLOOP; allcaps _ TRUE }; node: RefTextNode = entry.node; root: RefBranchNode = TiogaNodeOps.Root[node]; keyRoot: RefBranchNode = TiogaNodeOps.Root[keyNode]; nodeRope: ROPE _ node.rope; looks: TiogaLooks.Looks _ TextEdit.FetchLooks[keyNode,kStart]; allcaps, initialcap: BOOLEAN _ FALSE; format: TiogaNode.Name; child: RefTextNode _ TiogaNodeOps.NarrowToTextNode[TiogaNodeOps.Contents[node]]; textLen: Offset _ RopeEdit.Size[nodeRope]; CheckCaps; RopeReader.FreeRopeReader[rdr]; [,resultLen] _ TextEdit.ReplaceText[ destRoot: keyRoot, sourceRoot: root, dest:keyNode, destStart:keyStart, destLen:keyLen, source:node, sourceStart:0, sourceLen:textLen, event:event]; IF resultLen # textLen THEN ERROR; IF looks # TiogaLooks.noLooks THEN TextEdit.AddLooks[keyRoot,keyNode,looks,keyStart,textLen,event]; IF allcaps THEN TextEdit.AllCaps[keyRoot,keyNode,keyStart,textLen,event] ELSE IF initialcap AND textLen > 0 THEN -- make first letter uppercase TextEdit.AllCaps[keyRoot,keyNode,keyStart,1,event]; SELECT format _ NodeFormat[node] FROM TiogaNode.nullName, NodeFormat[keyNode] => NULL; ENDCASE => TextEdit.ChangeFormat[keyNode,format,event,keyRoot]; IF child # NIL THEN { -- insert as children of keyNode new: TiogaNode.Span _ EditSpan.Copy[keyRoot,root,TiogaNodeOps.MakeNodeLoc[keyNode], TiogaNodeOps.MakeNodeSpan[child,TiogaNodeOps.LastWithin[node]], FALSE,after,1,event]; last: TiogaNode.RefTextNode _ TiogaNodeOps.NarrowToTextNode[new.end.node]; IF last # NIL AND keyStart+textLen < TextEdit.Size[keyNode] THEN -- move text after key to end of last new node [] _ TextEdit.MoveText[ destRoot: keyRoot, sourceRoot: keyRoot, dest: last, destLoc: TextEdit.MaxLen, source: keyNode, start: keyStart+textLen, len: TextEdit.MaxLen, event: event] }; foundIt _ TRUE; commands _ entry.commands; }}; KeyHash: PROC [keyRope: ROPE, keyStart, keyEnd: Offset, rdr: RopeReader.Ref] RETURNS [h: CARDINAL] = { len: NAT _ keyEnd-keyStart; RopeReader.SetPosition[rdr,keyRope,keyStart]; h _ 0; FOR i: NAT IN [1..MIN[3,len]) DO -- use the first 3 characters h _ Inline.BITXOR[Inline.BITSHIFT[h,2], RopeEdit.UpperCase[RopeReader.Get[rdr]]]; ENDLOOP; IF len >= 2 THEN { -- use the last 2 characters RopeReader.SetPosition[rdr,keyRope,keyEnd]; FOR i: NAT IN [len-2..len) DO h _ Inline.BITXOR[Inline.BITSHIFT[h,2], RopeEdit.UpperCase[RopeReader.Backwards[rdr]]]; ENDLOOP }}; Lookup: ENTRY PROC [dict: Entry, hash: CARDINAL, keyRope: ROPE, keyStart: Offset, keyLen: NAT, rdr1, rdr2, rdr3: RopeReader.Ref _ NIL] RETURNS [entry: Entry] = INLINE { ENABLE UNWIND => NULL; RETURN [LookupInternal[dict,hash,keyRope,keyStart,keyLen,rdr1,rdr2,rdr3]] }; LookupInternal: PROC [dict: Entry, hash: CARDINAL, keyRope: ROPE, keyStart: Offset, keyLen: NAT, rdr1, rdr2, rdr3: RopeReader.Ref _ NIL] RETURNS [entry: Entry] = { FreeReaders: PROC = INLINE { IF free1 THEN RopeReader.FreeRopeReader[rdr1]; IF free2 THEN RopeReader.FreeRopeReader[rdr2]; IF free3 THEN RopeReader.FreeRopeReader[rdr3] }; free1, free2, free3: BOOLEAN _ FALSE; pred: Entry _ NIL; IF keyLen=0 THEN RETURN [NIL]; IF rdr1=NIL THEN { free1 _ TRUE; rdr1 _ RopeReader.GetRopeReader[] }; IF rdr2=NIL THEN { free2 _ TRUE; rdr2 _ RopeReader.GetRopeReader[] }; IF rdr3=NIL THEN { free3 _ TRUE; rdr3 _ RopeReader.GetRopeReader[] }; RopeReader.SetPosition[rdr1, keyRope, keyStart]; -- leave this at the start of the key [] _ RopeReader.Peek[rdr1]; -- prime the reader for the key entry _ NIL; -- will stay nil if don't find key in dict FOR e: Entry _ dict, e.next UNTIL e=NIL DO IF e.hash = hash AND RopeEdit.Size[e.keyRope] = keyLen THEN { -- check the ropes rdr2^ _ rdr1^; IF RopeReader.CompareSubstrs[keyRope,e.keyRope, keyStart,keyLen,0,keyLen,rdr2,rdr3,FALSE] = equal THEN { IF pred # NIL THEN { -- move entry to front pred.next _ e.next; e.next _ dict.next; dict.next _ e }; entry _ e; EXIT }}; pred _ e; ENDLOOP; FreeReaders[] }; FindKeyLen: PROC [keyRope: ROPE, rdr: RopeReader.Ref] RETURNS [len: NAT] = { size: Offset _ RopeEdit.Size[keyRope]; RopeReader.SetPosition[rdr,keyRope,0]; IF RopeEdit.PunctuationChar[RopeReader.Peek[rdr]] THEN RETURN [1]; len _ 0; WHILE len0 AND RopeEdit.AlphaNumericChar[RopeReader.Backwards[rdr]] DO start _ start-1; ENDLOOP }; NoDictAtom: ATOM = $NoDictionaryAvailable; GetDict: PROC [dictName: ATOM] RETURNS [entry: Entry] = { prop: REF ANY; prop _ RefTab.Fetch[dictTable,dictName].val; WITH prop SELECT FROM x: Entry => RETURN [x]; x: ATOM => IF x = NoDictAtom THEN RETURN [NIL] ELSE ERROR; ENDCASE => { -- try to load it r: ROPE _ Atom.GetPName[dictName]; fileName: ROPE _ RopeEdit.Concat[r,".Abbreviations"]; [] _ RefTab.Store[dictTable, dictName, NoDictAtom]; [] _ Load[fileName, r ! CIFS.Error => CHECKED {CONTINUE}]; RETURN [GetDict[dictName]] }}; Start: PUBLIC PROC = { }; END. âAbbrevExpandImpl.mesa; written by Bill Paxton, May 1981 edited by McGregor, February 14, 1983 2:06 pm edited by Paxton, June 14, 1983 4:57 pm This package implements abbreviation expansion in Tioga ***** Declarations ***** Operations ***** clear the specified abbreviation dictionary force dictName lowercase before create the atom see if have '. before try to get the dictName from the key hash must be independent of case of chars ***** Initialization Ê é˜Jšœ7™7Jšœ-™-Jšœ'™'J˜Jšœ7™7J˜šÏk ˜ J˜ J˜Jšœ˜J˜ J˜Jšœ˜J˜J˜J˜J˜ J˜ J˜ J˜ J˜ J˜ —J˜šœ ˜JšœœœD˜lJšœ˜—Jš˜Jšœ˜J˜Jšœ™J˜J˜(J˜Jšœœœ ˜šœ œœ˜J˜ Jšœœ˜Jšœ œ˜J˜Jšœ œœœ˜J˜J˜—Jšœ™J˜šÏnœœ˜šœœ˜J˜(Jšœ œœ˜—Jšœ œ˜J˜Jšœœ˜#J˜J˜ Jšœ0Ïc˜HJ˜:J˜!šœ?œœ˜PJ˜5Jš œœœ œœœ˜'J˜!J˜Jšœ˜—J˜!J˜—šž œœœ˜Jšœ2œœ˜VJšœœœ˜J˜J˜ Jšœ œ ˜J˜Jšœœ˜J˜ Jšœœ˜ Jšœ œœ˜J˜Jš œ œœœœ˜J˜Jšœœœ/œ˜EJ˜!Jš œ œœ œ!œŸ˜\J˜,J˜>šœ œœŸ˜&Jšœœ ˜Jšœœœ.˜@Jšœ/˜3—J˜J˜9J˜J˜DJ˜J˜-Jšœ œ ˜/J˜J˜—šž œœ œ%˜GJš œœœœœœ ˜EJšœœ˜Jšœœ˜J˜!Jš œœ œœ œ˜YšœœŸ˜.Jšœœ œK˜\Jšœ œœ˜#Jšœœ ˜Jšœ ˜ J˜!Jš œœ œœ œ˜YJ˜—šœœŸ˜+J˜JšœœœŸ-˜]J˜J˜—Jšœ˜"Jšœœ#˜6J˜J˜—š žœœœœ œ˜-Jšœ+™+Jšœœœ˜Jšœ4œ˜;J˜—Jšœœœœ˜"J˜š ž œœ œœœ˜;Jšœ/™/š œœœœœœ˜.Jšœœ œ ˜=J˜ —Jšœœ˜ Jšœ;˜AJ˜J˜—šžœœ˜Jšœ-œœ˜Fšœ œœ&˜[Jš œ œœœœ˜J˜—šž œœœœ˜GJš œœœœœ ˜8J˜—š ž œœ œœœ˜6J˜ Jšœœœ5˜EJšœ œ˜J˜—J˜Jšœ œ˜#Jšœ œ˜Jšœœ˜ J˜Jšœœ˜J˜ Jšœœ˜$J˜J˜!Jšœ œœ!˜3J˜5J˜ J˜,Jšœ*™*J˜-šœœœ˜7JšŸ$™$J˜9šœœ˜ Jšœ œJ˜XJ˜Jšœœ˜J˜,——Jšœ œœ˜-J˜Jšœ œœ#œ˜?JšœŸ˜ ˜šž œœœ˜Jšœ œ˜J˜+Jšœ"œ ˜.šœ œ ˜Jš œœœ œœ˜3Jšœ˜—Jšœ œ˜J˜—J˜J˜.J˜4Jšœ œ ˜J˜>Jšœœœ˜%J˜J˜PJ˜*J˜ J˜˜$J˜$J˜1J˜<—Jšœœœ˜"šœ˜"J˜@—Jšœ œ9˜Hš œœ œ œŸ˜FJ˜3—šœ˜%Jšœ+œ˜0Jšœ8˜?—šœ œœŸ ˜6˜SJ˜?Jšœ˜—J˜Jšœœ˜Jšœ*œŸ.˜]˜J˜MJ˜P———Jšœ œ˜J˜J˜J˜——šžœ˜ Jšœ œ0˜>Jšœœ˜Jšœ)™)Jšœœ˜J˜-J˜š œœœœ œŸ˜>šœ œœ˜'J˜)—Jšœ˜—šœ œŸ˜/J˜+šœœœ˜šœ œœ˜'J˜/—Jšœ˜ J˜———šžœœ˜šœœ œœ˜KJšœ#œ˜'—Jšœœ˜!Jšœœœ˜JšœF˜LJ˜—šžœ˜šœœ œœ˜KJšœ#œ˜'—Jšœ˜šž œœœ˜Jšœœ!˜.Jšœœ!˜.Jšœœ#˜0—Jšœœœ˜%Jšœœ˜Jšœ œœœ˜Jšœœœ œ&˜EJšœœœ œ&˜EJšœœœ œ&˜EJšœ1Ÿ%˜VJšœŸ˜;JšœœŸ*˜7šœœœ˜*šœœ#œŸ˜PJ˜šœ-˜/šœ#œ œ˜8šœœœŸ˜+J˜J˜J˜—Jšœ œ˜———J˜ Jšœ˜—J˜J˜—š ž œœ œœœ˜LJ˜&J˜&Jšœ0œœ˜BJ˜šœ œ0˜DJšœ œ˜J˜——šž œœ œ&˜GJšœ˜J˜+Jšœ9œœ ˜RJ˜šœ œ6˜IJšœœ˜J˜——Jšœ œ˜*J˜šžœœ œœ˜9Jšœœœ˜J˜,šœœ˜Jšœ œ˜Jšœœœœœœœœ˜:šœŸ˜Jšœœ˜"Jšœ œ'˜5J˜3Jšœœ œœ˜:Jšœ˜J˜———Jšœ™J˜šžœœœ˜J˜J˜—Jšœ˜J˜—…—(¶6