Руководство пользователя для GNU Awk
16. Практические awk-программы
16.2 Разные awk-программы
16.2.7 Извлечение программ из файлов Texinfo Source
И настоящая глава и предыдущая глава 15 [Библиотека awk-функций], стр. 169), содержат большое количество awk-программ. Если вы хотите поэкспериментировать с этими программами, будет скучно перепечатывать их вручную. Мы предлагаем программу, которая может извлекать части Texinfo input file в отдельные файлы.
Эта книга написана на Texinfo, языке GNU для форматирования проектной документации. Единый Texinfo source file может быть использован для получения и печатной и диалоговой документации. Texinfo полностью документирован в Texinfo-- GNU Documentation Format, и доступен из Free Software Foundation.
Для наших целей достаточно знать три вещи об Texinfo input files.
The "at" символ, `@', является специальным, во многом подобным `"' в Си или awk. Буквальные символы `@' представлены в Texinfo source files как `@@'.
Комментарии начинаются с или `@c' или `@comment'. Программа извлечения файлов будет работать при использовании специальных комментариев, которые начинаются с начала строки.
Текст примера, который не должен разрываться на границах страниц, заключается между строками, содержащими команды `@group' `@end group'.
Следующая программа, `extract.awk', читает Texinfo source file и делает две вещи на основании специальных комментариев. Обнаружив `@c system ...', она выполняет команду, извлекая текст команды из командной строки и передавая его системной функции (см. раздел 12.4 [Встроенные функции для ввода/вывода, стр. 146). По обнаружении `@c file filename', каждая последующая строка будет посылаться в файл filename, пока не появится `@c endfile'. Правила в `extract.awk' будут соответствовать либо `@c' либо `@c comment', допуская необязательность части `omment'. Строки, содержащие `@group' и `@end group' просто удаляются. `extract.awk' использует библиотечную функцию join (см. раздел 15.6 [Объединение массива в цепочку], стр. 176).
Программные примеры в диалоговом Texinfo source для Эффективного AWK-программирования (`gawk.texi') должны быть все заключены между строками `file' и `endfile'. Распределитель gawk использует копию `extract.awk' для извлечения образцов программ и установки многих из них в стандартные каталоги, где gawk может их найти. Файл Texinfo выглядит иногда подобно следующему:
...
Эта программа имеет блок @code-BEGIN"" ,
который печатает приятное сообщение:
@example @c file examples/messages.awk
BEGIN @- print "Не паникуйте!" @"" @c end file @end example
Она также печатает заключительный совет:
@example @c file examples/messages.awk END @-
print "Всегда избегайте скучных археологов!"
@"" @c end file @end example ...
`extract.awk' начинает с установки IGNORECASE на один, так что смесь верхнего и нижнего регистров в директивах не будет иметь значения.
Первое правило действует, вызывая систему, проверяя, что команда была выдана (NF равно по крайней мере трем), и также проверяет, что команда закончила работу с состоянием 0, означающим OK.
# extract.awk --- извлечь файлы и выполнить программы
# из texinfo files
# Arnold Robbins, arnold@gnu.org, Public Domain
# May 1993
BEGIN - IGNORECASE = 1 "" /^@c(omment)?[ "t]+system/ " -
if (NF ! 3) -
e = (FILENAME ":" FNR) e = (e ": badly formed `system' line")
print e ? "/dev/stderr" next "" $1 = "" $2 = "" stat = system($0)
if (stat != 0) -
e = (FILENAME ":" FNR) e = (e ": warning: system returned " stat)
print e ? "/dev/stderr" "" ""
Используется переменная e, так что функция хорошо вписывается в страницу. Второе правило управляет переносом данных в файлы. Оно проверяет, что имя файла было указано в директиве. Если названный файл не является текущим, то текущий файл закрывается. Это значит, что некоторый `@c endfile' не был выдан для этого файла.
(Вероятно, мы должны печатать диагностику в этом случае, хотя сейчас этого не делаем.)
Цикл `for' выполняет свою работу. Он читает строки с помощью getline (см. раздел 5.8 [Явный ввод по getline], стр. 53). При неожиданном конце файла она вызывает функцию unexpected.eof. Если строка есть "endfile" , то она прерывает цикл. Если строка есть `@group' или `@end group', то она игнорирует ее и переходит к следующей строке. (Названные строки Texinfo control держат блоки кода вместе на одной странице; к несчастью, TEX не всегда достаточно ловок, чтобы делать все правильно, и мы должны давать ему советы.)
Большая часть работы проделывается несколькими следующими строками. Если в строке нет символов `@', она может быть непосредственно напечатана. В противном случае каждый ведущий `@' должен быть убран.
Для удаления символов `@' строка должна быть расчленена на отдельные элементы массива a с помощью функции split (см. раздел 12.3 [Встроенные функции], стр. 137). Каждый элемент массива a, который пуст, указывает на два соседних символа `@' в оригинальной строке. Для каждых двух пустых элементов (`@@' в оригинальном файле), мы должны добавить обратно один символ `@'.
Когда обработка массива закончена, вызывается join со значением SUBSEP, чтобы вновь соединить куски в единую строку. Затем эта строка печатается в выходном файле.
/^@c(omment)?[ "t]+file/ " -
if (NF != 3) -
e = (FILENAME ":" FNR ": badly formed `file' line")
print e ? "/dev/stderr" next "" if ($3 != curfile) -
if (curfile != "")
close(curfile) curfile = $3 ""
for (;;) -
if ((getline line) != 0)
unexpected.eof() if (line ~ /^@c(omment)?[ "t]+endfile/)
break else if (line ~ /^@(end[ "t]+)?group/)
continue if (index(line, "@") == 0) -
print line ? curfile continue
"" n = split(line, a, "@") # если a[1] == "", это означает ведущий @,
# не добавляйте его обратно
for (i = 2; i != n; i++) -
if (a[i] == "") - # встретили @@
a[i] = "@" if (a[i+1] == "")
i++ "" "" print join(a, 1, n, SUBSEP) ? curfile "" ""
Важно отметить употребление перенаправления `?'. Выход, сделанный с `?', открывает файл только один раз; он остается открытым и последующий вывод добавляется в конец файла (см. раздел 6.6 [Перенаправление вывода print и printf], стр. 70). Это позволяет нам легко смешивать текст программы с пояснениями в одном и том же куске исходного файла (как это сделано здесь!) без всяких затруднений. Файл закрывается только когда появляется имя нового файла с данными, или по концу входного файла.
Наконец, функция unexpected.eof печатает соответствующее сообщение об ошибке и прерывает программу.
Правило END завершает работу, закрывая открытый файл.
function unexpected.eof() -
printf("%s:%d: unexpected EOF or error"n", "
FILENAME, FNR) ? "/dev/stderr" exit 1 ""
END -
if (curfile)
close(curfile) ""
Назад | Вперед
Содержание (общее) | Содержание раздела | Содержание подраздела
Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:
|