DIRECTORY Atom, CharOps, IO, NodeProps, PFS, PFSNames, RefText, Rope, Rosary, TextEdit, TextNode, Tioga, TiogaFileFormat, TiogaFileIO, TiogaIO, TiogaIOExtras; TiogaIOImpl: CEDAR PROGRAM IMPORTS Atom, CharOps, IO, NodeProps, PFS, PFSNames, RefText, Rope, Rosary, TextEdit, TextNode, TiogaFileIO EXPORTS TiogaIO, TiogaIOExtras ~ BEGIN STREAM: TYPE ~ IO.STREAM; ROPE: TYPE ~ Rope.ROPE; ROSARY: TYPE ~ Rosary.ROSARY; Node: TYPE ~ Tioga.Node; Looks: TYPE ~ Tioga.Looks; noLooks: Looks ~ Tioga.noLooks; Look: TYPE ~ Tioga.Look; GetByte: PROC [s: STREAM] RETURNS [BYTE] ~ INLINE { RETURN[IO.GetByte[s]] }; PutByte: PROC [s: STREAM, byte: BYTE] ~ INLINE { IO.PutByte[s, byte] }; GetChar: PROC [s: STREAM] RETURNS [CHAR] ~ INLINE { RETURN[IO.GetChar[s]] }; PutChar: PROC [s: STREAM, char: CHAR] ~ INLINE { IO.PutChar[s, char] }; Op: TYPE ~ TiogaFileFormat.Op; GetOp: PROC [s: STREAM] RETURNS [Op] ~ INLINE { RETURN[VAL[GetByte[s]]] }; PutOp: PROC [s: STREAM, op: Op] ~ INLINE { PutByte[s, ORD[op]] }; IndexFromOp: PROC [first: Op, op: Op] RETURNS [BYTE] ~ INLINE { RETURN[ORD[op]-ORD[first]] }; OpFromIndex: PROC [first: Op, index: BYTE] RETURNS [Op] ~ INLINE { RETURN[VAL[ORD[first]+index]] }; GetLen: PROC [s: STREAM] RETURNS [CARD] ~ { b: BYTE ~ GetByte[s]; RETURN[IF b<(2**7) THEN b ELSE GetLen[s]*(2**7)+(b MOD (2**7))]; }; PutLen: PROC [s: STREAM, len: CARD] ~ { IF len<(2**7) THEN PutByte[s, len] ELSE { PutByte[s, (2**7)+(len MOD (2**7))]; PutLen[s, len/(2**7)] }; }; GetLenRope: PROC [s: STREAM] RETURNS [ROPE] ~ { len: CARD ~ GetLen[s]; RETURN[IO.GetRope[s, len, TRUE]]; }; SkipLenRope: PROC [s: STREAM] ~ { len: CARD ~ GetLen[s]; IO.SetIndex[s, IO.GetIndex[s]+len]; }; PutLenRope: PROC [s: STREAM, rope: ROPE] ~ { PutLen[s, Rope.Size[rope]]; IO.PutRope[s, rope]; }; GetLenText: PROC [s: STREAM, buffer: REF TEXT ¬ NIL] RETURNS [REF TEXT] ~ { len: CARD ~ GetLen[s]; RETURN[IO.GetText[s, len]]; }; GetLenAtom: PROC [s: STREAM, buffer: REF TEXT ¬ NIL] RETURNS [ATOM] ~ { RETURN[Atom.MakeAtomFromRefText[GetLenText[s, buffer]]]; }; PutLenAtom: PROC [s: STREAM, atom: ATOM] ~ { PutLenRope[s, Atom.GetPName[atom]]; }; Get16: PROC [s: STREAM] RETURNS [CARD16] ~ { b0: BYTE ~ GetByte[s]; b1: BYTE ~ GetByte[s]; RETURN[b0*(2**8)+b1]; }; Put16: PROC [s: STREAM, val: CARD16] ~ { b0: BYTE ~ val / (2**8); b1: BYTE ~ val MOD (2**8); PutByte[s, b0]; PutByte[s, b1]; }; Get32: PROC [s: STREAM] RETURNS [CARD32] ~ { h0: CARD16 ~ Get16[s]; h1: CARD16 ~ Get16[s]; RETURN[h0*(2**16)+h1]; }; Put32: PROC [s: STREAM, val: CARD32] ~ { h0: CARD16 ~ val / (2**16); h1: CARD16 ~ val MOD (2**16); Put16[s, h0]; Put16[s, h1]; }; GetLooks: PROC [s: STREAM] RETURNS [Looks] ~ INLINE { RETURN[LOOPHOLE[Get32[s]]] }; PutLooks: PROC [s: STREAM, looks: Looks] ~ INLINE { Put32[s, LOOPHOLE[looks]] }; GetLookChars: PROC [s: STREAM, n: NAT] RETURNS [looks: Looks ¬ noLooks] ~ { THROUGH [0..n) DO c: Look ~ GetChar[s]; looks[c] ¬ TRUE ENDLOOP; }; PutLookChars: PROC [s: STREAM, looks: Looks] ~ { FOR c: Look IN Look DO IF looks[c] THEN PutChar[s, c] ENDLOOP; }; CountLooks: PROC [looks: Looks] RETURNS [n: NAT ¬ 0] ~ { FOR c: Look IN Look DO IF looks[c] THEN n ¬ n+1 ENDLOOP; }; Error: PUBLIC ERROR ~ CODE; numFormats: NAT ~ TiogaFileFormat.numFormats; numProps: NAT ~ TiogaFileFormat.numProps; numLooks: NAT ~ TiogaFileFormat.numLooks; PreloadTables: PROC [ reserveFormat: PROC [ATOM, BYTE], reserveProp: PROC [ATOM, BYTE], reserveLooks: PROC [Looks, BYTE] ] ~ { reserveFormat[NIL, 0]; reserveProp[NIL, 0]; reserveProp[$Prefix, 1]; reserveProp[$Postfix, 2]; reserveLooks[noLooks, 0]; }; GetDocRope: PUBLIC PROC [s1, s2, s3: STREAM] RETURNS [rope: ROPE ¬ NIL] ~ { SkipRuns: PROC ~ { numRuns: INT ~ GetLen[s3]; THROUGH [0..numRuns) DO looksOp: Op ~ GetOp[s3]; SELECT looksOp FROM IN [looksFirst..looksLast] => NULL; look1 => [] ¬ GetLookChars[s3, 1]; look2 => [] ¬ GetLookChars[s3, 2]; look3 => [] ¬ GetLookChars[s3, 3]; looks => [] ¬ GetLooks[s3]; ENDCASE => ERROR Error; [] ¬ GetLen[s3]; ENDLOOP; }; newlineChars: NAT ¬ 1; ReadRope: PROC [comment: BOOL] ~ { size: INT ~ GetLen[s3]; s: STREAM ~ IF comment THEN s2 ELSE s1; rope ¬ Rope.Concat[rope, IO.GetRope[s, size+newlineChars, TRUE]]; }; DO op: Op ~ GetOp[s3]; SELECT op FROM startNode, startLeaf => SkipLenRope[s3]; IN [startNodeFirst..startNodeLast] => NULL; IN [startLeafFirst..startLeafLast] => NULL; prop => { SkipLenRope[s3]; SkipLenRope[s3] }; propShort => { [] ¬ GetByte[s3]; SkipLenRope[s3] }; runs => SkipRuns[]; dataRope => ReadRope[comment: FALSE]; commentRope => ReadRope[comment: TRUE]; endNode => NULL; endOfFile => EXIT; ENDCASE => ERROR Error; ENDLOOP; }; GetDoc: PUBLIC PROC [s1, s2, s3: STREAM] RETURNS [root: Node] ~ { tableF: ARRAY [0..numFormats) OF ATOM; tableP: ARRAY [0..numProps) OF ATOM; tableL: ARRAY [0..numLooks) OF Looks; countF, countP, countL: NAT ¬ 0; StoreFormat: PROC [format: ATOM] RETURNS [index: BYTE ¬ BYTE.LAST] ~ { IF countF node.charSets ¬ NARROW[value]; $CharProps => node.charProps ¬ NARROW[value]; ENDCASE => NodeProps.PutProp[node, name, value]; }; ReadLooks: PROC RETURNS [Looks] ~ { looksOp: Op ~ GetOp[s3]; IF looksOp IN [looksFirst..looksLast] THEN { index: BYTE ~ IndexFromOp[looksFirst, looksOp]; RETURN[FetchLooks[index]]; } ELSE { looks: Looks ~ SELECT looksOp FROM look1 => GetLookChars[s3, 1], look2 => GetLookChars[s3, 2], look3 => GetLookChars[s3, 3], looks => GetLooks[s3], ENDCASE => ERROR Error; index: BYTE ~ StoreLooks[looks]; RETURN[looks]; }; }; ReadRuns: PROC ~ { p: PROC [q: PROC [item: REF, repeat: INT]] ~ { numRuns: INT ~ GetLen[s3]; THROUGH [0..numRuns) DO looks: Looks ~ ReadLooks[]; repeat: INT ~ GetLen[s3]; q[TextEdit.ItemFromLooks[looks], repeat]; ENDLOOP; }; node.runs ¬ Rosary.FromRuns[p]; }; CheckRosary: PROC [rosary: ROSARY, size: INT] ~ { IF NOT (rosary=NIL OR Rosary.Size[rosary]=size) THEN ERROR Error; }; newlineChars: NAT ¬ 1; ReadRope: PROC [comment: BOOL] ~ { size: INT ~ GetLen[s3]; s: STREAM ~ IF comment THEN s2 ELSE s1; node.comment ¬ comment; node.rope ¬ IF size>0 THEN IO.GetRope[s, size, TRUE] ELSE NIL; THROUGH [0..newlineChars) DO [] ¬ GetChar[s] ENDLOOP; -- discard newline sequence CheckRosary[node.runs, size]; -- can check these now because the rope comes last CheckRosary[node.charSets, size]; CheckRosary[node.charProps, size]; }; buffer: REF TEXT ~ RefText.ObtainScratch[100]; PreloadTables[ReserveFormat, ReserveProp, ReserveLooks]; DO op: Op ~ GetOp[s3]; SELECT op FROM startNode, startLeaf => { format: ATOM ~ GetLenAtom[s3, buffer]; index: BYTE ~ StoreFormat[format]; StartNode[leaf: (op=startLeaf), format: format]; }; IN [startNodeFirst..startNodeLast] => { index: BYTE ~ IndexFromOp[startNodeFirst, op]; format: ATOM ~ FetchFormat[index]; StartNode[leaf: FALSE, format: format]; }; IN [startLeafFirst..startLeafLast] => { index: BYTE ~ IndexFromOp[startLeafFirst, op]; format: ATOM ~ FetchFormat[index]; StartNode[leaf: TRUE, format: format]; }; prop => { name: ATOM ~ GetLenAtom[s3, buffer]; index: BYTE ~ StoreProp[name]; ReadProp[name]; }; propShort => { index: BYTE ~ GetByte[s3]; name: ATOM ~ FetchProp[index]; ReadProp[name]; }; runs => ReadRuns[]; dataRope => ReadRope[comment: FALSE]; commentRope => ReadRope[comment: TRUE]; endNode => { prev ¬ parent; parent ¬ prev.parent }; endOfFile => EXIT; ENDCASE => ERROR Error; ENDLOOP; RefText.ReleaseScratch[buffer]; IF NOT parent=NIL AND prev#NIL THEN ERROR Error; RETURN[IF prev#NIL THEN prev ELSE node]; }; emptyAtom: ATOM ~ Atom.MakeAtom[NIL]; PutDoc: PUBLIC PROC [s1, s2, s3: STREAM, root: Node] ~ { tableF: ARRAY [0..numFormats) OF ATOM; tableP: ARRAY [0..numProps) OF ATOM; tableL: ARRAY [0..numLooks) OF Looks; countF, countP, countL: NAT ¬ 0; FindFormat: PROC [format: ATOM] RETURNS [found: BOOL ¬ FALSE, index: BYTE ¬ 0] ~ { IF format=emptyAtom THEN format ¬ NIL; -- important for compatibility! FOR i: BYTE IN [0..countF) DO IF tableF[i]=format THEN RETURN[TRUE, i] ENDLOOP; IF countF { PutOp[s3, look1]; PutLookChars[s3, looks] }; 2 => { PutOp[s3, look2]; PutLookChars[s3, looks] }; 3 => { PutOp[s3, look3]; PutLookChars[s3, looks] }; ENDCASE => { PutOp[s3, looks]; PutLooks[s3, looks] }; PutLen[s3, repeat]; runsSize ¬ runsSize+repeat; }; [] ¬ Rosary.MapRuns[[node.runs], countRuns]; PutOp[s3, runs]; PutLen[s3, numRuns]; [] ¬ Rosary.MapRuns[[node.runs], writeRuns]; IF runsSize#ropeSize THEN ERROR; }; { -- write the rope s: STREAM ~ IF node.comment THEN s2 ELSE s1; PutOp[s3, IF node.comment THEN commentRope ELSE dataRope]; PutLen[s3, ropeSize]; IO.PutRope[s, node.rope]; IO.PutRope[s, newline]; }; { -- move to the next node IF NOT leaf THEN node ¬ node.child -- descend in the tree ELSE DO -- move to sibling or up* then sibling IF node=root THEN GOTO Finis; IF node.next#NIL THEN { node ¬ node.next; EXIT }; -- sibling node ¬ node.parent; -- parent PutOp[s3, endNode]; ENDLOOP; }; REPEAT Finis => PutOp[s3, endOfFile]; ENDLOOP; }; InterestingProp: PROC [name: ATOM, value: REF] RETURNS [BOOL] ~ { RETURN [SELECT name FROM $Viewer, $LockedViewer, $FromTiogaFile, $DocumentLock, $FileCreateDate, $FileExtension, $NewlineDelimiter => FALSE, ENDCASE => TRUE]; }; SimpleNode: PROC [node: Node, comment: BOOL] RETURNS [BOOL] ~ { RETURN[node.runs=NIL AND node.charSets=NIL AND node.charProps=NIL AND (node.format=NIL OR node.format=emptyAtom) AND node.comment=comment AND NOT NodeProps.MapProps[node, InterestingProp, FALSE, FALSE]]; }; RopeFromSimpleDoc: PUBLIC PROC [root: Node] RETURNS [ROPE] ~ { IF root#NIL AND root.rope=NIL AND SimpleNode[root, TRUE] THEN { child: Node ~ root.child; IF child#NIL AND child.child=NIL AND child.next=NIL AND SimpleNode[child, FALSE] THEN RETURN[IF child.rope=NIL THEN "" ELSE child.rope]; }; RETURN [NIL]; }; SimpleDocFromRope: PUBLIC PROC [rope: ROPE] RETURNS [Node] ~ { RETURN [TextEdit.DocFromNode[TextEdit.FromRope[rope]]]; }; LowerCase: PROC [r: ROPE] RETURNS [ROPE] ~ { RETURN [Rope.Translate[base: r, translator: Rope.Lower]]; }; FileExtensionFromPath: PROC [path: PFS.PATH] RETURNS [ATOM] ~ { name: ROPE ~ PFSNames.ShortNameRope[path]; pos: INT ~ Rope.FindBackward[name, "."]; ext: ROPE ~ IF pos<0 THEN NIL ELSE Rope.Substr[name, pos+1]; RETURN[IF Rope.IsEmpty[ext] THEN $null ELSE Atom.MakeAtom[LowerCase[ext]]]; }; FileCreateDateFromUniqueID: PROC [uniqueID: PFS.UniqueID] RETURNS [REF] ~ { RETURN[NEW[PFS.UniqueID ¬ uniqueID]]; }; PutFileProps: PROC [root: Node, fullFName: PFS.PATH, uniqueID: PFS.UniqueID] ~ { NodeProps.PutProp[root, $FileExtension, FileExtensionFromPath[fullFName]]; NodeProps.PutProp[root, $FileCreateDate, FileCreateDateFromUniqueID[uniqueID]]; }; FromRope: PUBLIC PROC [rope: ROPE] RETURNS [Node] ~ { parts: TiogaFileIO.Parts ~ TiogaFileIO.GetParts[IO.RIS[rope]]; IF parts.isTioga THEN RETURN[GetDoc[ s1: IO.RIS[Rope.Substr[rope, parts.start1, parts.len1]], s2: IO.RIS[Rope.Substr[rope, parts.start2, parts.len2]], s3: IO.RIS[Rope.Substr[rope, parts.start3, parts.len3]] ]] ELSE RETURN[SimpleDocFromRope[rope]]; }; ToStream: PUBLIC PROC [s: STREAM, root: Node] RETURNS [dataLen: INT] ~ { rope: ROPE ~ RopeFromSimpleDoc[root]; IF rope=NIL THEN { put: PROC [s1, s2, s3: STREAM] ~ { PutDoc[s1, s2, s3, root] }; dataLen ¬ TiogaFileIO.PutParts[s, put]; } ELSE { IO.PutRope[s, rope]; dataLen ¬ Rope.Size[rope]; }; }; ToRope: PUBLIC PROC [root: Node] RETURNS [ROPE] ~ { rope: ROPE ~ RopeFromSimpleDoc[root]; IF rope=NIL THEN { s: STREAM ~ IO.ROS[]; dataLen: INT ~ ToStream[s, root]; RETURN[IO.RopeFromROS[s]]; } ELSE RETURN[rope]; }; FromPair: PUBLIC PROC [pair: TiogaIO.Pair] RETURNS [Node] ~ { IF Rope.Size[pair.formatting]>0 THEN RETURN[FromRope[Rope.Concat[pair.contents, pair.formatting]]] ELSE RETURN[SimpleDocFromRope[pair.contents]]; }; ToPair: PUBLIC PROC [root: Node] RETURNS [TiogaIO.Pair] ~ { rope: ROPE ~ RopeFromSimpleDoc[root]; IF rope=NIL THEN { s: STREAM ~ IO.ROS[]; dataLen: INT ~ ToStream[s, root]; rope: ROPE ~ IO.RopeFromROS[s]; RETURN[[ contents: Rope.Substr[base: rope, len: dataLen], formatting: Rope.Substr[base: rope, start: dataLen] ]]; } ELSE RETURN[[contents: rope, formatting: NIL]]; }; checkMutabilityInFromFile: BOOL ¬ TRUE; FromFile: PUBLIC PROC [fileName: PFS.PATH, wantedUniqueID: PFS.UniqueID] RETURNS [fullFName: PFS.PATH, uniqueID: PFS.UniqueID, root: Node] ~ { rope: ROPE ¬ NIL; [rope: rope, fullFName: fullFName, uniqueID: uniqueID] ¬ PFS.RopeOpen[ fileName: fileName, wantedUniqueID: wantedUniqueID, includeFormatting: TRUE, checkMutability: checkMutabilityInFromFile]; root ¬ FromRope[rope]; PutFileProps[root, fullFName, uniqueID]; }; ToFile: PUBLIC PROC [fileName: PFS.PATH, root: Node] RETURNS [fullFName: PFS.PATH, uniqueID: PFS.UniqueID, dataLen: INT] ~ { file: PFS.OpenFile ~ PFS.Open[name: fileName, access: create]; RETURN ToOpenFile[file, root]; }; FromOpenFile: PUBLIC PROC [file: PFS.OpenFile] RETURNS [fullFName: PFS.PATH, uniqueID: PFS.UniqueID, root: Node] ~ { [fullFName: fullFName, uniqueID: uniqueID] ¬ PFS.GetInfo[file]; PFS.Close[file]; RETURN FromFile[fullFName, uniqueID]; }; ToOpenFile: PUBLIC PROC [file: PFS.OpenFile, root: Node] RETURNS [fullFName: PFS.PATH, uniqueID: PFS.UniqueID, dataLen: INT] ~ { s: STREAM ~ PFS.StreamFromOpenFile[openFile: file, accessOptions: write]; [fullFName: fullFName, uniqueID: uniqueID] ¬ PFS.GetInfo[file]; dataLen ¬ ToStream[s, root]; IO.Close[s]; PutFileProps[root, fullFName, uniqueID]; }; IsAlreadyACommentLine: PROC [r: ROPE] RETURNS [BOOL] = { loc: INT ¬ 0; size: INT = Rope.Size[r]; c: CHAR; WHILE loc < size AND CharOps.Blank[c ¬ Rope.Fetch[r, loc]] DO loc ¬ loc+1; ENDLOOP; IF loc > size-2 OR c # '- OR Rope.Fetch[r, loc+1] # '- THEN RETURN [FALSE]; IF Rope.SkipTo[s: r, skip: "\r\l"] < size THEN { RETURN [FALSE]; }; IF Rope.Match[pattern: "--*--*", object: r] THEN { RETURN [FALSE]; }; RETURN [TRUE] }; MapDelimitedPieces: PROC [action: PROC [rope: ROPE, start, len: INT], delimiter: ROPE, base: ROPE, start: INT ¬ 0, len: INT ¬ INT.LAST] = { t: INT ¬ start; dSize: INT = Rope.Size[delimiter]; end: INT = MIN[start+len, Rope.Size[base]]; DO i: INT ¬ Rope.Index[s1: base, pos1: t, s2: delimiter]; IF i > end-dSize THEN {i ¬ end}; IF i >= t THEN action[base, t, i-t]; IF i = end THEN EXIT; t ¬ i+dSize; ENDLOOP; }; WritePlain: PUBLIC PROC [s: IO.STREAM, root: Node, restoreDashes: BOOL ¬ FALSE, indent: ROPE ¬ NIL] ~ { node: Node ¬ root; level: INTEGER ¬ 0; levelDelta: INTEGER; BeginLine: PROC = { THROUGH [1..level) DO IO.PutRope[s, indent] ENDLOOP; -- output level-1 tabs }; EndLine: PROC = { IO.PutChar[s, '\n]; }; IF indent=NIL THEN indent ¬ "\t"; DO [node, levelDelta] ¬ TextNode.Forward[node]; IF node=NIL THEN EXIT; level ¬ level+levelDelta; IF restoreDashes AND node.comment AND NOT IsAlreadyACommentLine[node.rope] THEN { EachLine: PROC [rope: ROPE, start, len: INT] = { first: BOOL ¬ TRUE; EachPart: PROC [rope: ROPE, start, len: INT] = { IF NOT first THEN IO.PutRope[s, " - - "]; IO.PutRope[self: s, r: rope, start: start, len: len]; first ¬ FALSE; }; BeginLine[]; IO.PutRope[s, "-- "]; -- restore the leading dashes for Mesa comments MapDelimitedPieces[EachPart, "--", rope, start, len]; EndLine[]; }; MapDelimitedPieces[EachLine, "\n", node.rope, 0, Rope.Size[node.rope]]; } ELSE { BeginLine[]; IO.PutRope[s, node.rope]; EndLine[] }; ENDLOOP; }; WritePlainToStream: PUBLIC PROC [s: IO.STREAM, root: Node, restoreDashes: BOOL] = { WritePlain[s, root, restoreDashes]; }; WritePlainToRope: PUBLIC PROC [root: Node, restoreDashes: BOOL] RETURNS [ROPE] ~ { rope: ROPE ~ RopeFromSimpleDoc[root]; IF rope=NIL THEN { s: STREAM ~ IO.ROS[]; WritePlain[s, root, restoreDashes]; RETURN[IO.RopeFromROS[s]]; } ELSE RETURN[rope]; }; END.  TiogaIOImpl.mesa Copyright Σ 1985, 1986, 1987, 1988, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. written by Paxton. March 1981 Paxton. August 24, 1982 10:39 am Last Edited by: Maxwell, January 5, 1983 1:07 pm Russ Atkinson, July 26, 1983 5:41 pm Last Edited by: Birrell, August 23, 1983 1:29 pm Bier, January 10, 1989 12:03:31 pm PST Plass, September 24, 1991 2:11 pm PDT Willie-s, February 15, 1991 3:17 pm PST Doug Wyatt, June 7, 1993 1:45 pm PDT Utilities Get/Put parts The following Find* operations just do a dumb linear search; this is much simpler than the old PGSupport, it uses only local storage, and the tables are never very large. -- DKW Simple documents When you add a new "system" property that should not go on files, add registration at end of TEditDocuments2Impl to skip copy/write. Get/Put file WritePlain comment has a CR or LF in it, so be careful comment has some other double dashes in it, so be careful TiogaSimpleText GetNewlineDelimiterChar: PUBLIC PROC [root: Node] RETURNS [CHAR] ~ { IF root # NIL THEN WITH NodeProps.GetProp[root, $NewlineDelimiter] SELECT FROM rope: ROPE => IF Rope.Size[rope] = 1 THEN RETURN [Rope.Fetch[rope, 0]]; ENDCASE => NULL; RETURN ['\r]; }; GetNewlineDelimiterRope: PUBLIC PROC [root: Node] RETURNS [ROPE] ~ { IF root # NIL THEN WITH NodeProps.GetProp[root, $NewlineDelimiter] SELECT FROM rope: ROPE => RETURN [rope]; ENDCASE => NULL; RETURN ["\r"]; }; SimpleText: PUBLIC PROC [root: Node] RETURNS [ROPE] ~ { RETURN [RopeFromSimpleDoc[root]]; }; IsThisStreamATiogaFile: PUBLIC PROC [stream: STREAM] RETURNS [yes: BOOL, len: INT] ~ { parts: TiogaFileIO.Parts ~ TiogaFileIO.GetParts[stream]; RETURN[yes: parts.isTioga, len: parts.len1]; }; GetTextContents: PUBLIC PROC [root: Node, start: INT ¬ 0, length: INT ¬ INT.LAST] RETURNS [ROPE] ~ { simple: ROPE ~ RopeFromSimpleDoc[root]; IF simple # NIL THEN { RETURN [Rope.Substr[simple, start, length]] } ELSE { loc: INT ¬ 0; -- offset of rope into document len: INT ¬ 0; -- same as Rope.Size[rope] rope: ROPE ¬ NIL; node: Node ¬ root; level: INT ¬ 0; nl: ROPE ~ GetNewlineDelimiterRope[root]; DO levelDelta: INTEGER; IF NOT node.comment THEN { nodeSize: INT ¬ Rope.Size[node.rope]; IF rope = NIL AND loc + nodeSize + 1 <= start THEN { loc ¬ loc + nodeSize + 1; } ELSE { rope ¬ Rope.Concat[rope, Rope.Concat[node.rope, nl]]; len ¬ len + nodeSize; }; }; [node, levelDelta] ¬ TextNode.Forward[node]; level ¬ level + levelDelta; IF level = 0 OR loc+len-start >= length THEN EXIT; ENDLOOP; RETURN [Rope.Substr[rope, start-loc, length]] }; }; Κ!–(cedarcode) style•NewlineDelimiter ™codešœ™Kšœ ΟeœU™`KšΟy™Kšž ™ Kšž0™0K™$Kšž0™0K™&K™%K™'K™$—K˜šΟk ˜ Kšœ˜Kšœ˜KšŸœ˜Kšœ ˜ KšŸœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ K˜K˜K˜—KšΟn œŸœŸ˜KšŸœŸœ ŸœB˜kKšŸœ˜šœŸ˜K˜KšŸœŸœŸœŸœ˜KšŸœŸœŸœ˜KšŸœŸœ Ÿœ˜KšœŸœ˜KšœŸœ˜Kšœ˜KšœŸœ˜—headšœ ™ š œŸœŸœŸœŸœŸœŸœŸœ˜LK˜—š  œŸœŸœŸœŸœŸœ˜GK˜—š œŸœŸœŸœŸœŸœŸœŸœ˜LK˜—š  œŸœŸœŸœŸœŸœ˜GK˜—šœŸœ˜K˜—š œŸœŸœŸœŸœŸœŸœ˜JK˜—š  œŸœŸœ ŸœŸœ˜AK˜—š   œŸœŸœŸœŸœ˜?KšŸœŸœŸœ˜Kšœ˜K˜—š   œŸœŸœŸœŸœ˜BKšŸœŸœŸœ˜Kšœ˜K˜—š  œŸœŸœŸœŸœ˜+KšœŸœ˜Kš ŸœŸœ ŸœŸœŸœ ˜@K˜K˜—š œŸœŸœŸœ˜'KšŸœ Ÿœ˜"KšŸœŸœ#˜DK˜K˜—š   œŸœŸœŸœŸœ˜/KšœŸœ ˜KšŸœŸœŸœ˜!K˜K˜—š  œŸœŸœ˜!KšœŸœ ˜KšŸœ Ÿœ˜#K˜K˜—š  œŸœŸœŸœ˜,K˜KšŸœ˜K˜K˜—š  œŸœŸœ ŸœŸœŸœŸœŸœŸœ˜KKšœŸœ ˜KšŸœŸœ˜K˜K˜—š  œŸœŸœ ŸœŸœŸœŸœŸœ˜GKšŸœ2˜8K˜K˜—š  œŸœŸœŸœ˜,Kšœ#˜#K˜K˜—š  œŸœŸœŸœŸœ˜,KšœŸœ˜KšœŸœ˜KšŸœ˜K˜K˜—š œŸœŸœŸœ˜(KšœŸœ˜KšœŸœŸœ˜Kšœ˜Kšœ˜K˜K˜—š  œŸœŸœŸœŸœ˜,KšœŸœ ˜KšœŸœ ˜KšŸœ˜K˜K˜—š œŸœŸœŸœ˜(KšœŸœ˜KšœŸœŸœ ˜Kšœ ˜ Kšœ ˜ K˜K˜—š œŸœŸœŸœ ŸœŸœŸœ˜SK˜—š  œŸœŸœŸœ Ÿœ ˜PK˜—š   œŸœŸœŸœŸœ˜KKšŸœŸœ"ŸœŸœ˜@K˜K˜—š  œŸœŸœ˜0Kš Ÿœ ŸœŸœŸœ ŸœŸœ˜>K˜K˜—š  œŸœŸœŸœ ˜8Kš Ÿœ ŸœŸœŸœ Ÿœ Ÿœ˜8K˜K˜——™ š œŸœŸœŸœ˜K˜—Kšœ Ÿœ˜-Kšœ Ÿœ˜)šœ Ÿœ˜)K˜—š  œŸœŸœŸœŸœŸœŸœŸœŸœ Ÿœ˜~KšœŸœ˜Kšœ Ÿœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—š  œŸœŸœŸœŸœŸœŸœ˜Kš œŸœ˜Kšœ Ÿœ˜šŸœŸ˜K˜šŸœ Ÿ˜KšŸœŸœ˜#Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ˜KšŸœŸœ˜—Kšœ˜KšŸœ˜—K˜—KšœŸœ˜š œŸœ Ÿœ˜"KšœŸœ˜Kš œŸœŸœ ŸœŸœ˜'KšœŸœŸœ˜AK˜—šŸœ˜šŸœŸ˜Kšœ(˜(KšŸœ$Ÿœ˜+KšŸœ$Ÿœ˜+Kšœ-˜-Kšœ3˜3Kšœ˜KšœŸœ˜%Kšœ!Ÿœ˜'Kšœ Ÿœ˜Kšœ Ÿœ˜KšŸœŸœ˜—KšŸœ˜—K˜K˜—š  œŸœŸœŸœŸœ˜AKšœŸœŸœŸœ˜&KšœŸœŸœŸœ˜$KšœŸœŸœ˜%KšœŸœ˜ š  œŸœ ŸœŸœ ŸœŸœŸœ˜FKšŸœŸœ8˜QK˜—š  œŸœŸœŸœ ŸœŸœŸœ˜BKšŸœŸœ6˜MK˜—š   œŸœŸœ ŸœŸœŸœ˜EKšŸœŸœ7˜NK˜—š   œŸœ ŸœŸœŸœ˜2Kš ŸœŸœŸœŸœŸœ˜=K˜—š   œŸœ ŸœŸœŸœ˜0Kš ŸœŸœŸœŸœŸœ˜=K˜—š  œŸœ ŸœŸœ ˜2Kš ŸœŸœŸœŸœŸœ˜=K˜—š  œŸœ Ÿœ Ÿœ˜3KšŸœŸœŸœ˜(Kšœ˜—š  œŸœŸœ Ÿœ˜/KšŸœŸœŸœ˜$Kšœ˜—š  œŸœŸœ˜2KšŸœŸœŸœ˜&Kšœ˜—KšœŸœ˜š  œŸœŸœ Ÿœ˜.KšœŸœ3˜=KšŸœŸœŸœŸœŸœŸœŸœ˜NKšŸœŸœ ŸœŸœ˜KšŸœŸœŸœΟc˜QKšœ‘2˜PKšœ!˜!Kšœ"˜"K˜—KšœŸœŸœ˜.Kšœ8˜8šŸœ˜šŸœŸ˜šœ˜KšœŸœ˜&KšœŸœ˜"Kšœ0˜0K˜—šŸœ%˜'KšœŸœ#˜.KšœŸœ˜"KšœŸœ˜'K˜—šŸœ%˜'KšœŸœ#˜.KšœŸœ˜"KšœŸœ˜&K˜—šœ ˜ KšœŸœ˜$KšœŸœ˜Kšœ˜K˜—šœ˜KšœŸœ˜KšœŸœ˜Kšœ˜K˜—Kšœ˜KšœŸœ˜%Kšœ!Ÿœ˜'Kšœ3˜3Kšœ Ÿœ˜KšŸœŸœ˜—KšŸœ˜—K˜KšŸœŸœŸœŸœŸœŸœŸœ˜0Kš ŸœŸœŸœŸœŸœ˜(K˜K˜—šœ ŸœŸœ˜%K˜—š œŸœŸœŸœ˜8KšœŸœŸœŸœ˜&KšœŸœŸœŸœ˜$KšœŸœŸœ˜%KšœŸœ˜ K™±š  œŸœ ŸœŸœ ŸœŸœ Ÿœ ˜RKšŸœŸœ Ÿœ‘˜FKšŸœŸœŸœ ŸœŸœŸœŸœŸœŸœ˜OKšŸœŸœ8˜QK˜—š œŸœŸœŸœ ŸœŸœ Ÿœ ˜NKšŸœŸœŸœ ŸœŸœŸœŸœŸœŸœ˜MKšŸœŸœ6˜MK˜—š   œŸœŸœ ŸœŸœ Ÿœ ˜QKšŸœŸœŸœ ŸœŸœŸœŸœŸœŸœ˜NKšŸœŸœ7˜NK˜—š  œŸœ Ÿœ Ÿœ˜3KšŸœ ŸœŸœ˜-Kšœ˜—š  œŸœŸœ Ÿœ˜/KšŸœŸœŸœ˜)Kšœ˜—š  œŸœŸœ˜2KšŸœŸœŸœ˜+Kšœ˜—Kšœ Ÿœ&˜3Kšœ˜Kšœ8˜8šŸ˜KšœŸœŸœ˜Kšœ Ÿœ˜%šœ‘˜KšœŸœ Ÿœ˜Kšœ)˜)šŸœŸœ‘ ˜KšœŸœŸœŸœ˜QKšœ˜—šŸœ‘ ˜Kšœ ŸœŸœ Ÿœ ˜3Kšœ˜K˜—K˜—šœ‘˜š  œŸœŸœ ŸœŸœŸœŸœ˜CKšœŸœ#˜.šŸœŸœŸœ˜KšœŸœ Ÿœ˜Kšœ ˜ KšŸœŸœ.‘ ˜FKšŸœ,‘ ˜;K˜K˜—K˜—š œŸœŸœ Ÿœ˜6KšŸœŸœŸœŸœ˜KšŸœŸœŸœ˜+Kšœ˜K˜—Kšœ*˜*Kšœ,˜,Kšœ)ŸœŸœ˜7K˜—šŸœ ŸœŸœ‘˜&KšœŸœ˜Kšœ:˜:šœ#˜#K˜-KšœŸœ Ÿœ˜Kšœ"˜"KšŸœŸœ*˜7šŸœŸœŸœ‘˜>Kšœ3˜3Kšœ3˜3Kšœ3˜3KšŸœ.˜5—K˜Kšœ˜Kšœ˜—Kšœ,˜,Kšœ˜K˜Kšœ,˜,KšŸœŸœŸœ˜ K˜—šœ‘˜Kš œŸœŸœŸœŸœ˜,Kšœ ŸœŸœ Ÿœ ˜:K˜KšŸœ˜KšŸœ˜K˜—šœ‘˜KšŸœŸœŸœ‘˜9šŸœŸœ‘&˜.KšŸœ ŸœŸœ˜Kš Ÿœ ŸœŸœŸœ‘ ˜šŸœŸœŸœ ŸœŸœŸœŸœ˜?K˜KšŸœŸœŸœ ŸœŸœ ŸœŸœŸœŸœŸœŸœ ŸœŸœŸœ ˜ˆK˜—KšŸœŸœ˜ K˜K™—š  œŸœŸœŸœŸœ ˜>KšŸœ1˜7K˜K™——™ š   œŸœŸœŸœŸœ˜,KšŸœ3˜9K˜K™—š  œŸœŸœŸœŸœŸœ˜?KšœŸœ ˜*KšœŸœ ˜(Kš œŸœŸœŸœŸœŸœ˜šŸœŸœŸœ˜$KšœŸœŸœ.˜8KšœŸœŸœ.˜8KšœŸœŸœ-˜7K˜—KšŸœŸœ˜%K˜K˜—š  œŸœŸœŸœŸœ Ÿœ˜HKšœŸœ˜%šŸœŸœŸœ˜KšœŸœŸœ!˜>Kšœ'˜'Kšœ˜—šŸœ˜KšŸœ˜Kšœ˜K˜—K˜K˜—š  œŸœŸœŸœŸœ˜3KšœŸœ˜%šŸœŸœŸœ˜KšœŸœŸœŸœ˜Kšœ Ÿœ˜!KšŸœŸœ˜Kšœ˜—KšŸœŸœ˜K˜K˜—K˜š œŸœŸœŸœ ˜=šŸœ˜KšŸœŸœ7˜BKšŸœŸœ#˜.—K˜K˜—š œŸœŸœŸœ˜;KšœŸœ˜%šŸœŸœŸœ˜KšœŸœŸœŸœ˜Kšœ Ÿœ˜!KšœŸœŸœ˜šŸœ˜Kšœ0˜0Kšœ3˜3Kšœ˜—Kšœ˜—KšŸœŸœŸœ˜/K˜K™—šœŸœŸœ˜'K™—š œŸœŸœ ŸœŸœŸœ Ÿœ ŸœŸœ Ÿœ˜KšœŸœŸœ˜Kšœ9ŸœSŸœ.˜ΑKšœ˜Kšœ(˜(K˜K˜—š œŸœŸœ ŸœŸœŸœ ŸœŸœ ŸœŸœ˜}KšœŸœ Ÿœ&˜>KšŸœ˜K˜K˜—š  œŸœŸœŸœ Ÿœ ŸœŸœ Ÿœ˜uKšœ-Ÿœ˜?KšŸœ ˜KšŸœ˜%K˜K˜—š  œŸœŸœŸœŸœ ŸœŸœ ŸœŸœ˜KšœŸœŸœ:˜IKšœ-Ÿœ˜?Kšœ˜KšŸœ ˜ Kšœ(˜(K˜K˜——™ š  œŸœŸœŸœŸœ˜8KšœŸœ˜ KšœŸœ˜KšœŸœ˜šŸœ Ÿœ'Ÿ˜=Kšœ Ÿœ˜—Kš ŸœŸœŸœŸœŸœŸœ˜K•StartOfExpansion>[s1: ROPE, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE]šŸœ(Ÿœ˜0KšœŸœŸœ™+KšŸœŸœ˜Kšœ˜—šŸœ*Ÿœ˜2K™9KšŸœŸœ˜Kšœ˜—KšŸœŸœ˜K˜K˜—š œŸœ ŸœŸœŸœŸœŸœ Ÿœ ŸœŸœŸœ˜‹KšœŸœ ˜KšœŸœ˜"KšœŸœŸœ˜+šŸ˜KšœŸœ0˜6KšŸœŸœ ˜ KšŸœŸœ˜$KšŸœ ŸœŸœ˜Kšœ ˜ KšŸœ˜—Kšœ˜K™—š  œŸœŸœŸœŸœŸœŸœ ŸœŸœ˜hKšœ˜KšœŸœ˜Kšœ Ÿœ˜š  œŸœ˜Kš Ÿœ ŸœŸœŸœ‘˜KKšœ˜—š  œŸœ˜KšŸœ˜Kšœ˜—KšŸœŸœŸœ˜!šŸ˜K˜,KšŸœŸœŸœŸœ˜K˜šŸœŸœŸœŸœ!˜JšŸœ˜š œŸœŸœŸœ˜0KšœŸœŸœ˜š œŸœŸœŸœ˜0KšŸœŸœŸœŸœ˜)KšŸœ3˜5KšœŸœ˜Kšœ˜—Kšœ Ÿœ‘/˜RKšœ5˜5K˜ Kšœ˜—KšœG˜GKšœ˜—KšŸœŸœ$˜:—KšŸœ˜—K˜K™—š  œŸœŸœŸœŸœŸœ˜SJ˜#K˜K™—š  œŸœŸœŸœŸœŸœ˜RKšœŸœ˜%šŸœŸœŸœ˜KšœŸœŸœŸœ˜K˜#KšŸœŸœ˜Kšœ˜—KšŸœŸœ˜K˜K˜—K™—™š  œŸœŸœŸœŸœ™Dš ŸœŸœŸœŸœ,ŸœŸ™NKš œŸœŸœŸœŸœ™GKšŸœŸœ™—KšŸœ™ Kšœ™K™—š  œŸœŸœŸœŸœ™Dš ŸœŸœŸœŸœ,ŸœŸ™NKšœŸœŸœ™KšŸœŸœ™—KšŸœ™Kšœ™K™—š   œŸœŸœŸœŸœ™7KšŸœ™!Kšœ™K™—š œŸœŸœ ŸœŸœŸœŸœ™VK™8KšŸœ&™,K™K™—š œŸœŸœŸœŸœŸœŸœŸœŸœ™dKšœŸœ™'šŸœ Ÿ™KšŸœŸœ'™4šŸœ™KšœŸœ‘™-KšœŸœ‘™(KšœŸœŸœ™Kšœ™KšœŸœ™KšœŸœ"™*šŸ™Kšœ Ÿœ™šŸœŸœŸœ™Kšœ Ÿœ™%šŸœŸœŸœ™-šŸœ™Kšœ™Kšœ™—šŸœ™Kšœ5™5Kšœ™Kšœ™——Kšœ™—Kšœ,™,Kšœ™KšŸœ ŸœŸœŸœ™2KšŸœ™—KšŸœ'™-Kšœ™——Kšœ™K™——K˜KšŸœ˜—…—Kκvό