ка не доберемся до конца комментария.
Когда обнаружена последняя строка, результатом проверки является
значение "ложь", поэтому выполняется else-часть. Поскольку мы знаем,
что это последняя строка, мы печатаем ее для завершенности блока ком-
ментария, а затем выходим из awk. Отметим, что благодаря вложению этих
двух команд вместе в фигурные скобки ({}), они рассматриваются как одно
составное предложение.
После завершения awk производится эхо-отображение прогона формата
на экран и берется следующий файл. Так продолжается до тех пор, пока
все файлы в командной строке не будут обработаны.
4.2.2. stripf - из Си-функции
---------------------------------------------------------------------------
ИМЯ: stripf
---------------------------------------------------------------------------
stripf Извлекает документирующий заголовок
Си-функции.
ФУНКЦИЯ
Извлекает и печатает комментирующий заголовок, имя функции с пара-
метрами вызова и объявление типов параметров для всех функций в исход-
ном файле на Си.
ФОРМАТ
stripf file [...]
ПРИМЕР ВЫЗОВА
stripf lib1.c
Извлекает документирующие заголовки для всех функций в
файле lib1.c.
ИСХОДНЫЙ КОД ДЛЯ stripf
1 :
2 # @(#) stripf v1.0 Strip function header Author: Russ Sage
4 for FILE in $@
5 do
6 sed -n -e '
7 /^L$/ {
8 s/^L$/.bp/p
9 : loop
10 n
11 /^{/b exit
12 p
13 b loop
14 : exit
15 i\
16 {}
17 b
18 }' $FILE
19 done
ПЕРЕМЕННАЯ СРЕДЫ
FILE Хранит имя файла для каждого файла
из командной строки.
ОПИСАНИЕ
ЗАЧЕМ НАМ НУЖЕН stripf?
Предположим, что наш код на языке Си соответствует модели докумен-
тации, представленной ранее при описании stripc. Тогда нам нужен способ
поддержания изменений в документации по ходу изменений кода. Мы видели,
что при хранении документации в исходных файлах более вероятно, что она
будет изменена, когда изменится код. Проблема возникает, когда нам нуж-
на твердая копия документации, которая находится внутри исходного кода.
Как нам получить ее из файлов?
ЧТО ДЕЛАЕТ stripf?
Командный файл stripf решает эту проблему. Он просматривает весь
файл и печатает всю документацию для каждой ФУНКЦИИ, которая размещена
в этом файле (включая "main", если она есть).
Входом для stripf являются имена файлов, переданные в командной
строке. Stripf обрабатывает файлы по очереди и помещает выход в stdout.
Этот выход можно перенаправить, но вход должен быть в командной строке.
К выходу применяются дополнительные модификации, чтобы сформиро-
вать данные для среды утилиты nroff, поэтому выводные файлы можно фор-
матировать с помощью этой утилиты. Все прогоны формата заменяются на
команду .bp, принятую в nroff для начала страницы. Эта команда nroff
прогоняет страницу и увеличивает на единицу счетчик страниц. Возможно,
вы не хотите менять нажатие клавиш control-L на это значение, но вы
всегда можете указать в командном файле такие действия, какие вам нуж-
ны.
ПРИМЕРЫ
1. $ stripf module1.c | grep >"^\.bp$" | wc -l
Печатает число модулей-функций, содержащихся в файле module1.c,
путем поиска каждого появления команд новой страницы программы nroff и
их подсчета. Мы знаем, что одна из таких команд является выходом для
каждой обнаруженной функции. Данную строку можно вложить в предложение
echo, которое говорит "имеется X модулей в файле $FILE".
2. $ for FILE in *.c ../*.c $HOME/src/*.c
> do
> stripf $FILE
> done >> /tmp/func.hdrs
Данный цикл for распространяется на все файлы в текущем каталоге,
которые оканчиваются на .c, все файлы в родительском каталоге с таким
же суффиксом и все файлы в подкаталоге src моего home-каталога с тем же
суффиксом. Из каждого файла извлекается документация о функциях и нап-
равляется в стандартный вывод. Весь цикл перенаправлен с помощью >>,
поэтому выход каждого вызова stripf ДОБАВЛЯЕТСЯ к файлу в /tmp.
ПОЯСНЕНИЯ
Вся программа - это один большой цикл for в строках 4-19. Этот
цикл присваивает переменной FILE каждое имя, имеющееся в командной
строке. Данный командный файл не имеет опций и обработки ошибок.
Команда sed системы UNIX вызывается для каждого имени файла. Прог-
рамма sed читает весь вход и выводит измененный текст в стандартный вы-
вод.
Опция -n используется в sed для подавления всего вывода, в проти-
воположность действию по умолчанию, когда все печатается. Мы используем
этот флаг по той причине, что мы хотим указать программе sed, когда пе-
чатать выход. Опция -e применяется, чтобы сообщить программе sed, что
следующая последовательность текста между одинарными кавычками является
выражением, которое нужно вычислить.
Напомним, что sed - потоковый редактор, который читает одну стро-
ку, сверяет ее с выражениями, затем читает следующую строку и делает
все сначала. Первое, что мы ищем - символ control-L, стоящий в строке
самостоятельно. Если мы не находим его, проверяется следующая строка и
так далее, пока не будет обнаружен control-L. (Еще раз напомним, что
вместо обозначения ^L в коде должен быть введен настоящий control-L.)
Когда обнаружен control-L, он активизирует все выражение, заклю-
ченное в фигурные скобки. Первым действием является подстановка команды
начала страницы программы nroff, как описано ранее. Эта подстановка пе-
чатается, что является самым первым выводом. В строке 9 объявлена метка
"loop". Это не приводит ни к каким действиям, но устанавливает точку
перехода, которая впоследствии используется. (Управляющие структуры
программы sed довольно примитивны, но они позволяют описать выполняемую
работу.)
Строка 8 использует команду n программы sed, чтобы вызвать чтение
следующей строки. Мы разобрались с первой строкой - строкой, которая
содержит control-L - так что мы можем ее отбросить. В случае выполнения
цикла мы видим, что sed продвигается по нашему требованию, но не прод-
вигается сам.
Вспомним модель документации, рассмотренную ранее. Эта модель
включает документирующий заголовок для файла в целом, выполненный в
обычном стиле языка Си. Модель завершается символом control-L. Этот
первый блок обрабатывается с помощью stripc, как описано ранее. Мы не
хотим использовать его здесь при работе со stripf. Поэтому мы сейчас
должны спозиционироваться после файлового документирующего заголовка.
Вслед за символом control-L имеется еще один набор из одной или
более строк комментария языка Си, которые описывают функцию, следующую
за ними. Далее идет само имя функции, объявление параметров и открываю-
щий символ самой функции, которым является левая фигурная скобка (}).
Строка 11 ищет эту фигурную скобку. Если она найдена, выполнение
переходит на метку exit (строка 14). Мы можем полагать, что мы все сде-
лали, если найдена левая фигурная скобка, так как этот символ должен
появляться только в начале функциимодуля. Когда мы находим фигурную
скобку, мы уже напечатали к этому моменту всю комментирующую информацию
и заголовок функции посредством строки 12, которую мы сейчас опишем. А
что если фигурная скобка появляется в поле комментария? Нет проблем,
поскольку поиск фигурной скобки привязан к началу строки с помощью сим-
вола ^. Он производит выражение, означающее "от первого символа в стро-
ке". Мы только тогда сопоставляем фигурную скобку этому выражению, ког-
да она встречается в качестве самого первого символа в строке.
Затем строка 12 предполагает, что мы еще не обнаружили фигурную
скобку и поэтому мы должны напечатать строку. Оператор p печатает теку-
щую строку, которую обрабатывает sed. Этот вывод направляется на экран.
Строка 13 - безусловный переход на метку loop. Отметим, что этот
переход только изменил процесс выполнения и не привел к чтению еще од-
ной вводной записи. С этим мы должны быть осторожны при управлении про-
цессом выполнения в программе sed. Мы только что напечатали текущую за-
пись, поэтому теперь мы должны отбросить ее и получить следующую за-
пись, что означает возврат в строку 9. Этот цикл печати и чтения следу-
ющей записи продолжается до обнаружения фигурной скобки, которая пере-
водит выполнение на метку exit.
Строка 14 - это метка exit. Когда мы попадаем на нее, мы знаем,
что был обнаружен control-L, напечатан комментирующий заголовок, напе-
чатаны имя функции и объявления ее параметров и найдена фигурная скоб-
ка. Заметим, что фигурная скобка еще не напечатана. Когда мы находим
ее, мы только делаем ветвление.
Строка 15 завершает вывод, вставляя некоторый текст в выводной по-
ток. Мы не можем сказать "печатать это в буквенном виде", поэтому про-
исходит движение вправо по тексту, как по команде echo. Мы должны сыг-
рать на правилах, установленных программой sed. Любой вывод должен быть
порожден обычными командами в стиле редактора ed. Вставка текста с по-
мощью команды "i" делает нам это. Отметим, что мы также вставляем сим-
вол возврата каретки (или перевода строки, в зависимости от вашей осве-
домленности). Он может быть определен символом обратной косой черты
(\). Обратная косая черта убирает специальное значение символов и при
использовании в конце строки, как здесь, означает, что специальный сим-
вол, вставленный в выражение, является возвратом каретки. Вдобавок к
возврату каретки, мы вставляем пару фигурных скобок. Это обозначает
объявление начала-конца функции, которую мы обрабатываем. Поскольку мы
вставляем текст, мы не должны говорить программе sed, что его нужно пе-
чатать.
Строка 17 - безусловный переход на себя, указывающий программе sed
переход на вершину всего обрабатываемого выражения. Когда это происхо-
дит, мы завершаем поиск еще одного control-L и начинаем весь процесс
снова. Таким образом, мы можем обработать все функции из одного файла
независимо от того, сколько их там.
Строка 18 является концом sed-выражения и содержит также имя фай-
ла, которое должно быть передано программе sed. Это является частью
обычного синтаксиса, принятого в sed, но выглядит несколько неуместным,
так как не выделено специальным отступом. Когда все файлы обработаны,
завершается внешний цикл и заканчивается работа командного файла.
4.2.3. strips - из командного файла Shell
---------------------------------------------------------------------------
ИМЯ: strips
---------------------------------------------------------------------------
strips Извлекает документирующий заголовок