<> <> <> <> <> DIRECTORY Commander, Basics, Rope, FS, IO, PressFormat, PressFileUtilities, UserProfile, TSViewer, PressPrinter; PressFileUtilitiesImpl: CEDAR PROGRAM IMPORTS Commander, FS, IO, Rope, UserProfile, TSViewer, PressPrinter EXPORTS PressFileUtilities ~ BEGIN Bad: ERROR ~ CODE; bytesPerPressPage: INT ~ 512; bytesPerWord: INT ~ Basics.bytesPerWord; PageRange: TYPE ~ PressFileUtilities.PageRange; ROPE: TYPE ~ Rope.ROPE; SpecError: PUBLIC ERROR [offset: INT] ~ CODE; RopeFromInt: PROC [int: INT] RETURNS [ROPE] ~ { RETURN [SELECT ABS[int] FROM 0 => "0", 1 => "1", 2 => "2", 3 => "3", 4 => "4", 5 => "5", 6 => "6", 7 => "7", 8 => "8", 9 => "9", ENDCASE => RopeFromInt[ABS[int]/10].Concat[RopeFromInt[ABS[int] MOD 10]] ]; }; ParsePageSpec: PUBLIC PROC [pageSpecRope: ROPE] RETURNS [pageSpec: LIST OF PageRange, charsParsed: INT] ~ { text: REF TEXT ~ pageSpecRope.ToRefText; i: NAT _ 0; c: CHAR; SkipSpaces: PROC ~ {c _ ' ; WHILE i < text.length AND ((c _ text[i]) = ', OR c = ' OR c = ' OR c = '\n) DO i _ i+1 ENDLOOP}; GetChar: PROC RETURNS [CHAR] ~ {IF i < text.length THEN {i _ i+1; RETURN [text[i-1]]} ELSE RETURN ['\000]}; Int: PROC RETURNS [value: INT_0] ~ { SkipSpaces[]; IF NOT c IN ['0..'9] THEN ERROR SpecError[i]; WHILE i < text.length AND (c _ text[i]) IN ['0..'9] DO value _ value * 10 + (c-'0); i _ i+1; ENDLOOP; }; spec: LIST OF PageRange _ NIL; SkipSpaces[]; WHILE i < text.length DO SELECT text[i] FROM IN ['0..'9] => spec _ CONS[[Int[], 1], spec]; '[, '( => { open: CHAR _ GetChar[]; start: INT _ Int[]; end: INT; SkipSpaces[]; IF i < text.length AND text[i] = '. THEN i _ i+1 ELSE ERROR SpecError[i]; IF i < text.length AND text[i] = '. THEN i _ i+1 ELSE ERROR SpecError[i]; end _ Int[]; SkipSpaces[]; IF (c _ GetChar[]) = '] OR c = ') THEN { IF open = '( THEN start _ start + 1; IF c = '] THEN end _ end + 1; IF end > start THEN spec _ CONS[[start, end-start], spec] } ELSE ERROR SpecError[i]; }; ENDCASE => EXIT; SkipSpaces[]; ENDLOOP; RETURN [Reverse[spec], i] }; Reverse: PROC [pageSpec: LIST OF PageRange] RETURNS [reversed: LIST OF PageRange] ~ { WHILE pageSpec # NIL DO t: LIST OF PageRange _ pageSpec; pageSpec _ t.rest; t.rest _ reversed; reversed _ t; ENDLOOP; }; ExtractPages: PUBLIC PROC [inputFile, outputFile: ROPE, pageSpec: LIST OF PageRange] RETURNS [success: BOOLEAN] ~ TRUSTED { input: IO.STREAM _ FS.StreamOpen[fileName: inputFile ! FS.Error => GOTO Quit]; output: IO.STREAM _ FS.StreamOpen[fileName: outputFile, accessOptions: create, keep: 2]; documentDirectory: REF PressFormat.DDV _ ReadDirectory[input ! Bad => GOTO Quit]; pdStartByte: INT _ documentDirectory.pdStart*bytesPerPressPage; pdLength: INT _ documentDirectory.pdRecs*bytesPerPressPage; numberOfParts: INT _ documentDirectory.nParts; ReadPart: PROC [n: INT] RETURNS [partEntry: PressFormat.PE] ~ TRUSTED { dest: LONG POINTER _ @partEntry; input.SetIndex[pdStartByte + n*bytesPerWord*SIZE[PressFormat.PE]]; [] _ input.UnsafeGetBlock[block: [base: dest, startIndex: 0, count: bytesPerWord*SIZE[PressFormat.PE]]]; }; page: INT _ 0; outputPart: INT _ 0; outputParts: REF ARRAY [0..960) OF PressFormat.PE _ NEW[ARRAY [0..960) OF PressFormat.PE]; buf: REF TEXT _ NEW[TEXT[bytesPerPressPage]]; CopyBlocks: PROC [nBlocks: INT] ~ CHECKED { buf.length _ bytesPerPressPage; THROUGH [0..nBlocks) DO IF input.GetBlock[buf] # bytesPerPressPage THEN ERROR; output.PutBlock[buf]; ENDLOOP; }; success _ FALSE; WHILE pageSpec # NIL DO FOR i: INT IN [0..numberOfParts) DO partEntry: PressFormat.PE _ ReadPart[i]; IF partEntry.Type = PressFormat.PETypeFont AND pageSpec.rest = NIL THEN { outputParts[outputPart] _ [partEntry.Type, output.GetIndex/bytesPerPressPage, partEntry.pRecs, partEntry.Padding]; outputPart _ outputPart + 1; input.SetIndex[partEntry.pStart*bytesPerPressPage]; CopyBlocks[partEntry.pRecs]; } ELSE IF partEntry.Type = PressFormat.PETypePage THEN { page _ page + 1; IF page > pageSpec.first.startPage + pageSpec.first.nPages AND pageSpec.rest # NIL AND page <= pageSpec.rest.first.startPage THEN pageSpec _ pageSpec.rest; IF page IN [pageSpec.first.startPage..pageSpec.first.startPage + pageSpec.first.nPages) THEN { success _ TRUE; outputParts[outputPart] _ [partEntry.Type, output.GetIndex/bytesPerPressPage, partEntry.pRecs, partEntry.Padding]; outputPart _ outputPart + 1; input.SetIndex[partEntry.pStart*bytesPerPressPage]; CopyBlocks[partEntry.pRecs]; } }; ENDLOOP; pageSpec _ pageSpec.rest; ENDLOOP; documentDirectory.pdStart _ output.GetIndex/bytesPerPressPage; documentDirectory.pdRecs _ (outputPart*bytesPerWord*SIZE[PressFormat.PE] + bytesPerPressPage - 1)/bytesPerPressPage; documentDirectory.nRecs _ documentDirectory.pdStart+documentDirectory.pdRecs+1; documentDirectory.nParts _ outputPart; documentDirectory.fPage _ documentDirectory.lPage _ LAST[CARDINAL]; documentDirectory.Backp _ 0; output.UnsafePutBlock[block: [base: LOOPHOLE[@(outputParts[0])], startIndex: 0, count: documentDirectory.pdRecs*bytesPerPressPage]]; output.UnsafePutBlock[block: [base: LOOPHOLE[documentDirectory], startIndex: 0, count: bytesPerWord*SIZE[PressFormat.DDV]]]; UNTIL output.GetLength MOD bytesPerPressPage = 0 DO output.PutChar['\000] ENDLOOP; input.Close; output.Close; EXITS Quit => success _ FALSE; }; ddvSize: INT _ SIZE[PressFormat.DDV]; ReadDirectory: PROC [input: IO.STREAM] RETURNS [REF PressFormat.DDV] ~ TRUSTED { ddv: REF PressFormat.DDV _ NEW[PressFormat.DDV]; fileLength: INT _ input.GetLength; IF fileLength MOD bytesPerPressPage # 0 THEN ERROR Bad; IF fileLength < bytesPerPressPage THEN ERROR Bad; input.SetIndex[fileLength-bytesPerPressPage]; [] _ input.UnsafeGetBlock[block: [base: LOOPHOLE[ddv], startIndex: 0, count: bytesPerWord*SIZE[PressFormat.DDV]]]; IF ddv.Passwd # PressFormat.PressPasswd THEN ERROR Bad; IF ddv.nRecs*bytesPerPressPage # fileLength THEN ERROR Bad; RETURN [ddv]; }; InsertPageNumberIntoName: PROC [inputFile: ROPE, number: INT, lastNumber: INT _ LAST[INT]] RETURNS [result: ROPE] ~ { cp: FS.ComponentPositions; fullName: ROPE; [fullName, cp] _ FS.ExpandName[inputFile]; IF cp.server.length > 0 THEN { [fullName, cp] _ FS.ExpandName[fullName.Substr[cp.base.start, cp.ext.start+cp.ext.length-cp.base.start]]; }; result _ fullName.Substr[0, cp.base.start+cp.base.length].Concat["-Page"]; IF lastNumber = LAST[INT] THEN result _ result.Cat[RopeFromInt[number], ".press"] ELSE result _ result.Cat[RopeFromInt[number], "of", RopeFromInt[lastNumber], ".press"] }; BreakIntoSinglePages: PUBLIC PROC [inputFile: ROPE, message: IO.STREAM _ NIL] ~ { page: INT _ 1; input: IO.STREAM _ FS.StreamOpen[fileName: inputFile ! FS.Error => GOTO Quit]; documentDirectory: REF PressFormat.DDV _ ReadDirectory[input ! Bad => GOTO Quit]; numberOfPages: INT _ documentDirectory.nParts - 1; -- don't include font part outputName: ROPE _ InsertPageNumberIntoName[inputFile, page, numberOfPages]; IF message # NIL THEN message.PutRope["Writing"]; WHILE page <= numberOfPages AND ExtractPages[inputFile, outputName, LIST[[page,1]]] DO IF message # NIL THEN {message.PutChar[' ]; message.PutRope[outputName]}; page _ page + 1; outputName _ InsertPageNumberIntoName[inputFile, page, numberOfPages]; ENDLOOP; message.PutChar['\n]; EXITS Quit => RETURN; }; SendSinglePages: PUBLIC PROC [server: Rope.ROPE, inputFile: Rope.ROPE, pageSpec: LIST OF PageRange, message: IO.STREAM _ NIL] ~ TRUSTED { tool: TSViewer.Tool _ TSViewer.NewTool[server, (IF message = NIL THEN IO.noWhereStream ELSE message)]; IF NOT PressPrinter.IsAPressFile[inputFile] THEN { message.PutRope[inputFile]; message.PutRope[" is not a press file\n"]; RETURN; }; FOR pageRangeList: LIST OF PageRange _ pageSpec, pageRangeList.rest UNTIL pageRangeList = NIL DO pageRange: PageRange _ pageRangeList.first; FOR page: INT IN [pageRange.startPage..pageRange.startPage+pageRange.nPages) DO tempName: ROPE _ InsertPageNumberIntoName[inputFile, page].Concat["$"]; IF NOT ExtractPages[inputFile, tempName, LIST[[page,1]]] THEN EXIT; IF message # NIL THEN { message.PutRope[tempName]; message.PutRope[" written\n"]; }; TSViewer.WaitForIdle[tool]; TSViewer.QueueRequest[tool, tempName]; TSViewer.Print[tool]; ENDLOOP; ENDLOOP; }; Break: PROC [char: CHAR] RETURNS [IO.CharClass] = { IF char = '_ THEN RETURN [break]; IF char = ' OR char = ' OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr]; RETURN [other]; }; GetToken: PROC [stream: IO.STREAM] RETURNS [token: ROPE _ NIL] = { token _ stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token; }; PressExtractCommand: Commander.CommandProc ~ { stream: IO.STREAM _ IO.RIS[cmd.commandLine]; outputName: ROPE _ GetToken[stream]; inputName: ROPE; pagesToken: ROPE; pageSpec: LIST OF PageRange; IF outputName.Length = 0 THEN {cmd.out.PutRope["Output file missing.\n"]; RETURN}; IF NOT GetToken[stream].Equal["_"] THEN {cmd.out.PutRope["Missing \"_\".\n"]; RETURN}; inputName _ GetToken[stream]; pagesToken _ GetToken[stream]; IF pagesToken.Equal["PAGE", FALSE] OR pagesToken.Equal["PAGES", FALSE] THEN { skip: INT; [pageSpec, skip] _ ParsePageSpec[cmd.commandLine.Substr[stream.GetIndex]]; stream.SetIndex[stream.GetIndex+skip]; } ELSE pageSpec _ LIST[[1, 1000000]]; IF NOT ExtractPages[inputName, outputName, pageSpec] THEN { cmd.out.PutRope["Unable to extract any pages from "]; cmd.out.PutRope[inputName]; cmd.out.PutChar['\n]; } ELSE {cmd.out.PutRope[outputName]; cmd.out.PutRope[" Written.\n"]}; IF NOT stream.EndOf THEN {cmd.out.PutRope["Ignored: "]; cmd.out.PutRope[cmd.commandLine.Substr[stream.GetIndex]]; cmd.out.PutChar['\n]}; }; PressPagesCommand: Commander.CommandProc ~ { stream: IO.STREAM _ IO.RIS[cmd.commandLine]; inputName: ROPE _ GetToken[stream]; IF inputName = NIL THEN cmd.out.PutRope["Please supply a file name.\n"] ELSE BreakIntoSinglePages[inputName, cmd.out]; }; SendSinglePagesCommand: Commander.CommandProc ~ { stream: IO.STREAM _ IO.RIS[cmd.commandLine]; pageSpec: LIST OF PageRange _ LIST[[1, 1000000]]; inputName: ROPE _ GetToken[stream]; token: ROPE _ GetToken[stream]; server: ROPE _ NIL; WHILE token # NIL DO IF token.Equal["PAGE", FALSE] OR token.Equal["PAGES", FALSE] THEN { skip: INT; [pageSpec, skip] _ ParsePageSpec[cmd.commandLine.Substr[stream.GetIndex]]; stream.SetIndex[stream.GetIndex+skip]; } ELSE IF token.Equal["TO", FALSE] THEN server _ GetToken[stream] ELSE {cmd.out.PutRope["Unknown keyword: "]; cmd.out.PutRope[token]; RETURN}; token _ GetToken[stream]; ENDLOOP; IF server = NIL THEN server _ UserProfile.Token["Hardcopy.PressPrinter", "Clover"]; IF inputName = NIL THEN cmd.out.PutRope["Please supply a file name.\n"] ELSE SendSinglePages[server, inputName, pageSpec, cmd.out]; }; Commander.Register["PressExtract", PressExtractCommand, "Extract pages from press files, e.g. result.press _ myPress.press PAGES 1, 3, [10..15]"]; <> <<>> Commander.Register["PressPages", PressPagesCommand, "Break a press file into single-page press files"]; Commander.Register["SendSinglePages", SendSinglePagesCommand, "Send single pages to a server, e.g., SendSinglePages myPress.press PAGES 1, 3, [10..15] TO RockNRoll"]; END.