[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]

Руководство по принтерам и печати


Вычисление ширины страницы по escape-последовательностям в файле описания принтера

В файле описания принтера IBM 4029 LaserPrinter для очереди вывода ASCII ширина страницы в символах задается с помощью атрибута wW. Команда lsvirprt (Просмотр, форматирование и изменение определений виртуальных принтеров) вычисляет значение wW следующим образом:

 Ширины страницы в символах с учетом значения из базы данных (применяется с конвейерами)
wW = %?%Cw%t%f!w%e%I_w%;
 %?            <IF>
     %Cw       PUSH: (1, если в командной строке есть флаг -w; 0 в противном случае)
 %t            <THEN>
     %f!w      Для каждого флага x в командной строке: "-xАргумент" -> 
OUTPUT
 %e        <ELSE>
     %I_w      INCLUDE: (число столбцов на странице)
 %;        <END>

Команда %Cw проверяет, есть ли в командной строке флаг w; если он есть, то в стек заносится число 1; в противном случае в стек заносится 0. В данном случае в командной строке не был указан флаг w, и поэтому в стек будет добавлен 0. Команда %t проверяет, истинное (ненулевое) ли значение находится в стеке и (поскольку в стек только что был добавлен 0) выполняет оператор %e (else), в котором указана команда %I_w. Команда %tпроверяет, истинное ли (ненулевое) значение находится в стеке, и (поскольку в стек только что был добавлен 0) выполняет оператор %e (else) construct %I_w.

Согласно следующей процедуре, команда lsvirprt присваивает атрибуту _w значение %IwX.

 Ширина страницы по умолчанию (в символах)
wX = 
%?%G_z%{1}%&%t%GwK%e%GwJ%;%?%G_p%{17}%=%t%{171}%e%G_p%{10}%*%;%*%
?%G_W%t%{6000}%e%{3000}%;%/%d
 %?            <IF>
     %G_z      PUSH: (ориентация страницы)
     %{1}  PUSH: (числовая константа 1)
     %&        PUSH: (pop2 & pop1) -- поразрядная конъюнкция
 %t            <THEN>
     %GwK      PUSH: (основная длина страницы (-z 0) или вспомогательная ширина страницы
               (-z 1) в точках)
 %e        <ELSE>
     %GwJ      PUSH: (основная ширина страницы (-z 0) или вспомогательная длина страницы
               (-z 1) в точках)
 %;        <END>
 %?        <IF>
     %G_p      PUSH: (число символов на дюйм)
     %{17}     PUSH: (числовая константа 17)
     %=    PUSH: (pop2 = pop1 ?)
 %t            <THEN>
     %{171}    PUSH: (числовая константа 171)
 %e        <ELSE>
     %G_p      PUSH: (число символов на дюйм)
     %{10}     PUSH: (числовая константа 10)
     %*            PUSH: (pop2 * pop1)
 %;        <END>
 %*            PUSH: (pop2 * pop1)
 %?        <IF>
     %G_W      PUSH: (печатать символы двойной ширины?)
 %t            <THEN>
     %{6000}   PUSH: (числовая константа 6000)
 %e        <ELSE>
     %{3000}   PUSH: (числовая константа 3000)
 %;        <END>
 %/            PUSH: (pop2 / pop1)
 %d            POP -> строка ASCII -> OUTPUT

Вычисление значения _w начинается с занесения в стек значения _z (ориентация страницы). В данном примере задание было запущено с помощью команды qprt -a1 -Pasc -fp -p12 -scourier -C -N3 /etc/motd т.е. атрибуту z было присвоено значение 1. Поэтому в стек заносится значение 1. Команда %{1} добавляет в стек еще одно значение 1, после чего команда %& забирает два значения из стека (в данном примере - два значения 1) и выполняет для них поразрядную конъюнкцию. Результат операции (1) заносится в стек.

