В файле описания принтера 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 и данной командной строке. Номера шагов в этом списке соответствуют числам, указанным слева от блоков на рисунке.
Ниже приведена логическая схема процедуры, выполняемой программой 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 в почтовом сообщении КОНВЕЙЕР ФИЛЬТРОВ.