Tioga.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Doug Wyatt, September 23, 1986 5:09:06 pm PDT
DIRECTORY
FS USING [OpenFile],
ImagerFont USING [BYTE, XChar],
IO USING [STREAM],
Rope USING [ROPE],
TextLooks USING [Looks, allLooks, noLooks, Runs];
Tioga: CEDAR DEFINITIONS
~ BEGIN
Types
Char, Rope, Looks
CharSet: TYPE ~ ImagerFont.BYTE;
XChar: TYPE ~ ImagerFont.XChar;
ROPE: TYPE ~ Rope.ROPE;
Runs: TYPE ~ TextLooks.Runs;
Looks: TYPE ~ TextLooks.Looks;
noLooks: Looks ~ TextLooks.noLooks;
allLooks: Looks ~ TextLooks.allLooks;
Node
Node: TYPE ~ REF NodeBody;
NodeBody: TYPE ~ RECORD [
next: Node, -- points to next sibling, or if last=true, to parent
child: Node, -- points to first child, if any, of this node
props: Props, -- points to node property list
formatName: ATOMNIL, -- name of format for the node
last: BOOLFALSE, -- true if this is last sibling
hasstyledef: BOOLFALSE, -- true if node has StyleDef prop (accelerator)
hasprefix: BOOLFALSE, -- true if node has Prefix prop (accelerator)
haspostfix: BOOLFALSE, -- true if node has Postfix prop (accelerator)
hascharprops: BOOLFALSE, -- true if node has CharProps prop (accelerator)
hascharsets: BOOLFALSE, -- true if node has CharSets prop (accelerator)
hasartwork: BOOLFALSE, -- true if node has Artwork prop (accelerator)
deleted: BOOLFALSE, -- true if has been deleted or is root pending delete
dirty: BOOLFALSE, -- true if has been edited (contents, or children moved, inserted, ...)
new: BOOLFALSE, -- true if created during this editing session (i.e., not from file)
comment: BOOLFALSE, -- true if node is a comment
count: [0..countMax] ← 0, -- incremented by text edit routines
rope: ROPE,
runs: Runs
];
Props: TYPE ~ REF PropsBody;
PropsBody: TYPE ~ RECORD [name: ATOM, value: REF, next: Props];
countMax: NAT ~ 37B; -- 5 bits for count
Location, Text, Span
maxLen: INT ~ INT.LAST;
nodeItself: INT ~ -1;
Location: TYPE ~ RECORD [node: Node, where: INT ← 0];
where >= length of text means at end
where in [0..length) means before that character
e.g., where = 0 means at start of text
where = nodeItself means location is the node itself rather than in its contents
nullLocation: Location ~ [node: NIL, where: nodeItself];
MakeNodeLoc: PROC [n: Node] RETURNS [Location]
~ INLINE { RETURN [[node: n, where: nodeItself]] };
Text: TYPE ~ RECORD [node: Node, start: INT ← 0, len: INT ← maxLen];
represents the characters [start..start+len) in node
end: PROC [text: Text] RETURNS [INT]
~ INLINE { RETURN[text.start+text.len] };
hack so text.start and text.end are uniformly usable
Span: TYPE ~ RECORD [start, end: Location ← nullLocation];
start.node can equal end.node
in which case either both start.where and end.where = nodeItself, or
neither does and start.where <= end.where
otherwise, end.node should follow start.node in the tree
nodes need not be siblings
no restrictions on start.where or end.where
nullSpan: Span ~ [nullLocation, nullLocation];
MakeNodeSpan: PROC [first, last: Node] RETURNS [Span]
~ INLINE { RETURN [[MakeNodeLoc[first], MakeNodeLoc[last]]] };
World
World: TYPE ~ REF WorldRep;
WorldRep: TYPE;
Tree operations
Parent, Sibling, Child
Parent: PROC [n: Node] RETURNS [Node];
returns parent of n
returns NIL if n is root
Root: PROC [n: Node] RETURNS [Node];
returns root of tree containing n
Next: PROC [n: Node] RETURNS [Node];
returns next sibling of n
returns NIL if n is last sibling
Previous: PROC [n: Node, parent: Node ← NIL] RETURNS [Node];
returns previous sibling of n
returns NIL if n is first sibling
runs faster if can supply parent
IsLastSibling: PROC [n: Node] RETURNS [BOOL];
IsLastSibling[n] == Next[n]=NIL.
FirstChild: PROC [n: Node] RETURNS [Node];
Parent[FirstChild[n]] = n; Previous[FirstChild[n]] = NIL.
LastChild: PROC [n: Node] RETURNS [Node];
Parent[FirstChild[n]] = n; Next[LastChild[n]] = NIL.
FirstSibling: PROC [n: Node] RETURNS [Node];
FirstSibling[n] = FirstChild[Parent[n]]
LastSibling: PROC [n: Node] RETURNS [Node];
LastSibling[n] = LastChild[Parent[n]]
LastWithin: PROC [n: Node] RETURNS [Node];
returns the last node within the branch
i.e., goes to last child of last child of last child ... until no child
Level: PROC [n: Node] RETURNS [INT];
Level[Root[x]] == 0; Level[FirstChild[n]]=Level[n]+1
Counting
NthChild: PROC [n: Node, index: INT] RETURNS [Node];
NthChild[n, 0] == FirstChild[n]; NthChild[n, k+1] == Next[NthChild[n, k]]
NthSibling: PROC [n: Node, index: INT] RETURNS [Node];
CountChildren: PROC [n: Node] RETURNS [count: INT];
CountFollowing: PROC [n: Node] RETURNS [count: INT];
CountToParent: PROC [n: Node] RETURNS [count: INT, parent: Node];
CountToChild: PROC [parent, child: Node] RETURNS [count: INT];
Forward, Backward
Forward: PROC [node: Node] RETURNS [nx: Node, levelDelta: INT];
returns next node in standard tree walk order
levelDelta is Level[node]-Level[nx], where level is depth in tree
levelDelta = 0 if nx and node are siblings
levelDelta = 1 if nx is child of node
levelDelta < 0 if do Parent* and Next to reach nx from node
Backward: PROC [node: Node, parent: Node ← NIL]
RETURNS
[back, backparent: Node, levelDelta: INT];
for backing through tree
runs faster if can supply parent
levelDelta same as for Forward
StepForward: PROC [node: Node] RETURNS [Node];
returns next node in standard tree walk order
StepBackward: PROC [node: Node, parent: Node ← NIL] RETURNS [Node];
returns preceding node in standard tree walk order
runs faster if can supply parent
ForwardClipped: PROC [node: Node, maxLevel: INT, nodeLevel: INT ← 0]
RETURNS
[nx: Node, nxLevel: INT];
like Forward, but limits how deep will go in tree
if pass nodeLevel=0, correct value will be computed
nxLevel = Level[nx] <= MAX[maxLevel,Level[node]]
BackwardClipped: PROC [node: Node, maxLevel: INT, parent: Node ← NIL, nodeLevel: INT ← 0] RETURNS [back, backparent: Node, backLevel: INT];
like Backward, but limits how deep will go in tree
backLevel = Level[back] <= MAX[maxLevel,Level[node]]
Locations
BadArgs: ERROR;
LocRelative: PROC [location: Location, count: INT, break: INT ← 1,
skipCommentNodes: BOOLFALSE] RETURNS [Location];
count is interpreted as a character offset from given location
returns <node,offset> location corresponding to count
adds in break at the end of each text subnode
if skipCommentNodes is true, then ignores them in walking the tree
LocWithin: PROC [n: Node, count: INT, break: INT ← 1,
skipCommentNodes: BOOLFALSE] RETURNS [Location];
LocRelative[[n, 0], ...]; count is offset from beginning of given node
LocOffset: PROC [loc1, loc2: Location, break: INT ← 1,
skipCommentNodes: BOOLFALSE] RETURNS [count: INT];
returns character offset of location2 relative to location1
loc1 and loc2 can be in same node
but loc2 must not be in node before loc1 or get ERROR BadArgs
if skipCommentNodes is true, then ignores them in walking the tree
LocNumber: PROC [at: Location, break: INT ← 1,
skipCommentNodes: BOOLFALSE] RETURNS [count: INT];
returns character offset of location relative to root
LastLocWithin: PROC [n: Node] RETURNS [Location];
returns the last location within the branch
Order
Order: TYPE ~ { before, same, after, disjoint };
CompareNodeOrder: PROC [node1, node2: Node] RETURNS [Order];
determines relative order in tree of the nodes
returns "same" if node1 = node2
returns "before" if node1 comes before node2
returns "after" if node1 comes after node2
returns "disjoint" if nodes are not from the same tree
CompareLocOrder: PROC [loc1, loc2: Location] RETURNS [Order];
Node operations
Creation
NewNode: PROC RETURNS [Node];
NodeFromRope: PROC [rope: ROPE, looks: Looks ← noLooks] RETURNS [Node];
create a text node with looks from a normal rope
RopeFromString: PROC [string: REF READONLY TEXT, start: NAT ← 0, len: NATNAT.LAST] RETURNS [ROPE];
copies the string
DocFromNode: PROC [child: Node] RETURNS [root: Node];
returns root node which has one child
child typically created by NodeFromRope
Size, Fetch
Size: PROC [node: Node] RETURNS [INT];
FetchChar: PROC [node: Node, index: INT] RETURNS [XChar];
fetches the indexed information
use rope readers if want characters from contiguous locations
FetchLooks: PROC [node: Node, index: INT] RETURNS [Looks];
returns the looks for the character at the given location
use readers if getting looks for sequence of locations
Fetch: PROC [node: Node, index: INT] RETURNS [char: XChar, looks: Looks];
fetches the indexed information, except for character properties
use rope & looks readers if want info from contiguous locations
GetRope: PROC [node: Node] RETURNS [ROPE];
GetRuns: PROC [node: Node] RETURNS [Runs];
Immutable PropList
PropList: TYPE ~ LIST OF Prop; -- assumed immutable!
Prop: TYPE ~ REF PropRep;
PropRep: TYPE ~ RECORD [name: ATOM, value: REF];
PropListGet: PROC [propList: PropList, name: ATOM] RETURNS [value: REF];
PropListPut: PROC [propList: PropList, name: ATOM, value: REF] RETURNS [PropList];
MapPropsAction: TYPE ~ PROC [name: ATOM, value: REF] RETURNS [quit: BOOLFALSE];
PropListMap: PROC [propList: PropList, action: MapPropsAction] RETURNS [quit: BOOL];
Node and Char Properties
GetProp: PROC [node: Node, name: ATOM] RETURNS [REF];
GetFormat: PROC [node: Node] RETURNS [ATOM];
GetComment: PROC [node: Node] RETURNS [BOOL];
MapProps: PROC [node: Node, action: MapPropsAction,
formatFlag, commentFlag: BOOLTRUE] RETURNS [quit: BOOL];
apply the action to each name & value pair for the node
returns true if&when an action returns true
if commentFlag is false, skips Comment property; ditto for formatFlag
hack to accelerate Inherit and PutFile operations
GetCharProp: PROC [node: Node, index: INT, name: ATOM] RETURNS [REF];
GetCharPropList: PROC [node: Node, index: INT] RETURNS [PropList];
MapCharProps: PROC [node: Node, index: INT, action: MapPropsAction]
RETURNS
[quit: BOOL];
apply the action to each name & value pair for the indexed character
Property registration
PropReader: TYPE ~ PROC [name: ATOM, specs: ROPE] RETURNS [value: REF];
used when reading files; convert from external specs to internal REF
PropWriter: TYPE ~ PROC [name: ATOM, value: REF] RETURNS [specs: ROPE];
used when writing files; convert from internal REF to external specs
PropCopier: TYPE ~ PROC [name: ATOM, value: REF] RETURNS [new: REF];
used when copying nodes; copy internal REF
ReadProp: PropReader;
calls the registered reader for this property name
if no reader is registered, returns specs
WriteProp: PropWriter;
calls the registered writer for this property name
if no writer is registered, returns value if it is a rope, NIL otherwise
CopyProp: PropCopier;
calls the registered copier for this property name
if no copier is registered, returns old value
NullRead: PropReader;
NullWrite: PropWriter;
NullCopy: PropCopier;
these always return NIL
RegisterProp: PROC [name: ATOM, reader: PropReader, writer: PropWriter, copier: PropCopier];
registers procs for given property name
they will be called by ReadProp, WriteProp, CopyProp
Editing
Replace by Rope
ReplaceByRope: PROC [world: World, root: Node, dest: Text, rope: ROPE,
inherit: BOOLTRUE, looks: Looks ← noLooks, charSet: CharSet ← 0] RETURNS [Text];
replacement characters don't get any character properties
if inherit is false, chars get specifed looks
if inherit is true, chars get looks in following manner:
if dest length is 0, then get looks from argument list, else
if start > 0, then get looks from previous char,
else get looks from char following replacement
result describes the new text
InsertRope: PROC [world: World, root: Node, dest: Location, rope: ROPE,
inherit: BOOLTRUE, looks: Looks ← noLooks, charSet: CharSet ← 0] RETURNS [Text]
~ INLINE{ RETURN ReplaceByRope[world: world, root: root, dest: [dest.node, dest.where, 0],
rope: rope, inherit: inherit, looks: looks, charSet: charSet] };
AppendRope: PROC [world: World, root: Node, dest: Node, rope: ROPE,
inherit: BOOLTRUE, looks: Looks ← noLooks, charSet: CharSet ← 0] RETURNS [Text]
~ INLINE{ RETURN ReplaceByRope[world: world, root: root, dest: [dest, maxLen, 0],
rope: rope, inherit: inherit, looks: looks, charSet: charSet] };
Edit Text
NOTE: edit operations do not create or delete addrs,
but they can change their locations within the text
ReplaceText: PROC [world: World, destRoot, sourceRoot: Node, dest: Text, source: Text]
RETURNS
[result: Text];
replace the dest text by a copy of the source text
addrs that are in the replaced text move to destStart
addrs that are after the replaced text are adjusted
DeleteText: PROC [world: World, root: Node, text: Text];
delete the specified range of text
addrs that are in the deleted section move to start
CopyText: PROC [world: World, destRoot, sourceRoot: Node, dest: Location, source: Text]
RETURNS
[result: Text];
copy the specified text
add length of inserted text to addrs that are beyond dest.where
MoveText: PROC [world: World, destRoot, sourceRoot: Node, dest: Location, source: Text]
RETURNS
[result: Text];
move source to dest
no-op if LocationInText[dest, source]
addrs that are in the moved text do one of the following:
move with the text if dest = source,
or move to start if dest # source
MoveTextOnto: PROC [world: World, destRoot, sourceRoot: Node, dest: Text, source: Text]
RETURNS
[result: Text];
move source onto dest
implemented by appropriate calls on MoveText and DeleteText
TransposeText: PROC [world: World, alphaRoot, betaRoot: Node, alpha: Text, beta: Text]
RETURNS
[alphaResult: Text, betaResult: Text];
transpose alpha and beta
addrs treated same as in Move
move with the text if alpha.node = beta.node,
or move to respective starts if alpha.node # beta.node
Edit Spans
Place: TYPE ~ { before, after, sibling, child };
these are modifiers for the destination of a Move or Copy or Insert
only apply when destination is an entire node (i.e., dest.where = nodeItself)
place = before means insert as sibling before dest
place = after means insert as sibling after dest; inherit children of dest
place = sibling means insert as sibling after dest; don't inherit children of dest
place = child means insert as first child of dest
Replace: PROC [world: World, destRoot, sourceRoot: Node, dest, source: Span,
saveForPaste: BOOLTRUE] RETURNS [result: Span];
replace dest span by copy of source span
result is the new copy of source
Delete: PROC [world: World, root: Node, del: Span, saveForPaste: BOOLTRUE];
SaveForPaste: PROC [world: World, span: Span];
SavedForPaste: PROC [world: World] RETURNS [span: Span];
result is last thing deleted or explicitly saved for Paste
Copy: PROC [world: World, destRoot, sourceRoot: Node, dest: Location, source: Span,
where: Place ← after, nesting: INT ← 0] RETURNS [result: Span];
result is the new copy of source
Move: PROC [world: World, destRoot, sourceRoot: Node, dest: Location, source: Span,
where: Place ← after, nesting: INT ← 0] RETURNS [result: Span];
dest cannot be within source or get error CannotDoEdit
result is moved span
nesting is relative to dest
e.g., where=after and nesting=1 makes source be child of dest
MoveOnto: PROC [world: World, destRoot, sourceRoot: Node, dest, source: Span,
saveForPaste: BOOLTRUE] RETURNS [result: Span];
like Replace, but moves source instead of copying it
result is moved span
Transpose: PROC [world: World, alphaRoot, betaRoot: Node, alpha, beta: Span]
RETURNS
[newAlpha, newBeta: Span];
alpha and beta must not overlap or get error CannotDoEdit
newAlpha is new location of alpha span; ditto for newBeta
CannotDoEdit: ERROR;
Insert, Split, Merge, Nest
Insert: PROC [world: World, root: Node, old: Node, where: Place ← after,
inherit: BOOLTRUE] RETURNS [new: Node];
new empty node is inserted in tree in position determined by "where"
if inherit, new node inherits properties of old
Split: PROC [world: World, root: Node, loc: Location] RETURNS [new: Node];
inserts copy of loc.node is inserted directly before loc.node (as sibling)
new adopts children of old (if any)
if loc.where # nodeItself and loc.node is a text node, then
text after loc.where moves to new node
text before loc.where stays in old node
returns the new node
Merge: PROC [world: World, root: Node, node: Node] RETURNS [loc: Location];
copies text of node to end of previous node
then deletes node
ChangeNesting: PROC [world: World, root: Node, span: Span, change: INT] RETURNS [Span];
moves all nodes of span, even if entire nodes not selected
change>0 is deeper in the tree, change<0 is shallower
Node properties
SetProp: PROC [world: World, node: Node, name: ATOM, value: REF, root: Node ← NIL];
SetComment: PROC [world: World, node: Node, comment: BOOL, root: Node ← NIL];
Sets the $Comment property of a node.
SetFormat: PROC [world: World, node: Node, formatName: ATOM, root: Node ← NIL];
Sets the $Format property of a node.
SetStyle: PROC [world: World, node: Node, styleName: ROPE, root: Node ← NIL];
appends <name> style to end of node prefix
Char properties
SetCharProp: PROC [world: World, text: Text, name: ATOM, value: REF, root: Node ← NIL];
Places the value on the character property lists of the chars in the specified range.
Use value = NIL to remove a character property.
SetCharPropList: PROC [world: World, text: Text, propList: PropList, root: Node ← NIL];
ModifyPropsAction: TYPE ~ PROC [value: REF, start: INT, len: INT]
RETURNS
[quit: BOOLFALSE, newValue: REF];
ModifyCharProps: PROC [world: World, text: Text, name: ATOM, action: ModifyPropsAction, root: Node ← NIL] RETURNS [quit: BOOL];
Used for traversing and altering the values of a character property over a range of characters; the action procedure is called for runs of properties, but adjacent runs are not necessarily merged.
Looks, Caps
ChangeTextLooks: PROC [world: World, root: Node, text: Text, remove, add: Looks];
first remove then add in the given range
ChangeLooks: PROC [world: World, root: Node, span: Span, remove, add: Looks];
first remove then add in the given span
CapChange: TYPE ~ {allCaps, allLower, initCaps, firstCap};
ChangeTextCaps: PROC [world: World, root: Node, text: Text, how: CapChange ← allCaps];
ChangeCaps: PROC [world: World, root: Node, span: Span, how: CapChange ← allCaps];
Other
Searching
"Find" operation for text nodes
The pattern is given as a substring of a text node
The text to be searched is also a substring of a text node
The search can be in either direction within the substring
If a match character in the pattern has looks,
the looks of the matching character(s) in the text will include those looks.
For example, if the pattern includes a * with looks x and y,
the characters matching the * will have looks x and y too.
The matching characters may have other looks too.
MalformedPattern: ERROR [ec: PatternErrorCode];
PatternErrorCode: TYPE = {
toobig, -- pattern too long
endquote, -- pattern ends with '
endtilda, -- pattern ends with ~
boundary, -- pattern has | inside rather than at beginning or end
missingNameEnd, -- pattern has < without matching >
unmatchedNameEnd -- pattern has > without previous <
};
Finder: TYPE = REF FinderRec;
FinderRec: TYPE;
FinderFromText: PROC [pattern: Text,
literal, word, ignoreLooks, ignoreCase, addBounds: BOOLFALSE]
RETURNS [finder: Finder];
creates a record containing a "compiled" version of the pattern
if literal is true, each character in pattern is taken literally
if word flag is true, pattern only matches if no adjacent letters or digits
if ignoreLooks is true, then ignore the looks of the pattern characters
if ignoreCase is false, then alpha chars in pattern must match case
otherwise, they can match either upper or lower
if addBounds is true, add |'s to both ends of pattern
FinderFromRope: PROC [pattern: ROPE, start: INT ← 0, len: INT ← maxLen,
literal, word, ignoreCase, addBounds: BOOLFALSE]
RETURNS [finder: Finder];
NameLoc: PROC [finder: Finder, name: ROPE] RETURNS [at, atEnd: INT];
name is the name of a subpattern
value is where that subpattern matched last time
NameLooks: PROC [finder: Finder, name: ROPE] RETURNS [looks: Looks];
name is the name of a subpattern
value are looks that name had in the pattern
SearchDirection: TYPE ~ {forward, backward};
SearchText: PROC [finder: Finder, text: Text, looksExact: BOOLFALSE,
direction: SearchDirection ← forward, interrupt: REF BOOLNIL
] RETURNS [found: BOOL, at, atEnd, before, after: INT];
if direction = forward, searches text for first match in [start..start+len)
i.e., searches up from start until reaches start+len
if direction = backward, searches for last match in [start..start+len)
i.e., searches down from start+len until reaches start
if finds a match, returns with found = true,
at = beginning of match or location corresponding to { in pattern
atEnd = end of match or location corresponding to } in pattern
after = end of entire match, which may be > atEnd if used } in pattern
before = start of entire match, which may be < at if used { in pattern
if looksExact is true, then match by equality, else by subset
if interrupt^ becomes true, will stop searching
SearchRope: PROC [finder: Finder, rope: ROPE, start: INT ← 0, len: INT ← maxLen,
direction: SearchDirection ← forward, interrupt: REF BOOLNIL
] RETURNS [found: BOOL, at, atEnd, before, after: INT];
like SearchText, but searches a rope instead of a node
CommentControl: TYPE = { includeComments, excludeComments, commentsOnly };
Search: PROC [finder: Finder, span: Span, looksExact: BOOLFALSE,
commentControl: CommentControl ← includeComments,
checkFormat: BOOLFALSE, format: ATOMNIL,
checkStyle: BOOLFALSE, style: ATOMNIL,
styleProc: PROC [Node] RETURNS [ATOM] ← NIL,
direction: SearchDirection ← forward, interrupt: REF BOOLNIL
] RETURNS [found: BOOL, where: Node, at, atEnd, before, after: INT];
if direction = forward, searches from span.start to span.end
continues until finds a match or reaches end of span
if direction = backward, searches from span.end to span.start
continues until finds a match or reaches start of span
if finds a match, returns with found = true,
at = beginning of match or location corresponding to { in pattern
atEnd = end of match or location corresponding to } in pattern
after = end of entire match, which may be > atEnd if used } in pattern
before = start of entire match, which may be < at if used { in pattern
if looksExact is true, then match by equality, else by subset
commentControl allows restriction of search to comments/noncomments
if checkFormat is true, then only match in nodes with given format
if checkStyle is true, then only match in nodes with given style
styleProc is supplied so called can determine style for nodes
if just interested in format/style, can pass finder=NIL
if interrupt^ becomes true, will stop searching
SearchApplyProc: TYPE = PROC [where: Node, at, atEnd, before, after: INT]
RETURNS [continue, bumpCount: BOOL, from, delta: INT];
arg's are results from Search
if continue is true, SearchApply will Search again starting at "from" in "where"
delta tells change in length caused by the action
SearchApply does the following with delta:
IF where=span.end.node AND span.end.where < maxLen THEN
span.end.where ← span.end.where+delta
if bumpCount is true, SearchApply will increment its result counter
SearchApply: PROC [finder: Finder, span: Span, proc: SearchApplyProc,
looksExact: BOOLFALSE, commentControl: CommentControl ← includeComments,
checkFormat: BOOLFALSE, format: ATOMNIL,
checkStyle: BOOLFALSE, style: ATOMNIL,
styleProc: PROC [Node] RETURNS [ATOM] ← NIL
] RETURNS [count: INT];
finds a span of text and calls proc
Input/Output
Stream I/O
ToStream: PROC [stream: IO.STREAM, node: Node, flatten, textOnly: BOOLFALSE]
RETURNS
[dataLen, count: INT];
does a series of IO.PutBlock's
returns number of bytes written
FromStream: PROC [stream: IO.STREAM, len: INT ← maxLen] RETURNS [Node];
reads up to len chars from stream (via GetBlock's) to construct a node
ToStreamPlain: PROC [stream: IO.STREAM, root: Node, restoreDashes: BOOLFALSE];
File I/O
ToFile: PROC [fileName: ROPE, node: Node, start: INT ← 0, flatten, textOnly: BOOLFALSE]
RETURNS
[dataLen, count: INT];
ToFileC: PROC [file: FS.OpenFile, node: Node, start: INT ← 0, flatten, textOnly: BOOLFALSE]
RETURNS
[dataLen, count: INT];
write the node on the specified file
starts writing at given address in file
returns dataLen = number of data bytes at start of file,
and count = the total number of bytes written
FromFile: PROC [fileName: ROPE, start: INT ← 0, len: INT ← maxLen] RETURNS [Node];
FromFileC: PROC [file: FS.OpenFile, start: INT ← 0, len: INT ← maxLen] RETURNS [Node];
create node from the contents of a file
starts reading at given start address in file
pretends that start+len is the end of the file
if file was not created by ToFile (i.e., password not correct)
then returns a single node containing contents of the file
FromFileError: ERROR;
ToFilePlain: PROC [fileName: ROPE, root: Node, restoreDashes: BOOLFALSE];
ToFileCPlain: PROC [file: FS.OpenFile, root: Node, restoreDashes: BOOLFALSE];
gives text of file with CR after each node and TABs before according to nesting
if restoreDashes, adds initial dashes to comments if necessary.
ReadIndent: PROC [fileName: ROPE, tabIndent: NAT ← 4] RETURNS [Node];
Rope I/O
ToRope: PROC [node: Node, flatten, textOnly: BOOLFALSE]
RETURNS
[dataLen, count: INT, output: ROPE];
resulting rope contains same representation of node as would be put on file
FromRope: PROC [rope: ROPE, start: INT ← 0, len: INT ← maxLen] RETURNS [Node];
reads rope to construct node
ToRopePlain: PROC [root: Node, restoreDashes: BOOLFALSE] RETURNS [output: ROPE];
END.