Примечание: Применение конъюнкции вместо обычного сравнения операндов обусловлено тем, что для флага z допустимы значения 0, 1, 2 и 3, задающие число поворотов страницы на 90 градусов. Значения 1 и 3 (нечетные) соответствуют альбомной, а 0 и 2 (четные) - книжной ориентации.

При выполнении команды %t в стеке находится число 1, поэтому перед дальнейшими вычислениями значения _w выполняется оператор then %GwK.

В команде lsvirprt применяется следующая процедура вычисления значения атрибута wK.

 Основная длина страницы (-z 0) или вспомогательная ширина страницы (-z 1) в точках
wK = 
%G_Q%Pq%?%GWu%{3}%<%t%?%gq%{1}%=%t%{3200}%e%gq%{2}%=%t%{4100}%e%g
q%{3}%=%t%{2935}%e%gq%{4}%=%t%{3407}%e%{3050}%;%e%?%gq%{1}%=%t%{2
150}%e%gq%{2}%=%t%{2562}%e%gq%{3}%=%t%{2750}%e%gq%{4}%=%t%{2498}%
e%gq%{5}%=%t%{2604}%e%{2852}%;%;%d
 %G_Q          PUSH: (переопределение размера страницы для выбранного источника бумаги)
 %Pq           POP -> внутренняя переменная q
 %?        <IF>
     %GWu      PUSH: (определить источник бумаги по значениям _O и _u.)
     %{3}  PUSH: (числовая константа 3)
     %<        PUSH: (pop2 < pop1 ?)
 %t            <THEN>
     %?        <IF>
         %gq   PUSH: (внутренняя переменная q)
         %{1}  PUSH: (Числовая константа 1)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{3200}  PUSH: (числовая константа 3200)
     %e        <ELSE>
         %gq   PUSH: (внутренняя переменная q)
         %{2}  PUSH: (числовая константа 2)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{4100}  PUSH: (числовая константа 4100)
     %e        <ELSE>
         %gq   PUSH: (внутренняя переменная q)
         %{3}  PUSH: (числовая константа 3)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{2935}  PUSH: (числовая константа 2935)
     %e        <ELSE>
         %gq   PUSH: (внутренняя переменная q)
         %{4}  PUSH: (числовая константа 4)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{3407}  PUSH: (числовая константа 3407)
     %e        <ELSE>
         %{3050}  PUSH: (числовая константа 3050)
     %;        <END>
 %e        <ELSE>
     %?        <IF>
         %gq   PUSH: (внутренняя переменная q)
         %{1}  PUSH: (Числовая константа 1)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{2150}  PUSH: (числовая константа 2150)
     %e        <ELSE>
         %gq   PUSH: (внутренняя переменная q)
         %{2}  PUSH: (числовая константа 2)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{2562}  PUSH: (числовая константа 2562)
     %e        <ELSE>
         %gq   PUSH: (внутренняя переменная q)
         %{3}  PUSH: (числовая константа 3)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{2750}  PUSH: (числовая константа 2750)
     %e        <ELSE>
         %gq   PUSH: (внутренняя переменная q)
         %{4}  PUSH: (числовая константа 4)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{2498}  PUSH: (числовая константа 2498)
     %e        <ELSE>
         %gq   PUSH: (внутренняя переменная q)
         %{5}  PUSH: (числовая константа 5)
         %=    PUSH: (pop2 = pop1 ?)
     %t        <THEN>
         %{2604}  PUSH: (числовая константа 2604)
     %e        <ELSE>
         %{2852}  PUSH: (числовая константа 2852)
     %;        <END>
 %;        <END>
 %d            POP -> строка ASCII -> OUTPUT

Вычисление значения wK начинается с занесения в стек значения _Q - размера бумаги в выбранном устройстве подачи. Значение _Q равно %IwQ. Вычисление значения Wk аналогично вычислению wJ при определении длины страницы , то есть сводится к определению значений wQ и Wu. В контексте выполнения одного задания значения wQ и Wu не изменяются, поскольку они вычисляются в одной и той же среде. Поэтому мы воспользуемся ранее вычисленными значениями: 1 для wQ и 1 для Wu.

