TiogaToJaMImpl.mesa
Copyright (C) 1985, Xerox Corporation. All rights reserved.
Michael Plass, January 8, 1985 9:29:57 am PST
DIRECTORY
Commander USING [CommandProc, Handle, Register],
FS USING [Error, StreamOpen],
IO USING [CharClass, Close, EndOfStream, GetTokenRope, int, PutChar, PutF, PutFR, PutRope, real, RIS, rope, STREAM, Value],
NodeStyle USING [Ref],
ProcessExtras USING [CheckForAbort],
PutGet USING [FromFile],
Rope USING [Equal, Length, ROPE],
TextNode USING [Ref],
TSFont USING [ParcFontSpecification, Ref, Width],
TSJaMPageBuilder USING [RunPageBuilder],
TSObject USING [ItemList],
TSOutput USING [Handle, OutputRec],
TSTranslate USING [TreeToVlist],
TSTypes USING [AddDimn, Dimn];
TiogaToJaMImpl: CEDAR PROGRAM
IMPORTS Rope, FS, IO, PutGet, Commander, TSTranslate, TSJaMPageBuilder, TSTypes, TSFont, ProcessExtras ~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
Data: TYPE ~ REF DataRep;
DataRep: TYPE ~ RECORD [
stream: IO.STREAM,
cmd: Commander.Handle,
pageCount: INT ← 0,
font: TSFont.Ref ← NIL,
instring: BOOLEANFALSE,
inpage: BOOLEANFALSE,
indent: INT ← 0,
cpx: TSTypes.Dimn,
cpy: TSTypes.Dimn,
hue, saturation, brightness: REAL ← 0.0
];
Do: PROC [document: TextNode.Ref, output: IO.STREAM, cmd: Commander.Handle] = {
galley: TSObject.ItemList;
style: NodeStyle.Ref;
outputHandle: TSOutput.Handle ← CreateOutputHandle[output, cmd];
isAborted: PROC RETURNS [BOOLEAN] = {ProcessExtras.CheckForAbort[]; RETURN[FALSE]};
[galley, style] ← TSTranslate.TreeToVlist[document];
output.PutRope["\n(leftParen) \"(\" .def (rightParen) \")\" .def\n"];
[] ← TSJaMPageBuilder.RunPageBuilder[
galley: galley,
style: style,
output: outputHandle,
abortCheckProc: isAborted
];
Finish[outputHandle];
};
NewLine: PROC [data: Data] = {
data.stream.PutChar['\n];
THROUGH [0..data.indent) DO data.stream.PutChar['\t] ENDLOOP;
};
BeginPage: PROC [data: Data] = {
IF data.inpage THEN ERROR;
data.pageCount ← data.pageCount + 1;
data.stream.PutF["(page-%g) (", IO.int[data.pageCount]];
data.indent ← data.indent + 1;
data.inpage ← TRUE;
NewLine[data];
data.font ← NIL;
data.hue ← data.saturation ← data.brightness ← 0.0;
};
EndPage: PROC [data: Data] = {
IF NOT data.inpage OR data.instring THEN ERROR;
data.cmd.out.PutF[" [%g]", IO.int[data.pageCount]];
data.stream.PutRope[").cvx .def"];
data.inpage ← FALSE;
NewLine[data];
data.indent ← data.indent - 1;
NewLine[data];
};
BeginString: PROC [data: Data] = {
IF data.instring THEN RETURN;
data.stream.PutRope[" \""];
data.instring ← TRUE;
};
EndString: PROC [data: Data] = {
IF NOT data.instring THEN RETURN;
data.stream.PutRope["\" .show"];
NewLine[data];
data.instring ← FALSE;
};
Bp: PROC [dimn: TSTypes.Dimn] RETURNS [IO.Value] = {
RETURN [IO.real[dimn.texPts/1.00375]]
};
FontName: PROC [font: TSFont.Ref] RETURNS [ROPE] = {
family: Rope.ROPE;
face: [0..255];
weight: [0..3);
slope: [0..2);
expansion: [0..3);
[family: family, face: face] ← TSFont.ParcFontSpecification[font];
slope ← face MOD 2;
weight ← (face/2) MOD 3;
expansion ← (face/6) MOD 3;
RETURN [IO.PutFR["Xerox/PressFonts/%g/%g%g%g",
IO.rope[family],
IO.rope[SELECT weight FROM
0 => "M",
1 => "B",
2 => "L",
ENDCASE => "?"],
IO.rope[SELECT slope FROM
0 => "R",
1 => "I",
ENDCASE => "?"],
IO.rope[SELECT expansion FROM
0 => "R",
1 => "C",
2 => "E",
ENDCASE => "?"]
]];
};
Same: PROC [a, b: TSTypes.Dimn] RETURNS [BOOLEAN] = {
RETURN [ABS[a.texPts-b.texPts]<=0.01]
};
Char: PROC [self: TSOutput.Handle, x, y: TSTypes.Dimn, char: CHAR, font: TSFont.Ref] ~ {
data: Data ← NARROW[self.outputState];
IF char = '( OR char = ') THEN EndString[data];
IF Same[data.cpx, x] AND Same[data.cpy, y] THEN NULL
ELSE {
EndString[data];
data.stream.PutF["%g %g .setxy", Bp[x], Bp[y]];
data.cpx ← x;
data.cpy ← y;
NewLine[data];
};
IF data.font = font THEN NULL
ELSE {
EndString[data];
data.stream.PutF["(%g) %g 0 .nsrsetfont ", IO.rope[FontName[font]], Bp[font.size]];
data.font ← font;
NewLine[data];
};
IF char = '( THEN {
data.stream.PutF["leftParen .show "];
NewLine[data];
RETURN
};
IF char = ') THEN {
data.stream.PutF["rightParen .show "];
NewLine[data];
RETURN
};
IF data.instring THEN NULL
ELSE BeginString[data];
SELECT char FROM
< ' , > '~ => data.stream.PutF["\\%03b", IO.int[ORD[char]]];
'\\, '\', '\" => {data.stream.PutChar['\\]; data.stream.PutChar[char]};
ENDCASE => data.stream.PutChar[char];
data.cpx ← TSTypes.AddDimn[data.cpx, TSFont.Width[font, char]];
};
Rule: PROC [self: TSOutput.Handle, leftX, bottomY, width, height: TSTypes.Dimn] ~ {
data: Data ← NARROW[self.outputState];
EndString[data];
data.stream.PutF["%g %g %g %g .maskrectangle ",
Bp[leftX],
Bp[bottomY],
Bp[width],
Bp[height]
];
NewLine[data];
};
Color: PROC [self: TSOutput.Handle, hue, saturation, brightness: REAL] ~ {
data: Data ← NARROW[self.outputState];
IF hue = data.hue AND saturation = data.saturation AND brightness = data.brightness THEN NULL
ELSE {
EndString[data];
data.stream.PutF["%g %g %g .hsvcolor .setcolor ",
IO.real[hue/255],
IO.real[saturation/255],
IO.real[brightness/255]
];
data.hue ← hue;
data.saturation ← saturation;
data.brightness ← brightness;
NewLine[data];
};
};
NewPage: PROC [self: TSOutput.Handle] ~ {
data: Data ← NARROW[self.outputState];
EndString[data];
IF data.inpage THEN EndPage[data];
BeginPage[data];
};
PageSize: PROC [self: TSOutput.Handle, height, width: TSTypes.Dimn] ~ {
data: Data ← NARROW[self.outputState];
IF NOT data.inpage THEN {
data.stream.PutF["%% %g %g pagesize",
Bp[height],
Bp[width]
];
};
};
Finish: PROC [self: TSOutput.Handle] ~ {
data: Data ← NARROW[self.outputState];
EndString[data];
IF data.inpage THEN EndPage[data];
};
CreateOutputHandle: PROC [output: IO.STREAM, cmd: Commander.Handle] RETURNS [TSOutput.Handle] = {
data: Data ← NEW[DataRep ← [
stream: output,
cmd: cmd,
pageCount: 0,
font: NIL,
instring: FALSE,
cpx: [-1],
cpy: [-1]
]];
new: TSOutput.Handle ← NEW[TSOutput.OutputRec ← [
charProc: Char,
ruleProc: Rule,
colorProc: Color,
newPageProc: NewPage,
pageSizeProc: PageSize,
finishProc: Finish,
outputState: data
]];
RETURN [new]
};
GetToken: PROC [stream: IO.STREAM] RETURNS [token: ROPENIL] = {
token ← stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token;
};
Break: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← OR char = '; THEN RETURN [break];
IF char = ' OR char = '  OR char = ', OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
TiogaToJaMCommand: Commander.CommandProc ~ {
stream: IO.STREAMIO.RIS[cmd.commandLine];
outputName: ROPE ← GetToken[stream];
gets: ROPE ← GetToken[stream];
inputName: ROPE ← GetToken[stream];
IF NOT gets.Equal["←"] OR inputName.Length = 0 THEN {
RETURN [result: $Failure, msg: "Specify output ← input, please\n"];
}
ELSE {
output: IO.STREAMFS.StreamOpen[outputName, $create];
document: TextNode.Ref ← NIL;
errorMsg: ROPENIL;
document ← PutGet.FromFile[inputName ! FS.Error => TRUSTED {errorMsg ← error.explanation; CONTINUE}];
IF errorMsg # NIL THEN RETURN [result: $Failure, msg: errorMsg];
output.PutRope["% Created from "];
output.PutRope[inputName];
Do[document, output, cmd];
output.Close;
};
};
Commander.Register["TiogaToJaM", TiogaToJaMCommand, "Format a Tioga document as a JaMImager file (output ← input)"];
END.