[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]

Guide to Printers and Printing


Calculating Page Length Using Printer Colon File Escape Sequences

The printer colon file for an ASCII queue on an IBM 4029 LaserPrinter defines page length, in lines, with the work attribute wL. Obtaining a numeric value for wL involves evalutating embedded references in the definition of wL. As formatted by the lsvirprt commmand, wL is defined as follows:

Page Length In Chars, Using Length From Data Base (used in
 pipelines)
wL = %?%Cl%t%f!l%e%I_l%;

 %?            <IF>
     %Cl       PUSH: (1 If -l Flag on Command Line; Otherwise 0)
 %t            <THEN>
     %f!l      For Each Flag x on Command Line: "-xArgument" ->
OUTPUT
 %e            <ELSE>
     %I_l      INCLUDE: (LINES per page)
 %;            <END>

The %Cl checks to see if the l flag was used on the command line; if it was, then a 1 is pushed onto the stack, else a 0 is pushed onto the stack. In this case, the l flag was not used on the command line so a 0 is pushed onto the stack. The %t checks for a true (non-zero) value on the stack and, not finding one, executes the %e (else) construct %I_l.

_l is defined as %IwY, shown below as formatted by the lsvirprt command.

Default Page Length (lines)
wY = %?%G_z%{1}%&%t%GwJ%e%GwK%;%G_v%*%{300}%/%d

 %?           <IF>
     %G_z     PUSH: (Page ORIENTATION)
     %{1}     PUSH: (Integer Constant 1)
     %&       PUSH: (pop2 & pop1) -- Bitwise AND
 %t           <THEN>
     %GwJ     PUSH: (Primary Page Width (-z 0) or Secondary Page
                     Length (-z1), in pels)
 %e           <ELSE>
     %GwK     PUSH: (Primary Page Length (-z 0) or Secondary Page
                     Width (-z1), in pels)
 %;           <END>
 %G_v         PUSH: (LINE DENSITY (lines per inch))
 %*           PUSH: (pop2 * pop1)
 %{300}       PUSH: (Integer Constant 300)
 %/           PUSH: (pop2 / pop1)
 %d           POP -> ASCII String -> OUTPUT

The calculation of _l begins by pushing the value of _z, page orientation, onto the stack. The job submission command being used in this example, qprt -a1 -Pasc -fp -z1 -p12 -scourier -C -N3 /etc/motd, specifies a z value of 1, so a 1 is pushed onto the stack. The %{1} pushes another 1 onto the stack, after which the %& pops the top two values (both 1s) off the stack and performs a bitwise AND with the two values. The result of the bitwise AND, a 1, is pushed onto the stack.

Note: The test is a bitwise AND instead of a simple test for equality because the legal values for the z flag are 0, 1, 2, and 3, correpsonding to the legal number of 90 degree rotations that can be applied to a printed page.

The next %t finds a 1 on the stack and so the then clause, %GwJ, is resolved before any more work is done on resolving _l.

As formatted by lsvirprt, wJ is defined as follows:

