IPAttributesImpl:
CEDAR
PROGRAM
IMPORTS Commander, DecomposerRegistry, BasicTime, IO, IPAttributes, IPInstructions, IPInterpreter, Real, RefTab, Rope
EXPORTS IPAttributes
ROPE: TYPE = Rope.ROPE;
Attribute: TYPE = DecomposerRegistry.Attribute;
Value: TYPE = DecomposerRegistry.Value;
ValueRep: TYPE = DecomposerRegistry.ValueRep;
ValueTag: TYPE = DecomposerRegistry.ValueTag;
ValueSeq: TYPE = DecomposerRegistry.ValueSeq;
ValueSeqRep:
TYPE = DecomposerRegistry.ValueSeqRep;
Name:
TYPE = IPInstructions.Names;
AttrEntry: TYPE = REF AttrEntryRep;
AttrEntryRep:
TYPE =
RECORD [
attr: Attribute,
proc: IPToValueProc,
names:
LIST
OF Name
This is a list of Name to deal with things like jobName, which is nested underneath standard/jobAttributes - in this case we would want names to be LIST[STANDARDjobAttributes, jobName]
];
baseTime: BasicTime.
GMT = BasicTime.Pack[[year: 1970, month: January, day: 1, hour: 0, minute: 0, second: 0, zone: 0, dst: no]];
GetAttributeProc: TYPE = PROC [attr: Attribute, proc: IPToValueProc, names: LIST OF Name];
For use with MapRegisteredAttributes
MapRegisteredAttributes:
PROC [proc: GetAttributeProc] = {
The proc is called once for each registered attribute.
KeyVal: RefTab.EachPairAction = {
WITH val
SELECT
FROM
ent: AttrEntry => proc[ent.attr, ent.proc, ent.names];
ENDCASE;
};
[] ¬ RefTab.Pairs[attrTable, KeyVal]; -- call KeyVal for every pair in the table
};
IPToValueProc:
TYPE =
PROC [attr: Attribute, iv: IPVector.Vector, names:
LIST
OF Name]
RETURNS [seq: ValueSeq ←
NIL];
There is one proc of this type for each DecomposerRegistry ValueSeq to be derived from the Interpress instructions vector iv for use in the subsequent call to setAttr. DecomposerRegistry Values may be mapped one-to-one to Interpress instructions vector values, but usually are not. When an IPToValueProc is called, it creates a seq and fills in the fields from values that it finds in the instructions vector.
RegisterAttr:
PROC [attr: Attribute, proc: IPToValueProc, names:
LIST
OF IPInstructions.Names] = {
Registers an IPToValueProc for this attribute.
new: AttrEntry = NEW[AttrEntryRep ¬ [attr: attr, proc: proc, names: names]];
[] ¬ RefTab.Store[attrTable, attr, new];
};
GetIPToValue:
PROC [attr: Attribute]
RETURNS [proc: IPToValueProc] = {
The IPToValueProc that has been registered for this attribute is returned.
WITH RefTab.Fetch[attrTable, attr].val
SELECT
FROM
ae: AttrEntry => RETURN [ae.proc];
ENDCASE => RETURN [NIL];
};
GetProp:
PROC [iv: IPVector.Vector, names:
LIST
OF IPInstructions.Names]
RETURNS [found:
BOOL ¬
FALSE, value: IPVector.Any] ~ {
v: IPVector.Vector ¬ iv;
FOR tail:
LIST
OF IPInstructions.Names ¬ names, tail.rest
UNTIL tail =
NIL
DO
nameRope: ROPE ~ IPInstructions.NameRopeFromName[tail.first];
name: IPVector.Any ~ IF Rope.Match["*/*", nameRope] THEN IPInterpreter.VectorFromName[nameRope] ELSE nameRope;
[found, value] ¬ IPInterpreter.GetProp[v, name];
IF found
AND tail.rest #
NIL THEN {
v ¬ IPInterpreter.VectorFromAny[value];
};
ENDLOOP;
};
GenericCard: IPToValueProc = {
attr is a cardinal-valued attribute
any: IPVector.Any;
found: BOOL ¬ FALSE;
[found, any] ¬ GetProp[iv, names];
IF found
THEN {
seq ¬ NEW[ValueSeqRep[1]];
seq[0] ¬ DecomposerRegistry.MakeCardVal[IPInterpreter.CardinalFromAny[any]];
};
};
GenericString: IPToValueProc = {
attr is a string-valued attribute
found: BOOL ¬ FALSE;
any: IPVector.Any;
[found, any] ¬ GetProp[iv, names];
IF found
THEN {
seq ¬ NEW[ValueSeqRep[1]];
seq[0] ¬ DecomposerRegistry.MakeTextVal[IPInterpreter.RopeFromVector[IPInterpreter.VectorFromAny[any]]];
};
};
These IPToValueProcs know how to build a value sequence of the right shape for their particular attribute
debug: IO.STREAM ¬ NIL;
IPAttrDebugCommand: Commander.CommandProc = {
IF debug =
NIL
THEN {debug¬cmd.err; msg ¬ "on"}
ELSE {debug¬NIL; msg ¬ "off"};
};
Plex
: IPToValueProc
= {
Interpess PLEX is "simplex", "duplex", or "tumbleDuplex". Values are Identifiers.
Decomposer Plex is an enumeration.
value: REF ~ GetProp[iv, names].value;
WITH value
SELECT
FROM
text:
ROPE => {
plex: DecomposerRegistryCodes.Plex ¬ unknown;
SELECT
TRUE
FROM
Rope.Equal["simplex", text, FALSE] => plex ¬ simplex;
Rope.Equal["duplex", text, FALSE] => plex ¬ duplex;
Rope.Equal["tumbleDuplex", text, FALSE] => plex ¬ tumble;
Rope.Equal["duplexHeadToToe", text,
FALSE] => {
This is non-standard, but it is what GlobalView expects to be able to say.
plex ¬ tumble;
};
ENDCASE;
seq ¬ NEW[ValueSeqRep[1]];
seq[0] ¬ DecomposerRegistry.MakeCardVal[ORD[plex]];
};
ENDCASE;
Staple
: IPToValueProc
= {
Interpess staple is "none" or "corner". Values are Identifiers.
Possible Vector of Identifiers not implemented here.
value: REF ~ GetProp[iv, names].value;
WITH value
SELECT
FROM
text:
ROPE => {
staple: DecomposerRegistryCodes.Staple ¬ unknown;
SELECT
TRUE
FROM
Rope.Equal["corner", text, FALSE] => staple ¬ singlePortraitStapling;
Rope.Equal["cornerStaple", text, FALSE] => staple ¬ singlePortraitStapling;
Rope.Equal["none", text, FALSE] => staple ¬ none;
Rope.Equal["finishingNone", text, FALSE] => staple ¬ none;
ENDCASE;
seq ¬ NEW[ValueSeqRep[1]];
seq[0] ¬ DecomposerRegistry.MakeCardVal[ORD[staple]];
};
ENDCASE;
ImageShift
: IPToValueProc
= {
Interpress has xImageShift and yImageShift in ICS coordinates, which I assume are meters.
DecomposerRegistry wants dimensions in units of milliMeters
any: IPVector.Any ¬ GetProp[iv, names].value;
IF any #
NIL
THEN {
shift: REAL ← IPInterpreter.RealFromAny[any]*1000.0; -- meters to mm
seq ← NEW[DecomposerRegistry.ValueSeqRep[1]];
seq[0] ← DecomposerRegistry.MakeIntVal[Real.Round[shift]]
};
};
Media
: IPToValueProc
= {
mediaType is [xSize: CARD32, ySize: CARD32, formType: ROPE, color: ROPE, weight: CARD32]
OPEN DecomposerRegistry;
Any: TYPE ~ IPInterpreter.Any;
Vector: TYPE ~ IPInterpreter.Vector;
VectorShape: TYPE ~ IPInterpreter.VectorShape;
Cardinal: TYPE ~ IPInterpreter.Cardinal;
Identifier: TYPE ~ IPInterpreter.Identifier;
RealFromAny: PROC [Any] RETURNS [REAL] ~ IPInterpreter.RealFromAny;
IdentifierFromAny: PROC [Any] RETURNS [ROPE] ~ IPInterpreter.IdentifierFromAny;
VectorFromAny: PROC [Any] RETURNS [Vector] ~ IPInterpreter.VectorFromAny;
Shape: PROC [Vector] RETURNS [VectorShape] ~ IPInterpreter.Shape;
any: Any ¬ GetProp[iv, names].value;
IF any #
NIL
THEN {
milliMetersPerMeter: REAL = 1000.0;
defaultXSize: CARD32 = 216; -- see XNSS359106, p. 2-4
defaultYSize: CARD32 = 279; -- see XNSS359106, p. 2-4
defaultMedium: Identifier = "";
defaultColor: Identifier = "";
defaultWeight: CARD32 = 0;
defaultMedium: Identifier = "defaultMedium";
defaultColor: Identifier = "white";
defaultWeight: CARD32 = 75;
mediaVec: Vector ¬ VectorFromAny[any];
Vector of mediumDescription Vectors
mediaShape: VectorShape ¬ Shape[mediaVec];
size: CARDINAL = mediaShape.size;
lb: Cardinal ¬ mediaShape.lowerBound;
ub: Cardinal ¬ mediaShape.lowerBound+size-1;
seq ¬
NEW[ValueSeqRep[size]];
make a new RETURN sequence with one sequence Value for each mediumDescription
FOR i: Cardinal
IN [lb..ub]
DO
-- for every mediumDescription
next: Any ¬ IPInterpreter.Get[mediaVec, i]; -- get the next mediumDescription
nextMedium: Vector ¬ VectorFromAny[next]; -- mediumDescription is a 5 element Vector
innerSeq: ValueSeq ¬ NEW[ValueSeqRep[5]]; -- make a 5 element sequence of Values
innerVal: Value ¬ NEW[ValueRep.sequence ¬ [sequence[innerSeq]]]; -- make a sequence Value to put innerSeq in
seq[i-lb] ¬ innerVal;
-- put this sequence value in the RETURN sequence
look for up to 5 elements in the mediumDescription vector
fill in the inner sequence with corresponding mediaType field values
any ¬ GetProp[nextMedium, LIST[mediumXSize] ].value;
innerSeq[0] ¬ MakeCardVal[IF any # NIL
THEN Real.Round[RealFromAny[any]*milliMetersPerMeter]
ELSE defaultXSize];
any ¬ GetProp[nextMedium, LIST[mediumYSize] ].value;
innerSeq[1] ¬ MakeCardVal[IF any # NIL
THEN Real.Round[RealFromAny[any]*milliMetersPerMeter]
ELSE defaultYSize];
any ¬ GetProp[nextMedium, LIST[mediumName] ].value;
innerSeq[2] ¬ MakeTextVal[IF any # NIL
THEN IdentifierFromAny[any]
ELSE defaultMedium];
any ¬ GetProp[nextMedium, LIST[color] ].value;
innerSeq[3] ¬ MakeTextVal[IF any # NIL
THEN IdentifierFromAny[any]
ELSE defaultColor];
any ¬ GetProp[nextMedium, LIST[weight] ].value;
innerSeq[4] ¬ MakeCardVal[IF any # NIL
THEN Real.Fix[RealFromAny[any]]
ELSE defaultWeight];
ENDLOOP;
};
};
PrintVector:
PROC [out:
IO.
STREAM, iv: IPVector.Vector] ~ {
OPEN IPInstructions, IPInterpreter;
k,v: ROPE;
shape: VectorShape ¬ Shape[iv];
lb: Cardinal ¬ shape.lowerBound;
ub: Cardinal ¬ shape.lowerBound+shape.size-1;
IO.PutF1[out, "[%g: ", IO.card[shape.size] ];
FOR i: Cardinal
IN [lb..ub]
DO
next: Any ¬ Get[iv, i];
nextType: TypeCode ¬ Type[next];
SELECT nextType
FROM
null => k ¬ "null";
number => {
decode each kind of number and print it
n: Number ¬ NumberFromAny[next];
SELECT n.tag
FROM
zero => k ¬ "zero";
int => k ¬ IO.PutFR1["%g", IO.int[IntegerFromAny[n] ]];
real => k ¬ IO.PutFR1["%g", IO.real[RealFromAny[n] ]];
rational => {
nn, nd: INT;
nr: NumberRep ~ n;
WITH nr: nr
SELECT
FROM
rational => {nn ¬ nr.n; nd ¬ nr.d;};
ENDCASE;
k ¬ IO.PutFR["n: %g, d: %g", IO.int[nn], IO.int[nd] ];
};
ENDCASE => k ¬ "unknown Number type";
};
identifier => k ¬ IdentifierFromAny[next];
vector => {
PrintVector[out, VectorFromAny[next] ];
k ¬ NIL; -- prevent redundant printing
};
operator => {
--print operator.type
op: Operator ¬ OperatorFromAny[next];
k ¬ IO.PutFR1["%g", IO.atom[op.class.type] ];
};
transformation => k ¬ "transformation";
color => k ¬ "color";
trajectory => k ¬ "trajectory";
outline => k ¬ "outline";
font =>k ¬ "font";
clipper => k ¬ "clipper";
ENDCASE => k ¬ "unknown";
IF k#NIL THEN IO.PutRope[out, k];
IF i < ub THEN IO.PutRope[out, ", "]; -- avoid comma on last element
ENDLOOP;
IO.PutRope[out, "]"];
};
PutAttributeValue:
PROC [stream:
IO.
STREAM, value: Value] = {
Used for debug. Does this replicate some code somewhere????
WITH value
SELECT
FROM
cardinal: REF ValueRep.cardinal => IO.Put1[stream, [cardinal[cardinal.cardinal]]];
integer: REF ValueRep.integer => IO.Put1[stream, [integer[integer.integer]]];
boolean: REF ValueRep.boolean => IO.Put1[stream, [boolean[boolean.boolean]]];
real: REF ValueRep.real => IO.Put1[stream, [real[real.real]]];
text: REF ValueRep.text => IO.PutRope[stream, text.text];
time: REF ValueRep.time => IO.Put1[stream, [time[time.time]]];
sequence:
REF ValueRep.sequence => {
IO.PutRope[stream, "["];
FOR i:
NAT
IN [0..sequence.sequence.len)
DO
IF i > 0 THEN IO.PutRope[stream, ", "];
PutAttributeValue[stream, sequence.sequence[i]];
ENDLOOP;
IO.PutRope[stream, "]"];
};
ENDCASE => IO.Put1[stream, [refAny[value]]];
};
IPAttr:
PUBLIC DecomposerRegistry.AttributesProc = {
AttributesProc: TYPE = PROC [instance: InstanceData];
dummy: INT ¬ 0;
sd: DecomposerRegistry.SequencerData ¬ instance.sequencer;
setAttr: DecomposerRegistry.SetAttrProc ¬ sd.procs.setAttr;
getAttr: DecomposerRegistry.GetAttrProc ¬ sd.procs.getAttr;
master: InterpressInterpreter.Master ¬ IPAttributes.MasterFromInstance[instance];
sk: IPMaster.Skeleton ¬ IPInstructions.GetMasterSkeleton[master: master]; -- new call
iv: IPVector.Vector ¬ sk.instructions.instructions;
ForAttribute: GetAttributeProc = {
[attr: Attribute, proc: IPToValueProc, names: LIST OF Name]
this is where all the work of deriving and setting attributes is done
FormatNames:
PROC [explanation:
ROPE]
RETURNS [
ROPE] = {
msg: ROPE ¬ explanation;
FOR tail:
LIST
OF Name ¬ names, tail.rest
UNTIL tail =
NIL
DO
msg ¬ msg.Cat[" ", IPInstructions.NameRopeFromName[tail.first]];
ENDLOOP;
RETURN [msg]
};
IF proc #
NIL
THEN {
ENABLE IPInterpreter.Error => {
msg: ROPE = FormatNames[Rope.Concat[explanation, " while processing printing instruction"]];
instance.sequencer.procs.feedback[instance, $PrintingInstructionsError, warning, msg];
IF debug #
NIL
THEN {
s: IO.STREAM = debug; -- sample it to guarantee NIL test.
IF s # NIL THEN s.PutRope[msg.Concat["\n"] ! IO.Error => {debug ¬ NIL; CONTINUE}];
};
CONTINUE;
};
seq: DecomposerRegistry.ValueSeq ¬ proc[attr, iv, names];
IF seq = NIL THEN RETURN;
IF debug #
NIL
THEN {
s: IO.STREAM = debug;
ros: IO.STREAM = IO.ROS[];
old: DecomposerRegistry.ValueSeq ¬ NIL;
Dump:
PROC [seq: DecomposerRegistry.ValueSeq] = {
IO.PutF1[ros, "[%g", [atom[attr]]];
FOR i:
NAT
IN [0..seq.len)
DO
IO.PutRope[ros, ", "];
PutAttributeValue[ros, seq[i]];
ENDLOOP;
IO.PutRope[ros, "]"];
};
Dump[seq];
IF getAttr # NIL THEN old ¬ getAttr[sd, attr ! UNCAUGHT => CONTINUE];
IF old # NIL THEN {IO.PutRope[ros, " was "]; Dump[old] };
IO.PutRope[ros, "\n"];
IF s # NIL THEN s.PutRope[IO.RopeFromROS[ros] ! IO.Error => {debug ¬ NIL; CONTINUE}];
};
setAttr[sd, attr, seq]; -- actually set the attribute!
};
};
instance.pages ¬ master.pages;
IF sd.flags.debug
OR debug #
NIL THEN {
ros: IO.STREAM = IO.ROS[];
s: IO.STREAM = debug;
PrintVector[ros, iv];
{
msg: ROPE = IO.RopeFromROS[ros];
IF sd.flags.debug THEN sd.procs.feedback[instance, $PrintVector, comment, msg];
IF s # NIL THEN s.PutRope[msg.Concat["\n"] ! IO.Error => {debug ¬ NIL; CONTINUE}];
};
};
MapRegisteredAttributes[ForAttribute];
};