TiogaToInterpressImpl.mesa
Copyright Ó 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, March 13, 1987 3:07:06 pm PST
Bloomenthal -- background and slidewide options, October 28, 1985 4:50:33 pm PST
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: ROPENIL] RETURNS [root: TextNode.Ref] ~ {
fullFName: ROPENIL;
root ← PutGet.FromFile[inputName];
IF Rope.Size[styleName]#0 THEN TextEdit.ChangeStyle[node: root, name: styleName, event: NIL, root: root];
};
ptpermeter: REAL ← 72.27/0.0254;
ptperbp: REAL ← 72.27/72;
MakeHeader: PROC [version: REAL] RETURNS [ROPE] ~ {
header: ROPE ~ IO.PutFR[format: "Interpress/Xerox/%g ", v1: [real[version]]];
RETURN [header]
};
TiogaToInterpressAction: PROC [data: ParsedCommand, msgStream: IO.STREAM] ~ {
master: ImagerInterpress.Ref ~ ImagerInterpress.Create[data.outputName, MakeHeader[data.version]];
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: ROPENIL;
fullFName ← FS.FileInfo[inputName].fullFName;
RETURN [fullFName]
};
ExtendName: PROC [inputName, ext: ROPE] RETURNS [ROPE] ~ {
fullFName: ROPENIL;
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: ROPENIL,
inputNames: LIST OF ROPENIL,
style: ROPE,
skipPages: INT,
nPages: INT,
magnify: REAL,
verbose: BOOL,
screenFormat: BOOL,
background: ImagerColor.ConstantColor,
version: REAL ← 3.0
];
ExpandStars: PROC [names: LIST OF ROPE] RETURNS [LIST OF ROPE] ~ {
new: LIST OF ROPELIST[NIL];
last: LIST OF ROPE ← new;
NameAction: PROC [fullFName: ROPE] RETURNS [continue: BOOLTRUE] ~ {
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 ROPENIL;
inputNamesTail: LIST OF ROPENIL;
keySeen: BOOLFALSE;
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: INTIO.GetIndex[stream];
name: ROPE ← GetCmdToken[stream];
bad: BOOLFALSE;
c: CHAR;
IF Rope.Size[name] = 0 THEN EXIT;
IF (c ← Rope.Fetch[name, 0]) IN ['0..'9] OR c = '- 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 TEXTNEW[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, tokenATOM => RETURN [TRUE];
tokenERROR, tokenOCTAL, tokenHEX, tokenCHAR, 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;
};
tokenATOM => {
CheckStack[];
IF token[0] # '$ THEN ERROR;
stringStack[stackTop] ← Rope.FromRefText[s: token, start: 1];
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 or atom 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["version"] => {data.version ← PopReal[]; 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.STREAMIO.RIS[cmd.commandLine];
refAction: REF ActionProc ~ NARROW[cmd.procData.clientData];
backgroundTask: PROC ~ {
data: ParsedCommand;
data ← Parse[stream !
ParseError => {
start: INTMAX[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-- 3.0 version 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, version: 3.0]];
docRope: ROPE ~ Rope.Concat["[<output> ←] <input> ", paramRope];
ParseParameters[IO.RIS[paramRope], default];
Commander.Register["TiogaToInterpress", Command, Rope.Cat["Convert Tioga file to Interpress\n ", docRope, "\n"], NEW[ActionProc ← TiogaToInterpressAction]];
END.