Primary Page Width (-z 0) or Secondary Page Length (-z1), in pels
wJ = %G_Q%Pq%?%GWu%{3}%<%t%?%gq%{1}%=%t%{2400}%e%gq%{2}%=%t%{2400
}%e%gq%{3}%=%t%{1999}%e%gq%{4}%=%t%{2330}%e%{2025}%;%e%?%gq%{1}%=
%t%{1012}%e%gq%{2}%=%t%{1012}%e%gq%{3}%=%t%{1087}%e%gq%{4}%=%t%{1
149}%e%gq%{5}%=%t%{1763}%e%{1928}%;%;%d

 %G_Q          PUSH: (PAPER SIZE override for input paper source)
 %Pq           POP -> Internal Variable q
 %?            <IF>
     %GWu      PUSH: (Calculate value for paper source based on _
                      O and _u.)
     %{3}      PUSH: (Integer Constant 3)
     %<        PUSH: (pop2 < pop1 ?)
 %t            <THEN>
     %?        <IF>
         %gq   PUSH: (Internal Variable q)
         %{1}  PUSH: (Integer Constant 1)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{2400}  PUSH: (Integer Constant 2400)
     %e        <ELSE>
         %gq   PUSH: (Internal Variable q)
         %{2}  PUSH: (Integer Constant 2)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{2400}  PUSH: (Integer Constant 2400)
     %e        <ELSE>
         %gq   PUSH: (Internal Variable q)
         %{3}  PUSH: (Integer Constant 3)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{1999}  PUSH: (Integer Constant 1999)
     %e        <ELSE>
         %gq   PUSH: (Internal Variable q)
         %{4}  PUSH: (Integer Constant 4)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{2330}  PUSH: (Integer Constant 2330)
     %e        <ELSE>
         %{2025}  PUSH: (Integer Constant 2025)
     %;        <END>
 %e            <ELSE>
     %?        <IF>
         %gq   PUSH: (Internal Variable q)
         %{1}  PUSH: (Integer Constant 1)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{1012}  PUSH: (Integer Constant 1012)
     %e        <ELSE>
         %gq   PUSH: (Internal Variable q)
         %{2}  PUSH: (Integer Constant 2)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{1012}  PUSH: (Integer Constant 1012)
     %e        <ELSE>
         %gq   PUSH: (Internal Variable q)
         %{3}  PUSH: (Integer Constant 3)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{1087}  PUSH: (Integer Constant 1087)
     %e        <ELSE>
         %gq   PUSH: (Internal Variable q)
         %{4}  PUSH: (Integer Constant 4)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{1149}  PUSH: (Integer Constant 1149)
     %e        <ELSE>
         %gq   PUSH: (Internal Variable q)
         %{5}  PUSH: (Integer Constant 5)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{1763}  PUSH: (Integer Constant 1763)
     %e        <ELSE>
         %{1928}  PUSH: (Integer Constant 1928)
     %;        <END>
 %;            <END>
 %d            POP -> ASCII String -> OUTPUT

The calculation of wJ begins by pushing the value of _Q, the paper size override for the input paper source, onto the stack. The value of _Q is defined as %IwQ. As formatted by the lsvirprt command, wQ is defined as follows:

Paper or Envelope Size For the Paper Source Selected By the -O
and -u Flag Values (Refer to the s0, s1, s2, s3, and s4
attributes)
wQ = 
%?%GWu%{0}%=%t%Gs0%e%GWu%{1}%=%t%Gs1%e%GWu%{2}%=%t%Gs2%e%GWu%{3}%
=%t%Gs3%e%Gs4%;%d

 %?            <IF>
     %GWu      PUSH: (Calculate value for paper source based on
_O and _u.)
     %{0}      PUSH: (Integer Constant 0)
     %=        PUSH: (pop2 = pop1 ?)
 %t            <THEN>
     %Gs0      PUSH: (PAPER SIZE for manual paper feed)
 %e            <ELSE>
     %GWu      PUSH: (Calculate value for paper source based on
_O and _u.)
     %{1}      PUSH: (Integer Constant 1)
     %=        PUSH: (pop2 = pop1 ?)
 %t            <THEN>
     %Gs1      PUSH: (PAPER SIZE for tray 1 (upper))
 %e            <ELSE>
     %GWu      PUSH: (Calculate value for paper source based on
_O and _u.)
     %{2}      PUSH: (Integer Constant 2)
     %=        PUSH: (pop2 = pop1 ?)
 %t            <THEN>
     %Gs2      PUSH: (PAPER SIZE for tray 2 (lower))
 %e            <ELSE>
     %GWu      PUSH: (Calculate value for paper source based on
_O and _u.)
     %{3}      PUSH: (Integer Constant 3)
     %=        PUSH: (pop2 = pop1 ?)
 %t            <THEN>
     %Gs3      PUSH: (ENVELOPE SIZE for envelope feeder)
 %e            <ELSE>
     %Gs4      PUSH: (ENVELOPE SIZE for manual envelope feed)
 %;            <END>
 %d            POP -> ASCII String -> OUTPUT

