<<>> <> <> <> <> <> <<>> <> <<>> DIRECTORY Commander, CommanderOps, Convert, FS, Imager, ImagerInterpress, ImagerTransformation, InterpressInterpreter, IO, Rope, ProcessProps, RasterEncodingStandardIO, ImagerRES; InterpressPageImpl: CEDAR PROGRAM IMPORTS Commander, CommanderOps, Convert, FS, Imager, ImagerInterpress, ImagerTransformation, InterpressInterpreter, IO, Rope, ProcessProps, RasterEncodingStandardIO, ImagerRES ~ 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: InterpressInterpreter.LogProc ~ { IO.PutRope[log, "\n *** Interpress Error "]; IO.PutRope[log, explanation]; success ¬ FALSE; }; n: ExpandedName ~ ExpandName[FS.FileInfo[inputFile].fullFName]; master: InterpressInterpreter.Master ~ InterpressInterpreter.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] ~ {InterpressInterpreter.DoPage[master, i, context, logProc]}; IO.PutF1[log, " [%g", [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: InterpressInterpreter.LogProc ~ { 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: InterpressInterpreter.Master; nFiles, j: INT ¬ 0; IO.PutRope[log, "Reading "]; IO.PutRope[log, n.fullFName]; IO.PutRope[log, " . . . "]; master ¬ InterpressInterpreter.Open[n.fullFName, logProc]; IO.PutF1[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 CommanderOps.Failed[cmd.procData.doc]; FS.Error => IF error.group = user THEN CommanderOps.Failed[error.explanation]; }; style: BreakupStyle ¬ pageCount; div: INT ¬ 1; inputName: ROPE ¬ CommanderOps.NextArgument[cmd]; IF inputName.Equal["-by"] THEN { div ¬ Convert.IntFromRope[CommanderOps.NextArgument[cmd]]; IF div<=0 THEN RETURN [result: $Failure, msg: IO.PutFR1["Must divide by a positive number of pages, not %g", [integer[div]] ]]; inputName ¬ CommanderOps.NextArgument[cmd]; } ELSE IF inputName.Equal["-into"] THEN { style ¬ numFiles; div ¬ Convert.IntFromRope[CommanderOps.NextArgument[cmd]]; IF div<=1 THEN RETURN [result: $Failure, msg: IO.PutFR1["Number of output files must be greater than 1, not %g", [integer[div]] ]]; inputName ¬ CommanderOps.NextArgument[cmd]; }; 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: InterpressInterpreter.LogProc ~ { 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: InterpressInterpreter.Master ~ InterpressInterpreter.Open[fullInputName, logProc]; IO.PutRope[log, fullInputName]; IO.PutRope[log, " "]; FOR i: INT IN [1..master.pages] DO onePage: PROC [context: Imager.Context] ~ {InterpressInterpreter.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["_"] OR 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 CommanderOps.Failed[error.explanation]; log: IO.STREAM ~ cmd.out; args: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd: cmd]; logProc: InterpressInterpreter.LogProc ~ { 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: InterpressInterpreter.Master; IO.PutF1[log, "%g... ", [rope[fullInputName]]]; master ¬ InterpressInterpreter.Open[fullInputName, logProc]; IO.PutF1[log, " %g pages\n", [integer[master.pages]]]; InterpressInterpreter.Close[master]; ENDLOOP; }; InterpressOverlay: PROC [output, input1, input2: ROPE, m: ImagerTransformation.Transformation] ~ { prevMsg: ROPE ¬ NIL; matchCount: INT ¬ 0; Log: InterpressInterpreter.LogProc ~ { WITH ProcessProps.GetProp[$ErrOut] SELECT FROM errOut: IO.STREAM => { IF Rope.Equal[explanation, prevMsg] THEN {matchCount ¬ matchCount + 1} ELSE { IF matchCount > 0 THEN { IO.PutF1[errOut, " (and %g more)\n", IO.int[matchCount]]; }; IO.PutRope[errOut, explanation]; IF explanation # NIL THEN IO.PutChar[errOut, '\n]; prevMsg ¬ explanation; matchCount ¬ 0; }; }; ENDCASE => NULL; }; ref: ImagerInterpress.Ref ~ ImagerInterpress.Create[fileName: output]; master1: InterpressInterpreter.Master ~ InterpressInterpreter.Open[fileName: input1, log: Log]; master2: InterpressInterpreter.Master ~ InterpressInterpreter.Open[fileName: input2, log: Log]; FOR page: INT IN [1..master1.pages] DO WriteAction: PROC [context: Imager.Context] ~ { <> context.SetGray [1]; InterpressInterpreter.DoPage[master: master1, page: page, context: context, log: Log]; Imager.ConcatT[context: context, m: m]; InterpressInterpreter.DoPage[master: master2, page: page2, context: context, log: Log]; }; page2: INT ~ ((page-1) MOD master2.pages)+1; --Cycle through the second master as needed ImagerInterpress.DoPage[self: ref, action: WriteAction]; ENDLOOP; Log[-1, ok, NIL, NIL]; ImagerInterpress.Close[self: ref]; }; InterpressOverlayCmd: Commander.CommandProc ~ { ENABLE FS.Error => IF error.group = user THEN CommanderOps.Failed[error.explanation]; IsIt: PROC [rope: ROPE, parmsNeeded: INT] RETURNS [BOOLEAN] ~ { RETURN [Rope.Equal[rope, tokens[tokenIndex], FALSE] AND tokens.argc > tokenIndex+parmsNeeded]; }; SkipArgs: PROC [args: INT] ~ INLINE {tokenIndex ¬ args+tokenIndex+1}; Real: PROC [index: INT] RETURNS [real: REAL] ~ { RETURN [Convert.RealFromRope[r: tokens[index]]]; }; tokens: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd: cmd]; <> <> <> <> <> <> tokenIndex: INT ¬ 5; --Initialized to start of transformation options m: ImagerTransformation.Transformation ¬ ImagerTransformation.Scale[s: 1]; IF tokens.argc < 5 OR ~Rope.Equal[s1: "_", s2: tokens[2]] THEN CommanderOps.Failed[cmd.procData.doc]; <> WHILE tokenIndex { m ¬ ImagerTransformation.PreTranslate[m: m, t: [Real[tokenIndex+1], Real[tokenIndex+2]]]; SkipArgs[2]; }; IsIt["rotate", 1] => { m ¬ ImagerTransformation.PreRotate[m: m, r: Real[tokenIndex+1]]; SkipArgs[1]; }; IsIt["scale", 1] => { m ¬ ImagerTransformation.PreScale[m: m, s: Real[tokenIndex+1]]; SkipArgs[1]; }; IsIt["scale2", 2] => { m ¬ ImagerTransformation.PreScale2[m: m, s: [Real[tokenIndex+1], Real[tokenIndex+2]]]; SkipArgs[2]; }; ENDCASE => CommanderOps.Failed[cmd.procData.doc]; ENDLOOP; InterpressOverlay[output: tokens[1], input1: tokens[3], input2: tokens[4], m: m]; }; InterpressFromRESAction: PROC [inputName: ROPE, outputName: ROPE, cmd: Commander.Handle, cmds: IO.STREAM] ~ { res: RasterEncodingStandardIO.RES ~ RasterEncodingStandardIO.Read[inputName]; OnePage: PROC [context: Imager.Context] ~ { ImagerRES.ShowRES[context: context, res: res, useImageScale: TRUE]; }; out: ImagerInterpress.Ref ~ ImagerInterpress.Create[outputName]; ImagerInterpress.DoPage[out, OnePage]; ImagerInterpress.Close[out]; }; MakeOutputName: PROC [inputName: ROPE, doc: ROPE] RETURNS [ROPE] ~ { start: INT ¬ Rope.Index[s1: doc, s2: " to "]+4; end: INT ¬ Rope.Index[s1: doc, pos1: start, s2: " "]; space: INT; cp: FS.ComponentPositions; [inputName, cp] ¬ FS.ExpandName[inputName]; space ¬ Rope.Index[s1: Rope.Substr[inputName, cp.base.start, cp.base.length], s2: " "]; -- = cp.base.length if no spaces in the base RETURN [Rope.Cat[Rope.Substr[inputName, cp.base.start, space], ".", Rope.Substr[doc, start, end-start]]] --if spaces were in the base, this uses just the first word }; FindFullName: PROC [inputName: ROPE] RETURNS [ROPE] ~ { fullFName: ROPE ¬ NIL; fullFName ¬ FS.FileInfo[inputName].fullFName; RETURN [fullFName] }; QuotedTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = { IF char = '" THEN RETURN [break]; RETURN [other]; }; GetQuotedToken: PROC [stream: IO.STREAM] RETURNS [ROPE] = { rope: ROPE ¬ NIL; rope ¬ stream.GetTokenRope[QuotedTokenBreak ! IO.EndOfStream => CONTINUE].token; [] ¬ stream.GetTokenRope[QuotedTokenBreak ! IO.EndOfStream => CONTINUE]; --skip over final quote RETURN [rope]; }; InterpressFromRESCommand: Commander.CommandProc ~ { stream: IO.STREAM ¬ IO.RIS[cmd.commandLine]; outputName: ROPE ¬ GetCmdToken[stream]; secondTokenIndex: INT ¬ IO.GetIndex[stream]; gets: ROPE ¬ GetCmdToken[stream]; inputName: ROPE ¬ NIL; IF outputName.Equal["\""] THEN { --reset and do it again, allowing spaces in name stream.SetIndex[secondTokenIndex]; outputName ¬ GetQuotedToken[stream]; secondTokenIndex ¬ IO.GetIndex[stream]; gets ¬ GetCmdToken[stream]; }; IF NOT (gets.Equal["_"] OR gets.Equal["¬"]) THEN { inputName ¬ outputName; outputName ¬ NIL; stream.SetIndex[secondTokenIndex]; } ELSE { inputName ¬ GetCmdToken[stream]; IF inputName.Equal["\""] THEN inputName ¬ GetQuotedToken[stream]; }; IF inputName = NIL THEN RETURN[result: $Failure, msg: cmd.procData.doc]; inputName ¬ FindFullName[inputName ! FS.Error => { IF error.group = user THEN {result ¬ $Failure; msg ¬ error.explanation; GOTO Quit} }]; IF outputName = NIL THEN { outputName ¬ MakeOutputName[inputName, cmd.procData.doc]; }; cmd.out.PutRope["Reading "]; cmd.out.PutRope[inputName]; cmd.out.PutRope[" . . . "]; InterpressFromRESAction[inputName, outputName, cmd, stream]; outputName ¬ FindFullName[outputName]; cmd.out.PutRope[outputName]; cmd.out.PutRope[" written.\n"]; EXITS Quit => NULL }; <> 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)"]; Commander.Register["InterpressOverlay", InterpressOverlayCmd, "Merge two interpress masters ( _ {translate | rotate | scale | scale2 })"]; Commander.Register["InterpressFromRES", InterpressFromRESCommand, "Convert an RES file to Interpress"]; END.