<<>> <> <> <> <> <<>> 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 <> 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 "; <> GetContentsOfNodeAndChildren: PUBLIC PROC [node: TextNode.Ref] RETURNS [text, formatting: ROPE] ~ { root, endnode, tmpnode: TiogaOps.Ref; newspan, span: TextNode.Span; level: INT; <> 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; <> 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; <> IF msgID = NIL THEN { msgID ¬ BuildMsgId[msgSet]; }; <> 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]]; }; <> 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]; }; <> <
> <> 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; { <> arg ¬ IO.GetTokenRope[cmdin, IO.IDProc ! IO.Error, IO.EndOfStream => { GOTO formatfailure;}].token; WHILE Rope.Fetch[arg,0] = '- DO <> flags: ROPE ¬ arg; l: INT ¬ Rope.Length[flags]; pos: INT; CedarProcess.CheckAbort[]; <> WHILE (pos ¬ Rope.SkipTo[flags, 0, "~"]) < l DO flags ¬ Rope.Replace[flags, pos, 2, NIL]; ENDLOOP; <> 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; <> 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;}]; <> IF PeanutFormat THEN startnode ¬ TextNode.Forward[startnode].nx; <<>> <> 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]]; } }; <> Commander.Register["TiogaToWalnut", TiogaToWalnutCmd, Explanation]; END.