The calculation of wQ begins by pushing the value of Wu, onto the stack. As formatted by the lsvirprt command, the value of Wu is defined as follows:

Calculate value for paper source based on _O and _u.
Wu = 
%?%CO%t%?%G_O%{1}%=%t%?%Cu%t%?%G_u%{2}%>%t%{4}%e%{0}%;%e%{0}%;%e%
G_u%;%e%G_u%;%d

 %?            <IF>
     %CO       PUSH: (1 If -O Flag on Command Line; Otherwise 0)
 %t            <THEN>
     %?        <IF>
         %G_O  PUSH: (Type of INPUT PAPER HANDLING (backward 
compatibility
               purpose only))
         %{1}  PUSH: (Integer Constant 1)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %?    <IF>
             %Cu  PUSH: (1 If -u Flag on Command Line; Otherwise 0)
         %t    <THEN>
             %?  <IF>
                 %G_u  PUSH: (Input PAPER SOURCE)
                 %{2}  PUSH: (Integer Constant 2)
                 %>  PUSH: (pop2 > pop1 ?)
             %t  <THEN>
                 %{4}  PUSH: (Integer Constant 4)
             %e  <ELSE>
                 %{0}  PUSH: (Integer Constant 0)
             %;  <END>
         %e    <ELSE>
             %{0}  PUSH: (Integer Constant 0)
         %;    <END>
     %e        <ELSE>
         %G_u  PUSH: (Input PAPER SOURCE)
     %;        <END>
 %e            <ELSE>
     %G_u      PUSH: (Input PAPER SOURCE)
 %;            <END>
 %d            POP -> ASCII String -> OUTPUT

The calculation for the value of Wu begins by evaluating %CO, which pushes a 1 onto the stack if the O flag was specified on the command line, else it pushes a 0 onto the stack. The job submission command being used in this example did not use the O flag, so a 0 is pushed onto the stack. The next %t, finding a 0 on the stack, skips the next 23 lines of printer colon file escape sequences and evaluates the %e (else) clause on the fourth line from the bottom of the formatted form of the Wu attribute. The else clause is %G_u, which pushes the value of _u, the input paper source, onto the stack. The default value for _u for this virtual printer is 1, so a 1 is pushed onto the stack. The next %; terminates the original %?. The only remaining escape sequence, %d, pops the top value (a 1) off the stack and returns it in ASCII format to the in-progress calculation of wQ.

The 1 returned to the in-progress calculation of wQ is the value of Wu, and is pushed onto the stack. The next %{0} pushes a 0 onto the stack. %= pops the top two values (a 0 and a 1) off the stack and, checking them for equality, fails; a 0 is pushed onto the stack.

The next %t finds the 0 and so skips the %Gs0 and instead evaluates the %e (else) clause. Wu (a 1) is again pushed onto the stack. The %{1} pushes another 1 onto the stack. The %= again pops the top two values ( two 1s) off the stack and, checking them for equality, succeeds; a 1 is pushed onto the stack.

The next %t finds the 1 and so evaluates the %Gs1. The s1 attribute is a number representing the paper size for paper tray 1, the upper paper tray, and its default value in this virtual printer definition is 1. This 1 is pushed onto the stack. All but the very last of the remaining printer colon escape sequences in the evaluation of wQ are skipped. The %d pops the top value (a 1) off the stack and returns it in ASCII format to the in-progress calculation of wJ.

The 1 returned to the in-progress caclulation of wJ is the value of _Q, and is pushed onto the stack. It is immediately popped back off the stack and stored in the internal variable q. Wu, already determined to be 1, is again pushed onto the stack. %{3} pushes a 3 onto the stack, then the %< pops the top two values off the stack and checks to see if the second value popped is less than the first value popped. 1 is less than 3, so a 1 is pushed onto the stack. The %t finds the 1 and so enters the if-then-else-then-else-then-else... sequence looking for an integer to pair with the paper size value calculated for _Q.

