В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13 |
Средства обработки структурированных данных
Справедливости ради нужно отметить, что приведенный пример носит искусственный характер, поскольку для генерации маршрутных имен, удовлетворяющих заданному шаблону, стандартом POSIX-2001 предусмотрена функция glob() (см. листинг 6.56).
#include <glob.h> int glob (const char *restrict file_pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *restrict pglob); void globfree (glob_t *pglob);Листинг 6.56. Описание функций glob() и globfree().
Функция glob() сопоставляет все доступные маршрутные имена с шаблоном file_pattern и генерирует список успешно сопоставленных имен. Результаты своей работы функция glob() возвращает в структуре типа glob_t, содержащей, согласно стандарту, по крайней мере следующие поля:
size_t gl_pathc; /* Число успешно сопоставленных маршрутных имен */ char **gl_pathv; /* Массив указателей на успешно сопоставленные маршрутные имена */ size_t gl_offs; /* Число элементов, которые нужно зарезерви- ровать в начале массива gl_pathv */
Структура, на которую указывает аргумент pglob, должна создаваться приложением. Другие области памяти, в том числе массив gl_pathv, резервируются функцией glob() по мере необходимости и освобождаются после обращения к globfree() с тем же значением pglob.
Работой функции glob() можно управлять с помощью следующих флагов.
GLOB_APPEND
Добавлять вновь сгенерированные маршрутные имена к предыдущим результатам функции glob().
GLOB_DOOFFS
Принимать во внимание поле gl_offs. Если этот флаг установлен, то pglob->gl_pathv будет указывать на pglob->gl_offs пустых указателей, за которыми следуют pglob->gl_pathc указателей на маршрутные имена и завершающий пустой указатель.
GLOB_ERR
Завершать работу по достижении каталога, который не удается открыть или прочитать. Обычно в таких случаях функция glob() продолжает процесс генерации маршрутных имен.
GLOB_MARK
Добавлять символ / после имен успешно сопоставленных файлов, являющихся каталогами.
GLOB_NOCHECK
При отсутствии успешно сопоставленных имен возвращать шаблон.
GLOB_NOESCAPE
Запретить экранирование символом \.
GLOB_NOSORT
Не сортировать сгенерированные имена по алфавиту.
Если в процессе своей работы функция glob() достигает каталога, который не удается открыть или прочитать, а аргумент errfunc отличен от пустого указателя, то glob() вызывает (*errfunc ()) с двумя аргументами: "проблемным" маршрутным именем и соответствующим значением errno. Если этот вызов возвращает значение, отличное от нуля, или если установлен флаг GLOB_ERR, генерация маршрутных имен завершается, значения полей pglob->gl_pathc и pglob->gl_pathv устанавливаются в соответствии с уже обработанными маршрутами, а результат вызова функции glob() полагается равным GLOB_ABORTED (при нормальном завершении возвращается 0).
Перепишем программу, которая выводит имена файлов, удовлетворяющие заданным в командной строке шаблонам, воспользовавшись функцией glob() (см. листинг 6.57).
#include <glob.h> #include <errno.h> #include <stdio.h> /* Программа выводит маршрутные имена, сгенерированные по заданным шаблонам */ static int errfunc (const char *epath, int eerrno) { fprintf (stderr, "Ошибка при обработке каталога %s: ", epath); errno = eerrno; perror (NULL); return (0); } int main (int argc, char *argv []) { glob_t gl_buf; int i; for (i = 1; i < argc; i++) { (void) glob (argv [i], ((i == 1) ? } (void) printf ("Маршрутные имена, сгенерированные по заданным шаблонам:\n"); for (i = 0; (unsigned) i < gl_buf.gl_pathc; i++) { (void) printf ("%s\n", gl_buf.gl_pathv [i]); } globfree (&gl_buf); return (0); }Листинг 6.57. Пример программы, использующей функции glob() и globfree().
Выше, при описании языка shell, мы рассматривали служебную программу basename. Ее логическим дополнением является утилита dirname:
dirname цепочка_символов
Она выдает на стандартный вывод имя каталога, в котором находится поименованный цепочкой символов файл. Отметим, что цепочка символов трактуется служебной программой dirname как маршрутное имя только синтаксически: никаких проверок существования компонентов маршрутного имени не производится.
В качестве примера использования утилиты dirname приведем фрагмент командного файла, выполняемого при загрузке ОС Linux (см. листинг 6.58).
if [ "`dirname $RAW`" = "/dev/raw" -a -f /dev/raw ]; then echo $" Please correct your /etc/sysconfig/rawdevices:" echo $" rawdevices are now located in the directory /dev/raw/ " echo $" If the command 'raw' still refers to /dev/raw as a file." echo $" you'll have to upgrade your util-linux package" exit fiЛистинг 6.58. Пример использования служебной программы dirname.
Совместное использование утилит basename и dirname иллюстрирует листинг 6.59. Это командный файл с одним аргументом - маршрутным именем компилируемого C-файла, которое может быть задано как с расширением .c, так и без него.
gcc -Wall -W -pedantic -o $(basename "$1" .c) $(dirname "$1")/$(basename "$1" .c).cЛистинг 6.59. Пример совместного использования служебных программ basename и dirname.