И, наконец, поскольку
eqn
выделяет курсивом любую строку букв, которые она не распознает, довольно просто выделять обычные слова курсивом. Последовательность
@Word@
например, печатается как
Word. Но будьте внимательны:
eqn
распознает некоторые обычные символы (такие, как
from
и
to
) и специальным образом их рассматривает: она "глотает" пробелы, поэтому указанный прием следует применять с осторожностью.
Получение выходного потока
Как только ваш документ готов, вы должны соединить все препроцессоры и
troff
в цепочку, чтобы получить выходной поток. Порядок команд следующий:
tbl
,
eqn
,
troff
. Если вы просто используете
troff
, то печатайте
$ troff -ms <i>имена_файлов</i>
(или
-mm
)
Иначе вам придется задать аргумент
<i>имена_файлов</i>
первой команде в цепочке и дать остальным командам читать их стандартный входной поток, как показано ниже:
$ eqn <i>имена_файлов</i> | troff -ms
или
$ tbl <i>имена_файлов</i> | eqn | troff -ms
Неудобно следить за тем из препроцессоров, который действительно должен печатать какой-то отдельный документ. Мы сочли уместным написать программу
doctype
, обеспечивающую вывод соответствующей последовательности команд:
$ doctype ch9.*
cat ch9.1 ch9.2 ch9.3 ch9.4 | pic | tbl | eqn | troff -ms
$ doctype hoc.ms
cat hoc.ms | tbl | eqn | troff -ms
$
Программа
doctype
реализована с помощью инструментов, рассмотренных в гл. 4. В частности, программа
awk
отыскивает последовательность команд, используемую препроцессорами, и печатает строку команд, которые нужно вызвать, чтобы отформатировать документ. Она также находит команду
.PP
(абзац) для форматирования пакетом запросов
ms
.
$ cat doctype
# doctype: synthesize proper command line for troff
echo -n "cat $* | "
egrep -h (EQ|TS|\[|PS|IS|PP)' $* |
sort -u |
awk '
/^\.PP/ { ms++ }
/^\.EQ/ { eqn++ }
/^\.TS/ { tbl++ }
/^\.PS/ { pic++ }
/^\.IS/ { ideal++ }
/^\.\[/ { refer++ }
END {
if (refer > 0) printf "refer | "
if (pic > 0) printf "pic | "
if (ideal > 0) printf "ideal | "
if (tbl > 0) printf "tbl | "
if (eqn > 0) printf "eqn | "
printf "troff "
if (ms > 0) printf "-ms"
printf "\n"
} '
$
(Флаг
-h
заставляет ее подавлять заголовки имен файлов на каждой строке: к сожалению, этот аргумент есть не во всех версиях системы.) При сканировании входного потока собирается информация о том, какие компоненты используются. После просмотра входной поток обрабатывается в требуемой последовательности для печати выходного текста. В формировании документов
troff
со стандартными препроцессорами есть специфика, и главная задача состоит в том, чтобы заставить "думать" об этом саму машину.
Программа
doctype
в нашем примере подобна
bundle
-программе, которая создает программу. Однако в таком виде она требует от пользователя вновь вводить строку для
shell
. В одном из приводимых ниже упражнений вам предлагается это исправить.
Когда дело дойдет до запуска реальных команд
troff
, не забывайте, что поведение программы зависит от системы: на некоторых установках она управляет наборным устройством непосредственно, в то время как на других выдает в стандартный выходной поток информацию, которая должна быть послана на наборное устройство отдельной программой.
Между прочим, в новой версии этой программы не предусмотрена программа
egrep
или
sort
;
awk
сама просматривает весь входной поток. Для больших документов такой вариант оказывается слишком медленным, поэтому для ускорения поиска мы добавили
egrep
и затем
sort -u
, чтобы избавиться от дублирования. При построении типичных документов накладные расходы по созданию двух дополнительных разбирающих данные процессов меньше, чем запуск
awk
в тех же целях с большим объемом входного текста.
В качестве иллюстрации сравним
doctype
с версией, только запускающей
awk
применительно к содержимому данной главы (около 52 000 символов):
$ time awk '... doctype without egrep ...' ch9.*
cat ch9.1 ch9.2 ch9.3 ch9.4 | pic | tbl | eqn | troff -ms
real 31.0
user 8.9
sys 2.8
$ time doctype ch9*
cat ch9.1 ch9.2 ch9.3 ch9.4 | pic | tbl | eqn | troff -ms
real 7.0
user 1.0
sys 2.3
$
Сравнение, очевидно, в пользу версии с тремя процессами. (Работа была выполнена в однопользовательском режиме; соотношение значений времени показало бы даже более значительное преимущество версии
egrep
и при повышенной нагрузке на систему.) Отметим, что, прежде чем начать оптимизацию, мы получили сначала простую работающую версию.