<> <> <> <<>> DIRECTORY Commander USING [CommandProc, Register], CommandTool USING [ParseToList], Convert USING [RopeFromInt], FS USING [StreamOpen], IO USING [Close, EndOfStream, GetChar, PutChar, STREAM], Rope USING [Cat, Find, ROPE, Substr], UserProfile USING [Number] ; Split: CEDAR PROGRAM IMPORTS Commander, CommandTool, Convert, FS, IO, Rope, UserProfile = BEGIN ROPE: TYPE ~ Rope.ROPE; splitDefaultSize: INT ~ 179968; HeadAndTail: PROC [file: ROPE] RETURNS [head, tail: ROPE] ~ { pos: INT ~ Rope.Find[file, "."]; IF pos=-1 THEN RETURN [file, NIL]; head _ Rope.Substr[base: file, len: pos]; tail _ Rope.Substr[base: file, start: pos]; }; PadWithNulls: PROC [s: IO.STREAM, alreadyIn: INT] ~ { padTo: INT ~ UserProfile.Number["Split.Pad", -1]; IF padTo<0 THEN RETURN; THROUGH ((alreadyIn-1) MOD padTo..padTo) DO IO.PutChar[s, '\000]; ENDLOOP; }; SplitCmd: Commander.CommandProc ~ { files: LIST OF ROPE ~ CommandTool.ParseToList[cmd].list; size: INT ~ UserProfile.Number["Split.Size", splitDefaultSize]; from, to: IO.STREAM; byteCount: INT; FOR each: LIST OF ROPE _ files, each.rest UNTIL each=NIL DO ENABLE IO.EndOfStream => {PadWithNulls[to, byteCount]; IO.Close[to]; IO.Close[from]; LOOP}; file: ROPE ~ each.first; segmentNumber: INT _ 1; head, tail: ROPE; from _ FS.StreamOpen[file]; [head, tail] _ HeadAndTail[file]; DO to _ FS.StreamOpen[Rope.Cat[head, "-", Convert.RopeFromInt[segmentNumber], tail], create]; byteCount _ 0; THROUGH [1..size] DO IO.PutChar[to, IO.GetChar[from]]; byteCount _ byteCount+1; ENDLOOP; segmentNumber _ segmentNumber+1; IO.Close[to]; ENDLOOP; ENDLOOP; }; Init: PROC ~ { Commander.Register[key: "Split", proc: SplitCmd, doc: "Splits a file into a number of file."]; }; Init[]; END.