Книга: Разработка приложений в среде Linux. Второе издание

14.5.2. Внутренняя универсализация

14.5.2. Внутренняя универсализация

Если необходимо универсализировать несколько файловых имен, запуск нескольких подоболочек с помощью popen() будет неэффективным. Функция glob() позволяет универсализировать имена файлов без запуска каких-либо подпроцессов, однако за счет увеличения сложности и снижения переносимости. Несмотря на то что вызов glob() описан в стандарте POSIX.2, многие варианты Unix до сих пор его не поддерживают.

#include <glob.h>
int glob(const char * pattern, int flags,
int (*errfunc)(const char * epath, int eerrno), glob_t* pglob);

Первый параметр, pattern, определяет шаблон, которому должны соответствовать имена файлов. В нем допускается применение операций универсализации *, ? и [], а также необязательно {, } и ~ которые трактуются так же, как в стандартных оболочках. Последний параметр указывает на структуру, которая заполняется результатами универсализации. Эта структура определена следующим образом.

#include <glob.h>
typedef struct {
 int gl_pathc; /* количество путей в gl_pathv */
 char **gl_pathv; /* список gl_pathc, соответствующих именам путей */
 int gl_offs; /* пространство, зарезервированное в gl_pathv для GLOB_DOOFFS*/
} glob_t;
flags
— это одно или несколько перечисленных ниже значений, объединенных с помощью битового "ИЛИ".

GLOB_ERR Возвращается в случае ошибки (если функция не может прочесть оглавление каталога, например, из-за проблем с доступом).
GLOB_MARK Если шаблон соответствует имени каталога, при возврате к этому имени будет добавлен символ /.
GLOB_NOSORT Обычно возвращаемые имена путей сортируются в алфавитном порядке. Если этот флаг установлен, они не сортируются.
GLOB_DOOFFS При установке первые строки pglob->gl_offs в возвращаемом списке имен путей оставляются пустыми. Это позволяет использовать glob() во время выстраивания ряда аргументов, которые будут переданы прямо в execv().
GLOB_NOCHECK Если ни одно из файловых имен не соответствует шаблону, в качестве единственного совпадения возвращается сам шаблон (обычно не возвращается ни одного совпадения). В обоих случаях шаблон возвращается, если он не содержит операций универсализации.
GLOB_APPEND pglob предположительно является действительным результатом предыдущего вызова glob(), и любые результаты этого вызова добавляются к результатам предыдущего вызова. Это облегчает универсализацию множества шаблонов.
GLOB_NOESCAPE Обычно если операции универсализации предшествует символ , она воспринимается как обычный символ. Например, шаблон а* обычно соответствует только файлу по имени а*. Если устанавливается GLOB_NOESCAPE, символ теряет свое особое значение, aa* соответствует любому имени файла, начинающемуся с символов а. В таком случае имена а. и abcd будут соответствовать, но arachnid — нет, поскольку оно не содержит .
GLOB_PERIOD Большинство оболочек не позволяют применять операции универсализации для файловых имен, начинающихся с . (запустите ls * в своем домашнем каталоге и сравните полученное с результатом ls - а .). Функция glob() обычно ведет себя подобным образом, но GLOB_PERIOD позволяет операциям универсализации работать с ведущим символом. Значение GLOB_PERIOD в POSIX не определено.
GLOB_BRACE Многие оболочки (следуя примеру csh) разворачивают последовательности с фигурными скобками как альтернативы; например, шаблон {a, b} разворачивается до a b, а шаблон a {, b, c} — до a ab ас. GLOB_BRACE делает возможным такое поведение. Значение GLOB_BRACE в POSIX не определено.
GLOB_NOMAGIС Действует подобно GLOB_NOCHECK за исключением того, что он добавляет шаблон к списку результатов только в том случае, если она не содержит специальных знаков. Значение GLOB_NOMAGIC в POSIX не определено.
GLOB_TILDE Включает расширение с тильдой, в котором ~ или подстрока ~/ разворачиваются до пути к домашнему каталогу текущего пользователя, а ~user — до пути к домашнему каталогу пользователя user. Значение GLOB_TILDE в POSIX не определено.
GLOB_ONLYDIR Совпадает только с каталогами, а не с другими типами файлов. Значение GLOB_ONLYDIR в POSIX не определено.

