Опубликован: 15.06.2004 | Доступ: свободный | Студентов: 2290 / 579 | Оценка: 4.35 / 3.96 | Длительность: 27:47:00
ISBN: 978-5-9556-0011-6
Лекция 6:

Средства обработки структурированных данных

Справедливости ради нужно отметить, что приведенный пример носит искусственный характер, поскольку для генерации маршрутных имен, удовлетворяющих заданному шаблону, стандартом 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.
Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?

Павел Храмцов
Павел Храмцов
Россия
Денис Комаров
Денис Комаров
Россия, Москва