Значение 1, возвращенное в качестве значения _Q в процедуру вычисления атрибута wK, заносится в стек. Следующей командой оно забирается из стека и присваивается внутренней переменной q. В стек вновь заносится уже вычисленное значение Wu (1). Команда %{3} заносит в стек число 3, затем команда %< забирает два значения из стека (3 и 1) и проверяет, действительно ли второе полученное значение меньше, чем первое. Поскольку 1 меньше, чем 3, в стек заносится положительный результат (1). Затем команда %t забирает этот результат (1) из стека и начинает выполнение оператора if-then-else-then-else-then-else..., суть которого сводится к занесению в стек числа, соответствующего значению атрибута _Q.

Команда %gq заносит в стек значение внутренней переменной q (фактически - значение _Q). Команда %{1} заносит в стек значение 1. Затем команда %= забирает два значения из стека (два значения 1), сравнивает их и, получив положительный результат, заносит его в стек (1). Команда %t, забрав из стека 1, выполняет команду %{3200}, которая, в свою очередь, заносит в стек число 3200. После этого выполнение сложного условного оператора завершается и выполнение передается в последнюю строку процедуры. Последняя команда (%d) забирает из стека значение 3200 и возвращает его в формате ASCII в процедуру вычисления атрибута wX.

Значение 3200, возвращенное в качестве значения wK в процедуру wZ, заносится в стек. Команда %GwJ, относящаяся к оператору else, пропускается, и команда %; завершает выполнение условного оператора. К этому моменту в процедуре wJ оставалось учесть только факторы, влияющие на число строк на странице (в частности, число строк на дюйм). При вычислении ширины страницы нас интересуют число символов на дюйм и ширина символов (одинарная или двойная).

Следующая выполняемая команда - %G_p. Она вычисляет значение атрибута _p - число символов на дюйм для данной очереди. Значение по умолчанию для этой очереди - 10, но в команде, которая рассматривается в данном примере, была указана плотность 12 символов на дюйм (-p12), поэтому в стек будет добавлено число 12. Команда %{17} заносит в стек число 17. Команда %= забирает два значения из стека (17 и 12), сравнивает их и, поскольку они не равны, заносит в стек число 0. Команда %t забирает из стека число 0 ("ложь") и выполняет предложение %e (else). Команда %G_p вновь заносит в стек число 12. Команда %{10} заносит в стек число 10. Команда %* забирает два значения из стека (12 и 10), перемножает их и заносит в стек произведение (120). Команда %; завершает выполнение условного оператора.

Затем команда %* вновь забирает два значения из стека (120 и 3200), перемножает их и заносит произведение (384000) в стек. Команда %G_W заносит в стек значение _W. Это значение - флаг (1 или 0), указывающий ширину печатаемых символов (двойная или одинарная). Значение по умолчанию - 0. Поскольку оно не было переопределено в командной строке, в стек заносится число 0. Команда %t забирает из стека значение 0 и выполняет предложение %e (else). Команда %{3000} заносит в стек число 3000. Команда %; завершает выполнение условного оператора. Команда %/ забирает два числа из стека (3000 и 384000), делит второе на первое и заносит частное (128) в стек. Команда %d забирает число из стека (128) и возвращает его в формате ASCII в процедуру вычисления wW.

Число 128 возвращается в качестве значения _w в процедуру вычисления wW. Значение wW необходимо для вычисления значения атрибута ia - конвейера входного потока данных для заданий ASCII. В этой процедуре вместо %lwW подставляется число 128, которое присваивается флагу -! в команде вызова программы pioformat: /usr/lib/lpd/pio/fmtrs/piof5202 -l48 -w128. Значение -w128 было выдано в исходном диагностическом сообщении piobe, обсуждавшемся в этой главе; оно указано в разделе КОНВЕЙЕР ФИЛЬТРОВ почтового сообщения, отправленного пользователем qdaemon от имени процесса piobe.