Часто glob() наталкивается на каталоги, к которым у процесса нет доступа, что вызывает ошибки. Хотя ошибку можно каким-то образом обработать, однако если glob() возвращает ошибку (GLOB_ERR), операцию универсализации нельзя перезапустить там, где предыдущая операция универсализации столкнулась с ошибкой. Поскольку сложно одновременно устранять ошибки, происходящие во время выполнения glob(), и завершать универсализацию, glob() позволяет передать ошибку в специально предусмотренную для этого функцию, которая определяется в третьем параметре glob().

Прототип этой функции показан ниже.

int globerr(const char * pathname, int globerrno);

Функции передается путевое имя, вызвавшее ошибку, и значение errno, возвращенное одним из системных вызовов opendir(), readdir() или stat(). Если функция ошибки возвращает величину больше нуля, glob() возвращается с ошибкой. В противном случае операция универсализации продолжается.

Результаты универсализации хранятся в структуре glob_t, на которую ссылается pglob. Она включает описанные ниже элементы, позволяющие абоненту найти согласованные имена файлов.

gl_pathc Количество путевых имен, соответствующих шаблону.
gl_pathv Массив путевых имен, соответствующих шаблону.

После использования возвращенного результата glob_t занимаемую им память следует освободить, передав его в globfree().

void globfree(glob_t * pglob);

Системный вызов glob() возвращает GLOB_NOSPACE в случае нехватки памяти, GLOB_ABEND, если ошибка чтения привела к неудачному выполнению функции, GLOB_NOMATCH, если соответствия не были найдены, или 0, если функция выполнилась удачно и нашла соответствия.

Для иллюстрации работы glob() ниже приведена программа globit, которая принимает множество шаблонов в качестве аргументов, универсализирует их и отображает результат. В случае ошибки отображается сообщение, описывающее ошибку, а операция универсализации продолжается.

 1: /* globit.с */
 2:
 3: #include <errno.h>
 4: #include <glob.h>
 5: #include <stdio.h>
 6: #include <string.h>
 7: #include <unistd.h>
 8:
 9: /* Это функция ошибки, которая передается в glob(). Она просто отображает
10:    сообщение об ошибке и возвращает состояние успеха, что позволяет glob()
11:    продолжить работу. */
12: int errfn(const char * pathname, int theerr) {
13:  fprintf(stderr, "ошибка при доступе к %s: %sn", pathname,
14:  strerror(theerr));
15:
16:  /* Операция универсализации должна продолжаться, поэтому вернуть 0 */
17:  return 0;
18: }
19:
20: int main(int argc, const char ** argv) {
21:  glob_t result;
22:  int i, rc, flags;
23:
24:  if (argc < 2) {
25:   printf("необходимо передать хотя бы один аргументn") ;
26:   return 1;
27:  }
28:
29:  /* установить flags в 0; позже он будет изменен на GLOB_APPEND */
30:  flags = 0;
31:
32:  /* совершить проход по всем аргументам командной строки */
33:  for (i = 1; i < argc; i++) {
34:   rc = glob(argv[i], flags, errfn, &result);
35:
36:   /* благодаря errfn, GLOB_ABEND не происходит */
37:   if (rc == GLOB_NOSPACE) {
38:    fprintf(stderr, "не хватает памяти для выполнения универсализацииn");
39:    return 1;
40:   }
41:
42:   flags |= GLOB_APPEND;
43:  }
44:
45:  if (!result.gl_pathc) {
46:   fprintf(stderr, "соответствий нетn");
47:   rc = 1;
48:  } else {
49:   for (i = 0; i < result.gl_pathc; i++)
50:    puts(result.gl_pathv[i]);
51:   rc = 0;
52:  }
53:
54:  /* структура glob_t занимает память из пула malloc(),
55:     которая должна быть освобождена */
56:  globfree(&result);
57:
58:  return rc;
59: }

Оглавление книги


Генерация: 2.176. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз