PutFileImpl.Mesa
written by Paxton. August 1983
Last Edited by: Paxton, August 16, 1983 7:50 pm
DIRECTORY
Directory USING [GetProperty],
File USING [Capability],
FileIO USING [CapabilityFromStream, Open, StreamFromCapability],
FileWriter USING [Close, OpenC, Ref, ToRope, ToStream],
IO USING [Close, CreateOutputStreamToRope, Error, GetIndex, GetOutputStreamRope, Handle, PutChar, PutRope, SetLength],
NodeProps USING [GetProp, HasWriter, PutProp, MapProps],
OutputStructure USING [Output],
Process USING [GetPriority, Priority, priorityBackground, SetPriority],
PropertyTypes USING [tCreateDate],
PutGet,
Rope USING [Fetch, ROPE],
RopeEdit USING [BlankChar, Size],
RopeIO USING [PutRope, ToFileC],
System USING [GreenwichMeanTime],
T2FileOps,
TiogaLooks USING [Look, Looks, noLooks, Runs],
TiogaItemClass USING [ItemClass],
TiogaNode USING [Name, nullName, Offset, Path, Ref, RefBranchNode, RefItemNode, RefTextNode],
TiogaNodeOps USING [FetchItemClass, NarrowToBranchNode, NarrowToTextNode],
TiogaPathOps USING [Contents, Equal, Forward, LastWithin, StepForwardNode];
PutFileImpl:
CEDAR PROGRAM
IMPORTS Directory, FileIO, FileWriter, IO, NodeProps, OutputStructure, Process, Rope, RopeEdit, RopeIO, TiogaNodeOps, TiogaPathOps
EXPORTS PutGet
SHARES TiogaNode =
ToRope:
PUBLIC
PROC [node: Ref, textOnly:
BOOLEAN ←
FALSE]
RETURNS [dataLen, count: Offset, output: ROPE] = {
ctrl, data: FileWriter.Ref;
simple: BOOLEAN;
flags: CHAR;
[output, simple] ← SimpleFile[node];
IF simple THEN { dataLen ← count ← RopeEdit.Size[output]; RETURN };
[ctrl, data] ← FileWriter.ToRope[];
flags ← OutputStructure.Output[ctrl, data, node];
[dataLen, count, output] ← FileWriter.Close[ctrl, data, textOnly, flags] };
ToStream:
PUBLIC
PROC [
stream: IO.Handle, node: Ref, textOnly: BOOL ← FALSE]
RETURNS [dataLen, count: Offset] = {
ctrl, data: FileWriter.Ref;
rope: ROPE;
simple: BOOLEAN;
flags: CHAR;
[rope, simple] ← SimpleFile[node];
IF simple THEN { RopeIO.PutRope[stream, rope]; dataLen ← count ← RopeEdit.Size[rope]; RETURN };
[ctrl, data] ← FileWriter.ToStream[stream];
flags ← OutputStructure.Output[ctrl, data, node];
[dataLen, count, ] ← FileWriter.Close[ctrl, data, textOnly, flags] };
ToFile:
PUBLIC
PROC [
fileName: ROPE, node: Ref,
start: Offset ← 0, textOnly: BOOLEAN ← FALSE]
RETURNS [dataLen, count: Offset] = {
stream: IO.Handle ← FileIO.Open[fileName, overwrite];
capability: File.Capability ← FileIO.CapabilityFromStream[stream];
IO.Close[stream]; -- need to close first or get 0 length file!
[dataLen, count] ← ToFileC[capability, node, start, textOnly] };
ToFileC:
PUBLIC
PROC [
file: File.Capability, node: Ref,
start: Offset ← 0, textOnly: BOOLEAN ← FALSE]
RETURNS [dataLen, count: Offset] = {
ropeToFile:
PROC [rope:
ROPE] = {
RopeIO.ToFileC[file, rope, start] };
opener:
PROC
RETURNS [ctrl, data: FileWriter.Ref] = {
[ctrl, data] ← FileWriter.OpenC[file, start] };
[dataLen, count] ← FileIt[ropeToFile, opener, node, textOnly] ;
UpdateCreateDate[node, file] };
UpdateCreateDate:
PROC [node: Ref, file: File.Capability] =
TRUSTED {
createDate: System.GreenwichMeanTime;
prop: REF System.GreenwichMeanTime;
Directory.GetProperty[file: file, property: PropertyTypes.tCreateDate,
propertyValue: DESCRIPTOR[@createDate, SIZE[System.GreenwichMeanTime]]];
IF (prop ← NARROW[NodeProps.GetProp[node, $FileCreateDate]]) # NIL THEN prop^ ← createDate
ELSE NodeProps.PutProp[node, $FileCreateDate, NEW[System.GreenwichMeanTime ← createDate]] };
FileIt:
PROC [
ropeToFile: PROC [ROPE],
opener: PROC RETURNS [ctrl, data: FileWriter.Ref],
node: Ref, textOnly: BOOL]
RETURNS [dataLen, count: Offset] = TRUSTED {
ctrl, data: FileWriter.Ref;
rope: ROPE;
simple: BOOLEAN;
priority: Process.Priority = Process.GetPriority[];
Process.SetPriority[Process.priorityBackground];
[rope, simple] ← SimpleFile[node];
IF simple THEN { ropeToFile[rope]; dataLen ← count ← RopeEdit.Size[rope] }
ELSE {
flags: CHAR;
[ctrl, data] ← opener[];
flags ← OutputStructure.Output[ctrl, data, node];
[dataLen, count, ] ← FileWriter.Close[ctrl, data, textOnly, flags] };
Process.SetPriority[priority] };
SimpleFile:
PROC [n: TiogaNode.Ref]
RETURNS [rope:
ROPE, simple:
BOOLEAN] = {
SimpleNode:
PROC [node: TiogaNode.RefBranchNode]
RETURNS [
ROPE,
BOOLEAN] =
TRUSTED {
HasInterestingProp:
PROC [n: Ref]
RETURNS [
BOOL] =
TRUSTED {
Check:
PROC [name:
ATOM, value:
REF]
RETURNS [
BOOL] =
TRUSTED {
RETURN [NodeProps.HasWriter[name]] };
RETURN [NodeProps.MapProps[n, Check, FALSE, FALSE]] };
IF node.format=TiogaNode.nullName
AND ~node.comment
AND node.templateInfo=normal AND ~HasInterestingProp[node] THEN
IF node.contents = NIL THEN RETURN [NIL, TRUE];
WITH node.contents
SELECT
FROM
-- must have simple text node for contents
t: TiogaNode.RefTextNode => {
classInfo: TiogaItemClass.ItemClass;
IF ~t.last
OR ~t.format=TiogaNode.nullName
OR t.comment
OR t.templateInfo # normal
OR classInfo.flavor # $Text OR HasInterestingProp[t] THEN RETURN [NIL, FALSE];
classInfo ← TiogaNodeOps.FetchItemClass[t.class];
IF classInfo.flavor # $Text OR HasInterestingProp[t] THEN RETURN [NIL, FALSE];
IF t.runs=NIL THEN RETURN [t.rope, TRUE];
WITH r: t.runs
SELECT
FROM
base => IF r.length=1 AND r[0].looks=TiogaLooks.noLooks THEN RETURN [t.rope, TRUE];
ENDCASE };
ENDCASE;
RETURN [NIL, FALSE] };
root: TiogaNode.RefBranchNode;
IF n=NIL THEN RETURN [NIL, TRUE];
IF (root ← TiogaNodeOps.NarrowToBranchNode[n])=NIL THEN RETURN [NIL, FALSE];
[rope, simple] ← SimpleNode[root];
IF ~simple OR root.contents#NIL THEN RETURN[NIL, FALSE]; -- root must not have contents
IF root.child=NIL THEN RETURN [NIL, TRUE]; -- simple root and no child
IF ~root.child.last
OR root.child.child #
NIL
THEN
RETURN [NIL, FALSE]; -- more than one child, so not simple
[rope, simple] ← SimpleNode[root.child] };
WriteMesaFilePlain:
PUBLIC
PROC [fileName:
ROPE, root: TiogaNode.RefBranchNode]={
h: IO.Handle ← FileIO.Open[fileName: fileName, accessOptions: overwrite];
WritePlain[h, root, TRUE]; IO.Close[h] };
WriteFilePlain:
PUBLIC
PROC [fileName:
ROPE, root: TiogaNode.RefBranchNode] = {
h: IO.Handle ← FileIO.Open[fileName: fileName, accessOptions: overwrite];
WritePlain[h, root]; IO.Close[h] };
WriteFileCPlain:
PUBLIC
PROC [file: File.Capability, root: TiogaNode.RefBranchNode] = {
h: IO.Handle ← FileIO.StreamFromCapability[file];
WritePlain[h, root]; IO.Close[h] };
WriteRopePlain:
PUBLIC
PROC [root: TiogaNode.RefBranchNode]
RETURNS [output:
ROPE] = {
h: IO.Handle ← IO.CreateOutputStreamToRope[];
WritePlain[h, root]; RETURN [IO.GetOutputStreamRope[h]] };
WritePlain:
PROC [h:
IO.Handle, root: TiogaNode.RefBranchNode, restoreDashes:
BOOL ←
FALSE] = {
HasInitialDashes:
PROC [r:
ROPE]
RETURNS [
BOOL] = {
loc: INT ← 0;
size: INT = RopeEdit.Size[r];
c: CHAR;
WHILE loc < size
AND RopeEdit.BlankChar[c ← Rope.Fetch[r, loc]]
DO
loc ← loc+1; ENDLOOP;
IF loc > size OR c # '- OR Rope.Fetch[r, loc+1] # '- THEN RETURN [FALSE];
RETURN [TRUE] };
br: TiogaNode.RefBranchNode ← root;
path: TiogaNode.Path ← [br, NIL];
contents, lastWithin: TiogaNode.Path;
level: INTEGER ← 0;
levelDelta: INTEGER;
first: BOOL ← TRUE;
DO
firstItem: BOOL ← TRUE;
[path, levelDelta] ← TiogaPathOps.Forward[path];
IF path.node=NIL THEN EXIT;
IF first THEN first ← FALSE
ELSE IO.PutChar[h, '\n]; -- carriage returns between nodes
level ← level+levelDelta;
IF (contents ← TiogaPathOps.Contents[path]).node=NIL THEN LOOP;
THROUGH [1..level) DO IO.PutChar[h, '\t]; ENDLOOP; -- output level-1 tabs
lastWithin ← TiogaPathOps.LastWithin[contents];
DO
-- output the contents of the node
text: TiogaNode.RefTextNode;
IF (text ← TiogaNodeOps.NarrowToTextNode[contents.node]) #
NIL
THEN {
IF firstItem
AND restoreDashes
AND text.comment
AND ~HasInitialDashes[text.rope]
THEN
IO.PutRope[h, "-- "]; -- restore the leading dashes for Mesa comments
IO.PutRope[h, text.rope] };
firstItem ← FALSE;
IF TiogaPathOps.Equal[contents, lastWithin] THEN EXIT; -- finished
contents ← TiogaPathOps.StepForwardNode[contents];
ENDLOOP;
ENDLOOP;
{ ENABLE IO.Error => IF ec = NotImplementedForThisStream THEN GOTO Exit;
IO.SetLength[h, IO.GetIndex[h]] }
EXITS Exit => RETURN };
END.