The %gq fetches the stored value of _Q from the internal variable q, and pushes it onto the stack. The %{1} pushes another 1 onto the stack. The %= pops the top two values (two 1s) off the stack and, checking them for equality, succeeds; a 1 is pushed onto the stack. The %t finds the 1 and so evaluates the %{2400}, which pushes 2400 onto the stack. The calculation of wJ then falls through all but the last line of the remaining printer colon file escape sequences defining wJ. The last escape sequence, %d, pops the top value, 2400, off the stack and returns it, in ASCII format, to the in-progress calculation of wY.

The 2400 returned to the in-progress calculation of wY is the value of wJ, and is pushed onto the stack. The %GwK in the else clause is skipped and the %; terminates the if-then-else sequence. The %G_v fetches the line density (in lines per inch), 6, and pushes it onto the stack. The %* pops the top two values (a 6 and a 2400) off the stack, multiplies them together, and pushes the result (14400) back onto the stack. The %{300} pushes a 300 onto the stack. The %/ pops the top two values (a 14000 and a 300) off the stack, divides the second value popped off the stack by the first value popped off the stack, and pushes the result (48) onto the stack. The %d pops the top value (48) off the stack and returns it to the in-progress calculation of wL.

The 48 returned to the in-progress calculation of wL is the value of _l. The value of wL was originally referenced in the determination of the value of the ia attribute, the input datastream pipeline for ASCII jobs. The number 48 replaces the %IwL in that determination, so the value of the -! flag to pioformat becomes /usr/lib/lpd/pio/fmtrs/piof5202 -l48. The -l48 can be seen in the original diagnostic message from piobe that was the basis of this discussion; it is part of the PIPELINE OF FILTERS section of the mail sent by the qdaemon on behalf of piobe.

The calculation of the value associated with the -w flag to piof5202 is described in Calculating Page Width Using Printer Colon File Escape Sequences .

The following "Calculation of Page Length" figure depicts the stack operations (as described above) used to obtain a final numeric value for page length in lines. The following numbered steps correspond to the numbers on the left side of the columns in the figure, and provide a step-by-step description of the evaluation of the printer colon file escape sequences defining page length, in lines, for this particlular queue (asc), colon file, and command line.

Figure 4-1. Calculation of Page Length

Graphic: Calculation of Page Length.

  1. %Cl - Pushes a 0 onto the stack since the l flag was not used on the command line.
  2. %I_l - Calls for the evaluation of _l.
  3. %G_z - Pushes a 1 onto the stack.
  4. %{1} - Pushes a 1 onto the stack.
  5. %& - Pops the top two values (two 1s) off the stack, performs a bitwise AND on the two values, and pushes the resultant 1 onto the stack.
  6. %t - Pops the 1 off the stack and, since it is a TRUE (non-zero) value, calls for the evaluation of %GwJ. The stack labeled _l is now empty.
  7. %GwJ - Calls for the evaluation of wJ.
  8. %G_Q - Calls for the evaluation of wQ.
  9. %GwQ - Calls for the evaluation of %GWu.
  10. %GWu - Calls for the evaluation of Wu.
  11. %CO - Pushes a 0 onto the stack since the O flag was not used on the command line.
  12. %t - Pops the 0 off the stack and, since it is a FALSE (zero) value, calls for the evaluation of %G_u. The stack labeled Wu is now empty.
  13. %G_u - Pushes a 1 onto the stack.
  14. %d - Pops the 1 off the stack and returns it, in ASCII format, to the in-progress calculation of wQ.
  15. %{0} - Pushes a 0 onto the stack.
  16. %= - Pops the 0 and 1 off the stack, compares them for equality, and pushes the resultant 0 onto the stack.
  17. %t - Pops the 0 off the stack and, since it is a FALSE (zero) value, calls for the evaluation of %GwU.
  18. %GWu - This value is already known, so a 1 is pushed onto the stack.
  19. %{1} - Pushes a 1 onto the stack.
  20. %= - Pops the two 1s off the stack, compares them for equality, and pushes the resultant 1 onto the stack.
  21. %t - Pops the 1 off the stack and, since it is a TRUE (non-zero) values, calls for the evaluation of %Gs1.
  22. %Gs1 - Pushes a 1 onto the stack.
  23. %d - Pops the 1 off the stack and returns it, in ASCII format, to the in-progress calculation of wJ.
  24. %Pq - Pops the 1 off the stack and stores it in the internal variable q.
  25. %GWu - This value is already known, so a 1 is again pushed onto the stack.
  26. %{3} - Pushes a 3 onto the stack.
  27. %< - Pops the 3 and the 1 off the stack and, since 1 is less than 3, pushes a 1 onto the stack.
  28. %t - Pops the 1 off the stack and, since it is a TRUE (non-zero) values, calls for the evaluation of %gq.
  29. %gq - Pushes the value of the internal variable q, a 1, onto the stack.
  30. %{1} - Pushes a 1 onto the stack.
  31. %= - Pops the two 1s off the stack, compares them for equality, and pushes the resultant 1 onto the stack.
  32. %t - Pops the 1 off the stack and, since it is a TRUE (non-zero) values, calls for the evaluation of %{2400}.
  33. %{2400} - Pushes a 2400 onto the stack.
  34. %d - Pops the 2400 off the stack and returns it, in ASCII format, to the in-porgress calculation of _l.
  35. %G_v - Pushes a 6 onto the stack.
  36. %* - Pops the 6 and the 2400 off the stack, multiplies them together, and pushes the resultant 14400 onto the stack.
  37. %{300} - Pushes a 300 onto the stack.
  38. %/ - Pops the 300 and the 14400 off the stack, divides 14400 by 300, and pushes the resultant 48 onto the stack.
  39. %d - Pops the 48 off the stack and returns it, in ASCII format, to the in-progress determination of ia, the input data stream pipeline for ASCII jobs.

