Calculation of page length using printer colon file escape sequences

You can use printer colon file escape sequences to calculate page length.

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, corresponding 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 Calculation of 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 1. Calculation of Page Length
Calculation of Page Length.
  1. %Cl - Pushes a 0 onto the stack because 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, because 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 because the O flag was not used on the command line.
  12. %t - Pops the 0 off the stack and, because 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, because 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, because 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, because 1 is less than 3, pushes a 1 onto the stack.
  28. %t - Pops the 1 off the stack and, because 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, because 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.