Операции, выполняемые над стеком в ходе вычисления ширины страницы, проиллюстрированы на рисунке "Вычисление ширины страницы" . Ниже приведен пошаговый список этих операций, соответствующих данному файлу описания для очереди вывода asc и данной командной строке. Номера шагов в этом списке соответствуют числам, указанным слева от блоков на рисунке.


Рисунок: Вычисление ширины страницы.

  1. %Cw - Заносит в стек значение 0, поскольку в командной строке не был указан флаг w.
  2. %I_w - Вызывает команду _w.
  3. %G_z - Заносит в стек значение 1.
  4. %{1} - Заносит в стек значение 1.
  5. %& - Забирает два значения из стека (два значения 1), выполняет поразрядную конъюнкцию и заносит результат (1) в стек.
  6. %t - Забирает значение из стека (1) и, поскольку оно отлично от нуля, вызывает процедуру вычисления %GwK.
  7. %G_Q - Вызывает процедуру вычисления _Q.
  8. %GwQ - Вызывает процедуру вычисления wQ.
  9. %GWu - Вызывает процедуру вычисления Wu.
  10. %CO - Поскольку в командной строке не был указан флаг O, заносит в стек значение 0.
  11. %CO - Заносит в стек значение 0, так как в командной строке не был задан флаг O.
  12. %t - Забирает значение из стека (0) и, поскольку оно равно нулю, выполняет команду %G_u. Стек, отмеченный _Wu, теперь пуст.
  13. %G_u - Заносит в стек значение 1.
  14. %d - Забирает значение из стека (1) и возвращает его в формате ASCII в процедуру вычисления wQ.
  15. %{0} - Заносит в стек значение 0.
  16. %= - Забирает два значения из стека (0 и 1), сравнивает их, и, поскольку они не равны, заносит в стек значение 0.
  17. %t - Забирает значение из стека (0) и, поскольку оно равно нулю, выполняет команду %GWu.
  18. %{1} - Заносит в стек значение 1.
  19. %{1} - Заносит в стек значение 1.
  20. %= - Забирает из стека два значения (оба равны 1), сравнивает их, и, поскольку они равны, заносит в стек значение 1.
  21. %t - Забирает значение из стека (1) и, поскольку оно отлично от нуля, выполняет команду %Gs1.
  22. %Gs1 - Заносит в стек значение 1.
  23. %d - Забирает значение из стека (1) и возвращает его в формате ASCII в процедуру вычисления wK.
  24. %Pq - Забирает значение из стека (1), и присваивает его внутренней переменной q.
  25. %{1} - Заносит в стек значение 1.
  26. %{3} - Заносит в стек значение 3.
  27. %< Забирает два значения из стека (3 и 1) и проверяет, действительно ли второе меньше первого. Поскольку 1 меньше, чем 3, в стек заносится положительный результат (1).
  28. %t - Забирает из стека значение 1 и, поскольку оно ненулевое, вызывает процедуру вычисления %pq.
  29. %{1} - Заносит в стек значение 1.
  30. %{1} - Заносит в стек значение 1.
  31. %t - Забирает значение из стека (1) и, поскольку оно отлично от нуля, выполняет команду %{3200}.
  32. %t - Забирает из стека значение 1 и, поскольку оно ненулевое, вызывает процедуру вычисления %(3200).
  33. %{3200} - Заносит в стек число 3200.
  34. %d - Забирает значение из стека (3200) и возвращает его в процедуру вычисления _w.
  35. %G_p - Заносит в стек число 12.
  36. %{17} - Заносит в стек число 17.
  37. %= - Забирает два значения из стека (17 и 12), сравнивает их и заносит результат (0) в стек.
  38. %t - Забирает значение из стека (0) и, поскольку оно равно нулю, вызывает процедуру вычисления %G_p.
  39. %G_p - Заносит в стек число 12.
  40. %{10} - Заносит в стек число 10.
  41. %* - Забирает два значения из стека (10 и 12), перемножает их и заносит в стек произведение (120).
  42. %* - Забирает два значения из стека (120 и 3200), перемножает их и заносит в стек произведение (384000).
  43. %G_w - Заносит в стек число 0.
  44. %t - Забирает значение из стека (0) и, поскольку оно равно нулю, выполняет процедуру вычисления %{3000}.
  45. %{3000} - Заносит в стек число 3000.
  46. %/ - Забирает два числа из стека (3000 и 384000), делит второе на первое и заносит частное (128) в стек.
  47. %d - Забирает значение из стека (128) и возвращает его в формате ASCII в процедуру вычисления ia (конвейер входного потока данных для заданий ASCII).