Why the Stack Language Describing Page Length Works

Going beyond the mechanical description of what happens when piobe resolves the reference to %IwL, here is a description of why the printer colon file escape sequence logic described above works.

The IBM LaserPrinter 4029 Series Technical Reference contains a figure and a table that together describe the printable and unprintable areas on a page, and the paper and envelope dimensions, in pels, for standard paper and envelope sizes. For instance, the printable area on an 8.5 x 11 (width by length) inch page is 2400 x 3200 pels (width by length). Note that if the page is rotated either 90 or 270 degrees for landscape printing, the dimensions are swapped and become 3200 x 2400 pels (width by length).

The evaluation of %IwL begins by checking to see if the l flag was used on the command line; if it was, then there are no calculations to perform. The requested value will be used. (That is not a promise that it will work, just that it will be used.) If the l flag was not used on the command line, then piobe has to figure out how long the page is under the current job environment, as determined by other command line flags and by colon file defaults.

The first item checked in the evaluation of _l (page length) is page orientation (_z). As noted above, rotating the page by odd multiples of 90 degrees flips the page dimensions. Looking at the if-then-else statement that is the beginning of the definition of wY, it can be seen that the value of _z is a switch that controls which of wJ and wK will be used for page length. If the page has a portrait orientation, then wK is length. If the page has a landscape orientation, then wJ is length. After the page length in pels is resolved, the remainder of the escape sequences in the definition of wY just take vertical line denisty into account while converting the number of pels to the number of lines.

wJ is selected because the page orientation is landscape. Thus far all that is known is that the dimensions have been flipped; what the dimensions actually are is still unknown. The evaluation of wJ begins by fetching the value (if any) of a command line usage of the Q flag, which is a printer-dependent value requesting a specific paper size. If the Q flag was used on the command line, then that value will be used to select the paper length in pels, otherwise a value for Q will be determined by evaluating Wu, which is a value for the paper source based on the attributes _O (type of input paper handling) and _u (input paper source). Note that _Q is defined as %IwQ, whose definition begins with %IWu.

Since Q was not used on the command line, the evaluation of Wu determines that the O flag wasn't used either, and so executes the else clause in the outer if-then-else statement in the definition of Wu, returning the default colon file value of _u, 1, to the evaluation of wQ.

