~
BEGIN
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];
};
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: 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,
version: REAL ← 3.0
];
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='. 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, 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.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-- 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]];