Как работает стек процедур вычисления ширины страницы

Ниже приведена логическая схема процедуры, выполняемой программой piobe при обработке ссылки на %wW.

В технической документации по принтерам IBM LaserPrinter 4029 приведены рисунок и таблица с информацией о стандартных форматах бумаги и конвертов и размерах областей печати. Например, область печати на бумаге размером 8,5 x 11 дюймов составляет 2400 x 3200 точек (ширина х длина). Учтите, что если печать выполняется с поворотом на 90 или 270 градусов, то область печати составляет уже 3200 x 2400 точек (ширина х длина).

Вычисление значения %IwW начинается с проверки, указан ли в командной строке флаг w, поскольку если он указан, то никаких вычислений выполнять не нужно. В этом случае применяется значение данного флага. (При этом не гарантируется, что данное значение будет допустимо - оно не проверяется.) Если флаг w не указан, то программа piobe должна определить ширину страницы в текущей среде с учетом значений других флагов и информации в файле описания виртуального принтера.

В первую очередь при вычислении ширины страницы (_w) определяется ее ориентация (_z). Как указано выше, при повороте на 90 или 270 градусов размер области печати по ширине и длине изменяется на противоположный. В условном операторе, который указан в начале процедуры вычисления wK, значение _z определяет, какое из двух значений (wJ и wK) является длиной страницы. При книжной ориентации ширина страницы равна значению атрибута wK. При альбомной ориентации ширина страницы равна значению атрибута wK. После вычисления ширины страницы в точках для получения значения wY (числа символов в строке) достаточно учесть плотность символов (число символов на дюйм) и их ширину (одинарная или двойная).

Поскольку в данном примере применяется альбомная ориентация, вызывается процедура wK. К данному моменту известно лишь то, что печать выполняется с поворотом; фактический размер области печати еще не известен. Вычисление wK начинается с проверки наличия флага Q, задающего нестандартный размер бумаги. Если в командной строке указан флаг Q, ширина страницы будет вычисляться согласно его значению; в противном случае ширина бумаги будет определена по значению Wu, которое, в свою очередь, зависит от значений _O (тип устройства подачи) и _u (источник бумаги). Обратите внимание, что процедура _Q начинается с вызова процедуры %IwQ. Обратите внимание, что процедура _Q начинается с вызова процедуры %IwQ.

Поскольку в командной строке нет флага Q, вызывается процедура Wu, которая прежде всего проверяет, есть ли в командной строке флаг O. Этого флага нет, и поэтому выполняется ветвь условного оператора, возвращающая значение по умолчанию для атрибута _u из файла описания виртуального принтера. Это значение равно 1, и оно передается в процедуру вычисления wQ.

Поскольку при вычислении _w в конце концов вызывается процедура Wu, мы подробно рассмотрим ее. В этой процедуре используются значения атрибутов O, u и Q:

В процедуре вычисленияWu рассматриваются следующие случаи:

