IPAttributesImpl.mesa
Copyright Ó 1992 by Xerox Corporation. All rights reserved.
Kenneth A. Pier, February 3, 1992 3:53 pm PST
Russ Atkinson (RRA) May 3, 1992 11:32 am PDT
Michael Plass, June 1, 1993 3:02 pm PDT
This module implements a procedure that can be called from registered Interpress decomposers. It is used to translate IP printing instructions found in the IP skeleton into attributes that the downstream decomposer understands. As the decomposer evolves so must this module; in particular, the attributes it registers with itself must track those registered by the AttributeTranslation module.
DIRECTORY
Commander,
BasicTime, DecomposerRegistry, DecomposerRegistryCodes, ImagerError, InterpressInterpreter, IO, IPAttributes, IPMaster, IPInstructions, IPInterpreter, IPVector, Real, RefTab, Rope;
IPAttributesImpl: CEDAR PROGRAM
IMPORTS Commander, DecomposerRegistry, BasicTime, IO, IPAttributes, IPInstructions, IPInterpreter, Real, RefTab, Rope
EXPORTS IPAttributes
= BEGIN
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];
};
The following attributes correspond to those registered with the AttributeTranslation module and must track that module as attributes evolve. The attributes registered here are not ALL of the attributes registered with the AttributeTranslation module, but only the ones for which it makes sense to derive values from the IP skeleton instructions.
attrTable: RefTab.Ref = RefTab.Create[mod: 57];
RegisterAttr[$SenderName, GenericString, LIST[STANDARDjobAttributes, jobSender]];
RegisterAttr[$RecipientName, GenericString, LIST[STANDARDjobAttributes, jobRecipient]];
RegisterAttr[$DocumentName, GenericString, LIST[docName]];
RegisterAttr[$DocumentDate, GenericString, LIST[docCreationDate]];
RegisterAttr[$DocumentDate, GenericString, LIST[docCreationDate]];
RegisterAttr[$Priority, GenericCard, LIST[STANDARDjobAttributes, jobPriority]];
RegisterAttr[$Plex, Plex, LIST[plex]];
RegisterAttr[$Staple, Staple, LIST[finishing]];
RegisterAttr[$ImageShiftHorizontal, ImageShift, LIST[xImageShift]];
RegisterAttr[$ImageShiftVertical, ImageShift, LIST[yImageShift]];
RegisterAttr[$AccountInfo, GenericString, LIST[jobAccountName]];
RegisterAttr[$Media, Media, LIST[media]];
RegisterAttr[$DocEndMessage, GenericString, LIST[docEndMessage]];
RegisterAttr[$, ];
Commander.Register["IPAttrDebug", IPAttrDebugCommand];
END.