<> <> <> <> DIRECTORY Atom, CedarProcess, Commander, Convert, FS, Imager, ImagerColor, ImagerInterpress, IO, Real, Rope, TiogaImager, TextNode, PutGet, TextEdit; TiogaToInterpressImpl: CEDAR PROGRAM IMPORTS CedarProcess, Commander, Convert, FS, Imager, ImagerColor, ImagerInterpress, IO, Real, Rope, TiogaImager, TextNode, PutGet, TextEdit ~ BEGIN ROPE: TYPE ~ Rope.ROPE; ActionProc: TYPE ~ PROC [data: ParsedCommand, msgStream: IO.STREAM]; Error: ERROR [rope: ROPE] ~ CODE; GetWithStyle: PROC [inputName: ROPE, styleName: ROPE _ NIL] RETURNS [root: TextNode.Ref] ~ { fullFName: ROPE _ NIL; root _ PutGet.FromFile[inputName]; IF Rope.Size[styleName]#0 THEN TextEdit.ChangeStyle[node: root, name: styleName, event: NIL, root: root]; }; header: ROPE _ "Interpress/Xerox/3.0 "; ptpermeter: REAL _ 72.27/0.0254; ptperbp: REAL _ 72.27/72; TiogaToInterpressAction: PROC [data: ParsedCommand, msgStream: IO.STREAM] ~ { master: ImagerInterpress.Ref ~ ImagerInterpress.Create[data.outputName, header]; pageCount: INT _ 0; FOR inputs: LIST OF ROPE _ data.inputNames, inputs.rest WHILE inputs#NIL AND pageCount-data.skipPages < data.nPages DO marks: Atom.PropList _ NIL; root: TextNode.Ref ~ GetWithStyle[inputs.first, data.style]; loc: TextNode.Location _ [node: TextNode.StepForward[root], where: 0]; IF inputs # data.inputNames THEN { msgStream.PutRope[" . . . "]; msgStream.PutRope[inputs.first]; msgStream.PutRope[" . . . "]; }; WHILE loc.node # NIL AND pageCount-data.skipPages < data.nPages DO page: TiogaImager.FormattedPage; paint: PROC [context: Imager.Context] ~ { Imager.ScaleT[context, 0.0254/72.27]; IF data.background#NIL THEN { Imager.SetColor[context, data.background]; Imager.MaskRectangle[context, [-10000, -10000, 20000, 20000]]; Imager.SetColor[context, Imager.black]; }; TiogaImager.Render[page.box, context, [0, 0]]; }; IF data.verbose AND pageCount >= data.skipPages THEN { msgStream.PutRope["\n (Location "]; msgStream.PutRope[Convert.RopeFromInt[TextNode.LocNumber[at: loc, skipCommentNodes: TRUE]]]; msgStream.PutRope[") "]; }; page _ TiogaImager.FormatPage[pageCounter: pageCount, startLoc: loc, filter: NIL, marks: marks, screenStyle: data.screenFormat]; IF pageCount >= data.skipPages THEN { msgStream.PutRope["["]; msgStream.PutRope[Convert.RopeFromInt[page.pageFigure]]; ImagerInterpress.DoPage[master, paint, data.magnify]; msgStream.PutRope["] "]; }; TiogaImager.Destroy[page.box]; pageCount _ pageCount + 1; marks _ page.marks; loc _ page.nextLoc; ENDLOOP; ENDLOOP; ImagerInterpress.Close[master]; }; FindFullName: PROC [inputName: ROPE] RETURNS [ROPE] ~ { fullFName: ROPE _ NIL; fullFName _ FS.FileInfo[inputName].fullFName; RETURN [fullFName] }; ExtendName: PROC [inputName, ext: ROPE] RETURNS [ROPE] ~ { fullFName: ROPE _ NIL; cp: FS.ComponentPositions; [fullFName, cp] _ FS.ExpandName[inputName]; RETURN [Rope.Cat[Rope.Substr[fullFName, cp.base.start, cp.base.length], ".", ext]]; }; 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; }; ParseError: ERROR [msg: ROPE, index: INT] ~ CODE; RaiseParseError: PROC [stream: IO.STREAM, msg: ROPE] ~ { ERROR ParseError[msg, IO.GetIndex[stream]]; }; ParsedCommand: TYPE ~ REF ParsedCommandRep; ParsedCommandRep: TYPE ~ RECORD [ outputName: ROPE _ NIL, inputNames: LIST OF ROPE _ NIL, style: ROPE, skipPages: INT, nPages: INT, magnify: REAL, verbose: BOOL, screenFormat: BOOL, background: ImagerColor.ConstantColor ]; ExpandStars: PROC [names: LIST OF ROPE] RETURNS [LIST OF ROPE] ~ { new: LIST OF ROPE _ LIST[NIL]; last: LIST OF ROPE _ new; NameAction: PROC [fullFName: ROPE] RETURNS [continue: BOOL _ TRUE] ~ { last.rest _ LIST[fullFName]; last _ last.rest; }; FOR p: LIST OF ROPE _ names, p.rest UNTIL p = NIL DO r: ROPE _ p.first; IF Rope.Find[s1: r, s2: "*"] >= 0 THEN { IF Rope.Find[s1: r, s2: "!"] < 0 THEN r _ Rope.Concat[r, "!H"]; FS.EnumerateForNames[r, NameAction] } ELSE [] _ NameAction[FindFullName[r]]; ENDLOOP; RETURN [new.rest] }; IsKeyword: PROC [name: ROPE] RETURNS [BOOL] ~ { Match: PROC [key: ROPE] RETURNS [BOOL] ~ {RETURN [Rope.Equal[name, key, FALSE]]}; RETURN [Match["verbose"] OR Match["terse"] OR Match["screenFormat"] OR Match["printFormat"]]; }; Parse: PROC [stream: IO.STREAM] RETURNS [data: ParsedCommand] ~ { outputName: ROPE _ GetCmdToken[stream]; secondTokenIndex: INT _ stream.GetIndex; gets: ROPE _ GetCmdToken[stream]; inputNames: LIST OF ROPE _ NIL; inputNamesTail: LIST OF ROPE _ NIL; keySeen: BOOL _ FALSE; IF NOT gets.Equal["_"] THEN { inputNames _ inputNamesTail _ LIST[outputName]; outputName _ NIL; stream.SetIndex[secondTokenIndex]; } ELSE {inputNames _ inputNamesTail _ LIST[GetCmdToken[stream]]}; IF inputNames = NIL THEN RaiseParseError[stream, docRope]; DO index: INT _ IO.GetIndex[stream]; name: ROPE _ GetCmdToken[stream]; bad: BOOL _ FALSE; c: CHAR; IF Rope.Size[name] = 0 THEN EXIT; IF (c _ Rope.Fetch[name, 0]) IN ['0..'9] OR c = '- OR c='. THEN bad _ TRUE ELSE IF IsKeyword[name] THEN bad _ TRUE ELSE name _ FS.ExpandName[name ! FS.Error => {bad _ TRUE; CONTINUE}].fullFName; IF bad THEN {IO.SetIndex[stream, index]; EXIT}; inputNamesTail.rest _ LIST[name]; inputNamesTail _ inputNamesTail.rest; ENDLOOP; inputNames _ ExpandStars[inputNames]; IF Rope.Size[outputName] = 0 THEN outputName _ ExtendName[inputNames.first, "interpress"]; data _ NEW[ParsedCommandRep _ default^]; data.outputName _ outputName; data.inputNames _ inputNames; ParseParameters[stream, data]; }; ParseParameters: PROC [stream: IO.STREAM, data: ParsedCommand] ~ { stackSize: NAT ~ 3; Type: TYPE ~ {number, dimension, string}; stack: ARRAY [0..3) OF REAL; stringStack: ARRAY [0..stackSize) OF ROPE; stackType: ARRAY [0..3) OF Type; stackTop: NAT _ 0; token: REF TEXT _ NEW[TEXT[30]]; tokenKind: IO.TokenKind _ tokenERROR; CheckStack: PROC ~ { IF stackTop = stackSize THEN RaiseParseError[stream, "Too many consecutive parameters "]; }; CheckN: PROC [size: NAT] ~ { IF stackTop # size THEN RaiseParseError[stream, "Wrong number of parameters "]; }; PopReal: PROC RETURNS [r: REAL _ 0] ~ { IF stackTop = 0 THEN RaiseParseError[stream, "Missing parameter "]; IF stackType[stackTop-1] # number THEN RaiseParseError[stream, "Number expected "]; r _ stack[stackTop-1]; stackTop _ stackTop - 1; }; PopDimn: PROC RETURNS [r: REAL _ 0] ~ { IF stackTop = 0 THEN RaiseParseError[stream, "Missing parameter "]; IF stackType[stackTop-1] # dimension THEN RaiseParseError[stream, "Dimension expected "]; r _ stack[stackTop-1]; stackTop _ stackTop - 1; }; MakeMeters: PROC [multiplier: REAL] ~ { r: REAL _ PopReal[]; stack[stackTop] _ r*multiplier; stackType[stackTop] _ dimension; stackTop _ stackTop + 1; }; PopInt: PROC RETURNS [INT] ~ { r: REAL _ PopReal[]; i: INT _ Real.Round[r]; IF i#r THEN RaiseParseError[stream, "Integer expected "]; RETURN [i] }; GetTok: PROC RETURNS [BOOL] ~ { tokenError: IO.TokenError _ none; charsSkipped: INT _ 0; [tokenKind: tokenKind, token: token, charsSkipped: charsSkipped, error: tokenError] _ IO.GetCedarToken[stream: stream, buffer: token, flushComments: TRUE]; SELECT tokenKind FROM tokenEOF => RETURN [FALSE]; tokenID, tokenDECIMAL, tokenREAL, tokenROPE => RETURN [TRUE]; tokenERROR, tokenOCTAL, tokenHEX, tokenCHAR, tokenATOM, tokenSINGLE, tokenDOUBLE => RaiseParseError[stream, Rope.Cat["Unknown token: ", Rope.FromRefText[token]]]; ENDCASE => ERROR; RETURN [FALSE] }; WHILE GetTok[] DO Match: PROC [rope: ROPE] RETURNS [BOOL] ~ TRUSTED { RETURN [Rope.Equal[LOOPHOLE[token], rope, FALSE]] }; SELECT tokenKind FROM tokenDECIMAL, tokenREAL => TRUSTED { CheckStack[]; stack[stackTop] _ Convert.RealFromRope[LOOPHOLE[token]]; stackType[stackTop] _ number; stackTop _ stackTop + 1; }; tokenROPE => { CheckStack[]; stringStack[stackTop] _ Convert.RopeFromLiteral[Rope.FromRefText[token]]; stackType[stackTop] _ string; stackTop _ stackTop + 1; }; tokenID => { SELECT TRUE FROM Match["style"] => { CheckN[1]; IF stackType[stackTop-1]#string THEN RaiseParseError[stream, "style needs string parameter "]; stackTop _ stackTop-1; data.style _ stringStack[stackTop]; }; Match["skipPages"] => {data.skipPages _ PopInt[]; CheckN[0]}; Match["nPages"] => {data.nPages _ PopInt[]; CheckN[0]}; Match["magnify"] => {data.magnify _ PopReal[]; CheckN[0]}; Match["terse"] => {data.verbose _ FALSE; CheckN[0]}; Match["verbose"] => {data.verbose _ TRUE; CheckN[0]}; Match["screenFormat"] => {data.screenFormat _ TRUE; CheckN[0]}; Match["printFormat"] => {data.screenFormat _ FALSE; CheckN[0]}; Match["background"] => { b: REAL _ PopReal[]; g: REAL _ PopReal[]; r: REAL _ PopReal[]; IF MIN[r, g, b] < 1.0 THEN data.background _ ImagerColor.ColorFromRGB[[r, g, b]]; }; Match["in"] => {MakeMeters[0.0254]}; Match["pt"] => {MakeMeters[0.0254/72.27]}; Match["cm"] => {MakeMeters[0.01]}; Match["mm"] => {MakeMeters[0.001]}; Match["bp"] => {MakeMeters[0.0254/72.0]}; ENDCASE => RaiseParseError[stream, "Unknown keyword parameter: "]; }; ENDCASE => ERROR; ENDLOOP; }; Command: Commander.CommandProc ~ { stream: IO.STREAM _ IO.RIS[cmd.commandLine]; refAction: REF ActionProc ~ NARROW[cmd.procData.clientData]; backgroundTask: PROC ~ { data: ParsedCommand; data _ Parse[stream ! ParseError => { start: INT _ MAX[index-10, 0]; cmd.out.PutRope[msg]; IF start > 0 THEN cmd.out.PutRope["..."]; cmd.out.PutRope[cmd.commandLine.Substr[start, index-start]]; IF index > 1 THEN cmd.out.PutRope["..."]; cmd.out.PutRope["\n"]; GOTO Quit }; FS.Error => { cmd.out.PutRope[error.explanation]; cmd.out.PutRope["\n"]; GOTO Quit }; ]; cmd.out.PutRope["Reading "]; cmd.out.PutRope[data.inputNames.first]; cmd.out.PutRope[" . . . "]; refAction^[data, cmd.out ! Error => { cmd.out.PutRope[rope]; cmd.out.PutRope["\n"]; GOTO Quit }]; IF data.outputName # NIL THEN { data.outputName _ FindFullName[data.outputName]; cmd.out.PutRope[data.outputName]; cmd.out.PutRope[" written.\n"]; } ELSE cmd.out.PutRope[" ok.\n"]; EXITS Quit => {} }; CedarProcess.DoWithPriority[background, backgroundTask]; }; paramRope: ROPE ~ " \"\" style 0 skipPages 9999999 nPages printFormat--screenFormat-- terse--verbose-- 1.0 magnify 1.0 1.0 1.0 background"; default: ParsedCommand _ NEW[ParsedCommandRep _ [style: NIL, skipPages: 0, nPages: 0, magnify: 0.0, verbose: FALSE, screenFormat: FALSE, background: NIL]]; docRope: ROPE ~ Rope.Concat["[ _] ", paramRope]; ParseParameters[IO.RIS[paramRope], default]; Commander.Register["///commands/TiogaToInterpress", Command, Rope.Cat["Convert Tioga file to Interpress\n ", docRope, "\n"], NEW[ActionProc _ TiogaToInterpressAction]]; END.