Процедура wQ состоит из сложного условного оператора if-then-else-then-else-then-else-then-else, в котором значение Wu последовательно сравнивается с числами 0, 1, 2 и 3. По результатам сравнения выбирается значение атрибута s0, s1, s2, s3 или s4 соответственно (s4 выбирается в случае, если совпадение не найдено). Этим атрибутам присвоены следующие значения, зависящие от конкретного принтера:

В описании виртуального принтера для очереди вывода ASCII и принтера IBM 4029 LaserPrinter предусмотрены следующие значения для этих атрибутов: s0, s1 и s2 равны 1, а s3 и s4 равны 3.

Затем управление возвращается в процедуру wK, которая также фактически состоит из сложного условного оператора. И ветвь if, и ветвь else этого оператора содержат цепочку операторов if-then-else-then-else... Значение атрибута Wu (источник бумаги, зависящий от значений O и u) определяет ветвь внешнего оператора if: если Wu равно 1 или 2 (меньше 3), то выполняется предложение %t; в противном случае выполняется предложение %e. Это последний этап вычисления значения атрибута wK - ширины страницы в точках.

Случай 1: В процедуру вычисления wQ возвращается значение u, указанное в командной строке, или значение по умолчанию из файла описания виртуального принтера (1, основной лоток подачи бумаги). Оставшиеся команды процедуры wQ в зависимости от значения Wu выбирают значение одного из атрибутов s0, s1, s2, s3 и s4. Выбранное значение возвращается в процедуру вычисления wK. Если u равно 1 или 2, то Q будет присвоено значение 1 (печать на обычной бумаге). Если u=3, то Q будет присвоено значение 3 (печать на конвертах). В первом случае (u=1 или 2) в процедуре wK выполняется предложение then (%t) внешнего оператора if-then-else, и поскольку Q=1, ширина страницы будет установлена равной 3200 точкам. Во втором случае (u=3), выполняется предложение else (%e) внешнего оператора if-then-else, и поскольку Q=3, ширина конвертов будет установлена равной 2750 точкам.

Случай 2: Совпадает со случаем 1.

Случай 3: Поскольку пользователь указал, что бумага будет подаваться вручную, но не задал устройство подачи, атрибуту Wu было присвоено значение 0, и оно было передано в процедуру wQ. В результате атрибуту wQ присваивается значение s0 (размер бумаги при подаче вручную -1). Поскольку атрибут u равен нулю, в процедуре wK будет выполняться предложение then внешнего оператора if-then-else. В силу того, что Q=1, ширина страницы будет установлена равной 3200 точкам.

Случай 4: Пользователь указал, что бумага будет подаваться вручную, и с помощью флага u задал основное или вспомогательное устройство подачи бумаги (но не устройство подачи конвертов). Так же, как и в случае 3, ширина страницы будет установлена равной 3200 точкам.

Случай 5: Пользователь указал, что подача будет осуществляться вручную, и с помощью флага u задал в качестве источника бумаги устройство подачи конвертов. В результате атрибуту Wu было присвоено значение 4. В результате атрибуту wQ присваивается значение s4 (размер конвертов при подаче вручную - 3). Поскольку атрибуту u присвоено значение 4, в процедуре wK выполняется предложение else внешнего оператора if-then-else. В силу того, что Q=3, ширина конвертов будет установлена равной 2498 точкам.

Затем в процедуре _w на основании значений 3200 (число точек на странице в ширину), 12 (число символов на дюйм) и 300 (число точек на дюйм) вычисляется число символов в строке - 128. Для того чтобы проверить, возможна ли печать с плотностью 17 символов на дюйм, число символов на дюйм и разрешение принтера умножаются на 10. Это вызвано тем, что фактически плотность 17 соответствует 17,1 символа на дюйм, но все вычисления должны быть целочисленными. Значение 128 возвращается в процедуру вычисления ia. Этим и объясняется появление строки -128 в почтовом сообщении КОНВЕЙЕР ФИЛЬТРОВ.


[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]