Since this is as deep as the nesting of escape sequences goes for the evaluation of _l, it is worth taking a closer look at the logic defining Wu. Keep in mind the definitions and legal values for O, u, and Q, which are:

The escape sequences defining Wu say this:

The definition of wQ is an if-then-else-then-else-then-else-then-else statement that repeatedly compares the value of Wu to the integers 0, 1, 2, and 3, looking for a match. The match selects the value of one of the attriubes s0, s1, s2, s3, or s4, respectively (s4 is selected when there is no other match). The items these attributes define are as follows:

In the virtual printer definition for an ASCII queue on an IBM 4029 LaserPrinter, there are only two unique values for these five attributes: s0, s1, and s2 are all 1, while s3 and s4 are both 3.

Looking back up the nested escape sequences, you can see that the definition of wJ is composed of an outer if-then-else statement. Both the if and the else pieces of this statement contain a chain of if-then-else-then-else... statements. The value of Wu (which is a value for paper source, based on O and u) determines whether the if or the else piece of the outer statment executes; if Wu is 1 or 2 (less than 3), then the if piece executes; otherwise the else piece executes. It is in the final determination of wJ that the page length, in pels, is fixed.

The if piece of the outer if-then-else statement defining wJ selects a pel value from a range of non-envelope paper sizes; the else piece of the outer if-then-else statement selects a pel value from a range of envelope paper sizes. Wu controls which piece of the if-then-else statement executes but, once either the if or else piece has been chosen, it is the value of Q that causes a pel value to be selected. The five cases listed above work like this:

Case 1: Either the command line value of u or the default from the colon file (1, primary paper tray) is returned to the evaluation of wQ. The remaining escape sequences in the definiton of wQ test the value of Wu and select the value of one of s0, s1, s2, s3, or s4. That value is in turn returned to the evaluation of wJ. If u is 1 or 2 , then Q will be 1 (non-envelope paper size). If u is 3, then Q will be 3 (envelope paper size). When the evaluation of wJ is resumed, a u value of 1 or 2 will direct the process into the if piece of the outer if-then-else statement, and the Q value of 1 will select a page length of 2400 pels. A u value of 3 will direct the process into the else piece of the outer if-then-else statement, and the Q value of 3 will select an envelope page length of 1087 pels.

Case 2: Same as case 1.

Case 3: The user-specified manual paper handling on the command line but did not specify a paper source so Wu is assigned the value 0, and that value is returned to the evaluation of wQ. The 0 will cause wQ to be assigned the value of s0 (the paper size for manual paper feed, a 1). When the evaluation of wJ is resumed, the u value of 0 will direct the process into the if piece of the outer if-then-else statement, and the Q value of 1 (s0) will select a page length of 2400 pels.

Case 4: The user specified manual paper handling on the command line and also used the u flag to specify either the primary or alternate paper source (but definitely not envelopes). As with case 3, a page length of 2400 pels will be chosen.

Case 5: The user-specified manual paper handling on the command line and also used the u flag to specify an envelope paper source so Wu is assigned the value 4, and that value is returned to the evaluation of wQ. The 4 will cause wQ to be assigned the value of s4 (the envelope size for manual envelope size, a 3). When the evaluation of wJ is resumed, the u value of 4 will direct the process into the else piece of the outer if-then-else statement, and the Q value of 3 will select an envelope length of 1087 pels.

Our example is case 1: neither the O nor the u flags were used on the command line, so Wu is assigned a value of 1, the default _u value for this colon file. When the evaluation of wQ resumes, the match occurs on s1, and a 1 is returned to the evaluation of wJ. The u value of 1 direct the process into the if piece of the outer if-then-else statement, and the Q value of 1 selects a page length of 2400 pels. This value is returned to the evaluation of _l.

The remaining printer colon file escape sequences defining _l reason that if there are 2400 pels available (vertically), and if we want six lines per inch, and if there are 300 pels per inch (the resolution of the printer), then 48 lines can be printed on a page. The value 48 is returned to the evaluation of ia. That's basically where the -l48 in the PIPELINE OF FILTERS came from.


[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]