<> <> <> <> <<>> <> <> <<>> DIRECTORY Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Parse], Convert USING [RopeFromInt], FS USING [ComponentPositions, Copy, Delete, Error, ExpandName, FileInfo], Imager USING [Context], ImagerInterpress USING [Close, Create, DoPage, Ref], Interpress USING [Close, DoPage, Master, Open], IO, Rope USING [Cat, Concat, Equal, Length, ROPE, Substr, ToRefText]; InterpressPageImpl: CEDAR PROGRAM IMPORTS Commander, CommandTool, Convert, FS, ImagerInterpress, Interpress, IO, Rope ~ BEGIN <> ROPE: TYPE ~ Rope.ROPE; <> CmdTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = { IF char = '_ THEN RETURN [break]; IF char = ' OR char = '\t OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr]; RETURN [other]; }; GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE] = { rope _ NIL; rope _ stream.GetTokenRope[CmdTokenBreak ! IO.EndOfStream => CONTINUE].token; }; ExpandedName: TYPE ~ RECORD [fullFName: ROPE, cp: FS.ComponentPositions]; ExpandName: PROC [inputName: ROPE] RETURNS [e: ExpandedName] ~ INLINE { [e.fullFName, e.cp] _ FS.ExpandName[inputName]; }; <> PageRange: TYPE ~ RECORD [startPage, nPages: INT]; SpecError: PUBLIC ERROR [offset: INT] ~ CODE; DoExtract: PUBLIC PROC [inputFile, outputFile: ROPE, pageSpec: LIST OF PageRange, log: IO.STREAM] RETURNS [success: BOOLEAN _ TRUE] ~ { logProc: PROC [class: INT, code: ATOM, explanation: ROPE] ~ { IO.PutRope[log, "\n *** Interpress Error "]; IO.PutRope[log, explanation]; success _ FALSE; }; n: ExpandedName ~ ExpandName[FS.FileInfo[inputFile].fullFName]; master: Interpress.Master ~ Interpress.Open[n.fullFName, logProc]; out: ImagerInterpress.Ref ~ ImagerInterpress.Create[outputFile]; IO.PutRope[log, "Reading "]; IO.PutRope[log, n.fullFName]; IO.PutRope[log, " . . . "]; FOR each: LIST OF PageRange _ pageSpec, each.rest UNTIL each=NIL DO pageRange: PageRange ~ each.first; FOR i: INT IN [pageRange.startPage..MIN[pageRange.startPage+pageRange.nPages-1, master.pages]] DO OnePage: PROC [context: Imager.Context] ~ {Interpress.DoPage[master, i, context, logProc]}; IO.PutF[stream: log, format: " [%g", v1: [integer[i]]]; ImagerInterpress.DoPage[out, OnePage]; IO.PutRope[self: log, r: "]"]; ENDLOOP; ENDLOOP; ImagerInterpress.Close[out]; IO.PutRope[log, " written.\n"]; }; InterpressExtractCommand: Commander.CommandProc ~ { GetToken: PROC [stream: IO.STREAM] RETURNS [token: ROPE _ NIL] = { 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]; }; token _ stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token; }; ParsePageSpec: PUBLIC PROC [pageSpecRope: ROPE] RETURNS [pageSpec: LIST OF PageRange, charsParsed: INT] ~ { 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; }; 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] }; 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 DoExtract[inputName, outputName, pageSpec, cmd.out] 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]}; }; <> BreakupStyle: TYPE ~ {pageCount, numFiles}; DoBreakup: PROC [inputName: ROPE, log: IO.STREAM, style: BreakupStyle, div: INT] ~ { logProc: PROC [class: INT, code: ATOM, explanation: ROPE] ~ { IO.PutRope[log, "\n *** Interpress Error "]; IO.PutRope[log, explanation]; }; n: ExpandedName ~ ExpandName[FS.FileInfo[inputName].fullFName]; base: ROPE ~ Rope.Substr[n.fullFName, n.cp.base.start, n.cp.base.length]; ext: ROPE ~ Rope.Substr[n.fullFName, n.cp.ext.start, n.cp.ext.length]; logPages: BOOL ~ div#1 OR style#pageCount; master: Interpress.Master; nFiles, j: INT _ 0; IO.PutRope[log, "Reading "]; IO.PutRope[log, n.fullFName]; IO.PutRope[log, " . . . "]; master _ Interpress.Open[n.fullFName, logProc]; IO.PutF[log, IF logPages THEN " %g pages\n" ELSE " %g pages; ", [integer[master.pages]]]; SELECT style FROM pageCount => nFiles _ (master.pages+div-1)/div; numFiles => nFiles _ div; ENDCASE => ERROR; FOR i: INT IN [1..nFiles] DO lim: INT ~ SELECT style FROM pageCount => MIN[j+div, master.pages], numFiles => (i*master.pages + div/2)/div, ENDCASE => ERROR; name: ROPE ~ Rope.Cat[base, "-", Convert.RopeFromInt[i], ".", ext]; out: ImagerInterpress.Ref ~ ImagerInterpress.Create[name]; IO.PutRope[log, FS.ExpandName[name].fullFName]; WHILE j GOTO SyntaxError]; IF div<=0 THEN RETURN [result: $Failure, msg: IO.PutFR["Must divide by a positive number of pages, not %g", [integer[div]] ]]; inputName _ GetCmdToken[stream !IO.Error => GOTO SyntaxError]; } ELSE IF inputName.Equal["-into"] THEN { style _ numFiles; div _ stream.GetInt[!IO.Error => GOTO SyntaxError]; IF div<=1 THEN RETURN [result: $Failure, msg: IO.PutFR["Number of output files must be greater than 1, not %g", [integer[div]] ]]; inputName _ GetCmdToken[stream !IO.Error => GOTO SyntaxError]; }; IF inputName = NIL THEN GOTO SyntaxError; DoBreakup[inputName, cmd.out, style, div ! FS.Error => IF error.group = user THEN {result _ $Failure; msg _ error.explanation; CONTINUE}]; EXITS SyntaxError => RETURN[result: $Failure, msg: cmd.procData.doc]}; <> DoConcatenate: PROC [outputName: ROPE, cmdLineStream: IO.STREAM, log: IO.STREAM] ~ { pageNumber: INT _ 0; logProc: PROC [class: INT, code: ATOM, explanation: ROPE] ~ { IO.PutRope[log, "\n *** Interpress Error "]; IO.PutRope[log, explanation]; }; n: ExpandedName ~ ExpandName[outputName]; extendedName: ROPE ~ IF n.cp.ext.length = 0 THEN Rope.Substr[n.fullFName, 0, n.cp.base.start+n.cp.base.length].Concat[".interpress"] ELSE n.fullFName; tempName: ROPE _ Rope.Cat["/vux/tmp/", Rope.Substr[n.fullFName, 0, n.cp.base.start+n.cp.base.length], ".interpress"]; <> out: ImagerInterpress.Ref ~ ImagerInterpress.Create[tempName]; IO.PutRope[log, "Reading "]; FOR inputName: ROPE _ GetCmdToken[cmdLineStream], GetCmdToken[cmdLineStream] UNTIL inputName = NIL DO fullInputName: ROPE ~ FS.FileInfo[inputName].fullFName; master: Interpress.Master ~ Interpress.Open[fullInputName, logProc]; IO.PutRope[log, fullInputName]; IO.PutRope[log, " "]; FOR i: INT IN [1..master.pages] DO onePage: PROC [context: Imager.Context] ~ {Interpress.DoPage[master, i, context, logProc]}; IO.PutRope[log, "["]; IO.PutRope[log, Convert.RopeFromInt[pageNumber _ pageNumber + 1]]; ImagerInterpress.DoPage[out, onePage]; IO.PutRope[log, "] "]; ENDLOOP; ENDLOOP; ImagerInterpress.Close[out]; [] _ FS.Copy[from: tempName, to: extendedName]; FS.Delete[tempName]; IO.PutRope[log, FS.FileInfo[extendedName].fullFName]; IO.PutRope[log, " written.\n"]; }; InterpressConcatenateCommand: Commander.CommandProc ~ { stream: IO.STREAM _ IO.RIS[cmd.commandLine]; outputName: ROPE _ GetCmdToken[stream]; gets: ROPE _ GetCmdToken[stream]; IF outputName = NIL OR NOT gets.Equal["_"] THEN RETURN[result: $Failure, msg: cmd.procData.doc]; DoConcatenate[outputName, stream, cmd.out ! FS.Error => IF error.group = user THEN {result _ $Failure; msg _ error.explanation; CONTINUE}]; }; <> InterpressLS: Commander.CommandProc ~ { ENABLE FS.Error => IF error.group = user THEN {result _ $Failure; msg _ error.explanation; CONTINUE}; log: IO.STREAM ~ cmd.out; args: CommandTool.ArgumentVector ~ CommandTool.Parse[cmd: cmd, starExpand: TRUE]; logProc: PROC [class: INT, code: ATOM, explanation: ROPE] ~ { IO.PutRope[log, "\n *** Interpress Error "]; IO.PutRope[log, explanation]; }; FOR i: NAT IN [1 .. args.argc) DO name: ROPE ~ args[i]; fullInputName: ROPE ~ FS.FileInfo[name].fullFName; master: Interpress.Master; IO.PutF[log, "%g... ", [rope[fullInputName]]]; master _ Interpress.Open[fullInputName, logProc]; IO.PutF[log, " %g pages\n", [integer[master.pages]]]; Interpress.Close[master]; ENDLOOP; }; <> Commander.Register[key: "InterpressExtract", proc: InterpressExtractCommand, doc: "Extract pages from interpress files, e.g. result.ip _ source.ip PAGES 1, 3, [10..15]"]; Commander.Register[key: "IPExtract", proc: InterpressExtractCommand, doc: "Extract pages from interpress files, e.g. result.ip _ source.ip PAGES 1, 3, [10..15] (alias for InterpressExtract)"]; Commander.Register[key: "InterpressBreakup", proc: InterpressBreakupCommand, doc: "Breaks an interpress master into a collection of masters: InterpressBreakup [-by | -into ] "]; Commander.Register[key: "IPBreakup", proc: InterpressBreakupCommand, doc: "Breaks an interpress master into a collection of masters (alias for InterpressBreakup)"]; Commander.Register[key: "InterpressConcatenate", proc: InterpressConcatenateCommand, doc: "Concatenates a collection of Interpress masters into one. (output _ input1 input2 . . .)"]; Commander.Register[key: "IPConcatenate", proc: InterpressConcatenateCommand, doc: "Concatenates a collection of Interpress masters into one. (output _ input1 input2 . . .) (alias for InterpressConcatenate)"]; Commander.Register[key: "InterpressLS", proc: InterpressLS, doc: "List page count of files, e.g. InterpressLS foo.ip bar.ip"]; Commander.Register[key: "IPLS", proc: InterpressLS, doc: "List page count of files (alias for InterpressLS)"]; END.