TiogaToWalnutImpl.mesa
Copyright Ó 1990, 1992 by Xerox Corporation. All rights reserved.
Weiser, May 26, 1992 10:35 pm PDT
Code reviewed March 10, 1992 by CHauser and DTerry.
DIRECTORY BasicTime, CedarProcess, Commander, Convert, EditSpanSupport, PFS, IO, Rope, TextNode, TiogaExtraOps, TiogaOpsDefs, TiogaOps, TiogaIO, TiogaToWalnut;
TiogaToWalnutImpl: CEDAR PROGRAM
IMPORTS BasicTime, CedarProcess, Commander, Convert, EditSpanSupport, IO, PFS, Rope, TextNode, TiogaOps, TiogaExtraOps, TiogaIO, TiogaToWalnut
EXPORTS TiogaToWalnut
~ BEGIN
Types and Constants
ROPE: TYPE ~ Rope.ROPE;
Explanation: ROPE ~ "Write the contents of a file to a walnut archive file.
\tTiogaToWalnut [-flags] archiveFileName ← tiogaFileName msgSetName
\twhere flags are interpreted as follows:
\t\t'a' means append to archive file instead of overwrite.
\t\t'x' means don't write the archive file at all, just check for wellformed peanut nodes
\t\t'p' process a peanut file
\t\t'v' means verbosely announce when done with each file
";
Public Procedures
GetContentsOfNodeAndChildren: PUBLIC PROC [node: TextNode.Ref] RETURNS [text, formatting: ROPE] ~ {
root, endnode, tmpnode: TiogaOps.Ref;
newspan, span: TextNode.Span;
level: INT;
locate node and children. endnode is left pointing to last child.
endnode ¬ node;
level ¬ TextNode.Level[node];
tmpnode ¬ TextNode.StepForward[node];
UNTIL tmpnode = NIL OR TextNode.Level[tmpnode] = level DO
CedarProcess.CheckAbort[];
endnode ¬ tmpnode;
tmpnode ¬ TextNode.StepForward[tmpnode];
ENDLOOP;
copy the nodes into a fresh document so can get formatting information
span ¬ TextNode.MakeNodeSpan[node, endnode];
newspan ¬ EditSpanSupport.CopySpan[span];
root ¬ TextNode.Root[newspan.start.node];
CedarProcess.CheckAbort[];
[text, formatting] ¬ GetContents[root];
};
ContentsToArchive: PUBLIC PROC [text, formatting: ROPE, msgSet, msgID: ROPE, outstream: IO.STREAM] ~ {
length, prefixLength, itemLength, formatLength, textLength: INT;
construct a msgID if necessary
IF msgID = NIL THEN {
msgID ¬ BuildMsgId[msgSet];
};
write the document information in archive format
text ¬ Rope.Substr[text, 1]; -- Skip the root node, archive format doesn't want it.
formatLength ¬ Rope.Length[formatting];
textLength ¬ Rope.Length[text] + 1; -- + 1 for newline at end
20 below is the length of the combined fixed parts of everthing between the two @'s: the newlines, the lengths, and the space.
itemLength ¬ 20 + Rope.Length[msgID] + Rope.Length[msgSet] + Rope.Length[formatting];
8+15+2 is the length of the stuff before the first @, plus the 2 @'s.
prefixLength ¬ 8 + 16 + 2 + itemLength;
length ¬ prefixLength + textLength;
IO.PutF1[outstream, "%g\n", IO.rope["*start*"]];
IO.PutF[outstream, "%05g %05g US \n", IO.int[length], IO.int[prefixLength]];
IO.PutF[outstream, "@%05g 00525 %05g\n", IO.int[itemLength], IO.int[formatLength]];
IO.PutF1[outstream, "%g\n", IO.rope[msgID]];
IO.PutF1[outstream, "%g\n", IO.rope[msgSet]];
IO.PutF1[outstream, "%g\n", IO.rope[formatting]];
IO.PutF1[outstream, "@%g\n", IO.rope[text]];
};
Private Procedures
GetContents: PROC [root: TextNode.Ref] RETURNS [text, formatting: ROPE] ~ {
pair: TiogaIO.Pair ¬ TiogaIO.ToPair[root];
RETURN[
text: pair.contents,
formatting: pair.formatting
];
};
MinLoc: PROC [loc1, loc2: TiogaOps.Location] RETURNS [minloc: TiogaOps.Location] ~ {
IF loc1.node = NIL THEN minloc ¬ loc2
ELSE IF loc2.node = NIL THEN minloc ¬ loc1
ELSE IF TiogaOps.CompareLocOrder[loc1, loc2] = before THEN minloc ¬ loc1 ELSE minloc ¬ loc2;
RETURN [minloc];
};
CurrentDate: PROC [] RETURNS [date: ROPE] ~ {
time: BasicTime.ExtendedGMT ¬ BasicTime.ExtendedNow[];
date ¬ Convert.RopeFromTime[from: time.gmt, end: seconds];
date ¬ Rope.Cat[date, ":", Convert.RopeFromInt[time.usecs]];
};
BuildMsgId: PROC [uniquifier: ROPE] RETURNS [msgId: ROPE] ~ {
date: ROPE = CurrentDate[];
msgId ¬ IO.PutFR["$ TiogaToWalnutServer:%g:PARCXerox@%g", IO.rope[uniquifier], IO.rope[date]];
RETURN [msgId];
};
Commander Proc
Form of command is:
TiogaToWalnut [-xpvx] archiveFileName ← tiogaFileName msgSetName
TiogaToWalnutCmd: Commander.CommandProc ~ {
cmdin: IO.STREAM = IO.RIS[cmd.commandLine];
outstream: IO.STREAM;
r, startnode: TextNode.Ref;
count: INT;
text, formatting, archiveName, tiogaFile, msgSetName, leftArrow, name, msgId, arg, uniquifier, date: ROPE;
DoCheckOnly: BOOL ¬ FALSE;
PeanutFormat: BOOL ¬ FALSE;
Verbose: BOOL ¬ FALSE;
accessType: PFS.AccessOptions ¬ create;
{
parse arguments
arg ¬ IO.GetTokenRope[cmdin, IO.IDProc ! IO.Error, IO.EndOfStream => { GOTO formatfailure;}].token;
WHILE Rope.Fetch[arg,0] = '- DO
These are flags
flags: ROPE ¬ arg;
l: INT ¬ Rope.Length[flags];
pos: INT;
CedarProcess.CheckAbort[];
Eliminate negative items
WHILE (pos ¬ Rope.SkipTo[flags, 0, "~"]) < l DO
flags ¬ Rope.Replace[flags, pos, 2, NIL];
ENDLOOP;
Search for positive items
IF Rope.SkipTo[flags, 0, "a"] < l THEN accessType ¬ append;
IF Rope.SkipTo[flags, 0, "x"] < l THEN DoCheckOnly ¬ TRUE;
IF Rope.SkipTo[flags, 0, "p"] < l THEN PeanutFormat ¬ TRUE;
IF Rope.SkipTo[flags, 0, "v"] < l THEN Verbose ¬ TRUE;
arg ¬ IO.GetTokenRope[cmdin, IO.IDProc ! IO.Error, IO.EndOfStream => { GOTO formatfailure;}].token;
ENDLOOP;
archiveName ¬ arg;
leftArrow ¬ IO.GetTokenRope[cmdin, IO.IDProc ! IO.Error, IO.EndOfStream => { GOTO formatfailure;}].token;
IF NOT Rope.Equal[leftArrow, "←"] THEN GOTO formatfailure;
tiogaFile ¬ IO.GetTokenRope[cmdin, IO.IDProc ! IO.Error, IO.EndOfStream => { GOTO formatfailure;}].token;
msgSetName ¬ IO.GetTokenRope[cmdin, IO.IDProc ! IO.Error, IO.EndOfStream => { GOTO formatfailure;}].token;
Open files
IF DoCheckOnly
THEN {
outstream ¬ IO.noWhereStream;
}
ELSE {
outstream ¬ PFS.StreamOpen[PFS.PathFromRope[archiveName], accessType ! PFS.Error =>
IF error.group = user THEN {IO.PutF1[cmd.out, "%g\n", IO.rope[error.explanation]]; name ¬ archiveName; GOTO iofailure;}];
};
startnode ¬ TiogaExtraOps.GetFile[tiogaFile ! PFS.Error, IO.Error, IO.EndOfStream => { name ¬ tiogaFile; GOTO iofailure;}];
skip the root for peanut format so we get the top level nodes individually
IF PeanutFormat THEN startnode ¬ TextNode.Forward[startnode].nx;
Startnode now points to the root node, or the first peanut mail message. Process this and subsequent items at the same level
count ¬ 0;
WHILE startnode # NIL DO
CedarProcess.CheckAbort[];
uniquifier ¬ IO.PutR[IO.rope[tiogaFile], IO.int[count]];
msgId ¬ BuildMsgId[uniquifier];
[text, formatting] ¬ TiogaToWalnut.GetContentsOfNodeAndChildren[startnode];
TiogaToWalnut.ContentsToArchive[text, formatting, msgSetName, msgId, outstream];
startnode ¬ TextNode.ForwardClipped[startnode, 1, 1].nx;
count ¬ count + 1;
IF Verbose AND (count MOD 10) = 0 THEN {
IF (count MOD 100) = 0
THEN IO.Put1[cmd.out, IO.int[count]]
ELSE IO.Put1[cmd.out, IO.rope["~"]];
};
ENDLOOP;
TiogaExtraOps.FreeTree[r];
IO.Close[outstream];
IF Verbose THEN IO.PutF[cmd.out, "Finished %g msgs in %g.\n", IO.int[count], IO.rope[tiogaFile]];
EXITS
iofailure => IO.PutF1[cmd.err, "Could not open file named '%g'.\n", IO.rope[name]];
formatfailure => IO.PutF1[cmd.err, "%g\n", IO.rope[Explanation]];
}
};
Initialization
Commander.Register["TiogaToWalnut", TiogaToWalnutCmd, Explanation];
END.