Рейтинговые книги
Читем онлайн Разработка приложений в среде Linux. Второе издание - Майкл Джонсон

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 65 66 67 68 69 70 71 72 73 ... 150

329: case '\':

330:  src++;

331:  if (!*src) {

332:   freeJob(job);

333:   fprintf(stderr, "после \ ожидался символn");

334:   return 1;

335:  }

336:  if (* src == '*' || *srс == '[' | | *src == ']'

337:   || *srс == '?')

338:   *buf++ = '\';

339:  /* сквозная обработка */

340: default:

341:  *buf++ = *src;

Для заключения знаков универсализации в кавычки здесь был добавлен тот же самый код.

Эти две кодовые последовательности обеспечивают передачу каждого аргумента в glob() без поиска неожиданных совпадений.

Теперь добавим функцию globLastArgument(), которая универсализирует самый последний аргумент для дочерней программы и замещает его любым найденным совпадением.

Для облегчения управления памяти к struct childProgram добавляется элемент globResult типа glob_t, используемый для хранения результатов всех операций универсализации. Кроме того, добавляется целочисленный элемент freeGlob, не равный нулю, если freeJob() должна освободить globResult. Ниже показано полное описание struct childProgram в ladsh3.c.

35: struct childProgram {

36:  pid; /* 0, если завершена */

37:  char ** argv; /* имя и аргументы программы */

38:  int numRedirections; /* элементы в массиве перенаправлений */

39:  struct redirection Specifier * redirections; /* перенаправления ввода-вывода */

40:  glob_t globResult; /* результат универсализации параметров */

41:  int freeGlob; /* нужно ли освобождать globResult? */

42: };

Во время первого запуска для командной строки функция globLastArgument() (когда argc для текущей дочерней оболочки равно 1) инициализирует globResult. Для остальных аргументов она пользуется преимуществом GLOB_APPEND для добавления новых совпадений к существующим. Это избавляет от необходимости распределения собственной памяти для целей универсализации, поскольку одиночный glob_t при необходимости автоматически расширяется.

Если globLastArgument() не находит совпадений, символы с кавычками удаляются из аргумента. В противном случае все новые совпадения копируются в список аргументов, создаваемый для дочерней программы.

Ниже приведена полная реализация globLastArgument(). Все сложные ее части относятся к управлению памятью; фактическая универсализация похожа на реализованную в программе globit.с, которая представлена ранее в главе.

 87: void globLastArgument(struct childProgram * prog, int * argcPtr,

 88:  int * argcAllocedPtr) {

 89:  int argc = *argcPtr;

 90:  int argcAlloced = *argcAllocedPtr;

 91:  int rc;

 92:  int flags;

 93:  int i;

 94:  char * src, * dst;

 95:

 96:  if (argc >1) {/* cmd->globResult уже инициализирован */

 97:   flags = GLOB_APPEND;

 98:   i = prog->globResult.gl_pathc;

 99:  } else {

100:   prog->freeGlob = 1;

101:   flags = 0;

102:   i = 0;

103:  }

104:

105:  rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);

106:  if (rc == GLOB_NOSPACE) {

107:   fprintf (stderr, "не хватает памяти для выполнения универсализацииn");

108:   return;

109:  } else if (rc == GLOB_NOMATCH ||

110:   (!rc && (prog->globResult.gl_path - i) == 1 &&

111:   !strcmp(prog->argv[argc - 1],

112:   prog->globResult.gl_pathv[i]))) {

113:    /* необходимо удалить кавычки в , если они все еще присутствуют */

114:    src = dst = prog->argv[argc - 1];

115:    while (*src) {

116:     if (*src ! = '\') *dst++ = *src;

117:     src++;

118:    }

119:    *dst = '';

120:   } else if (!rc) {

121:   argcAlloced += (prog->globResult.gl_pathc - i);

122:   prog->argv = realloc(prog->argv,

123:   argcAlloced * sizeof(*prog->argv));

124:   memcpy(prog->argv + (argc - 1),

125:    prog->globResult.gl_pathv + i,

126:    sizeof(*(prog->argv)) *

127:    (prog->globResult.gl_pathc - i));

128:   argc += (prog->globResult.gl_pathc - i - 1);

129:  }

130:

131:  *argcAllocedPtr = argcAlloced;

132:  *argcPtr = argc;

133: }

Последними изменениями касаются вызовов globLastArgument(), которые должны совершаться после синтаксического разбора нового аргумента. Вызовы добавляются в двух местах: когда за пределами строки в кавычках найдены пробелы и когда вся командная строка разобрана. Оба вызова выглядят следующим образом:

globLastArgument(prog, &argc, &argvAlloced);

Полный код ladsh3.с доступен на Web-сайте издательства, а также на сайте, посвященном книге.

14.7. Обход деревьев файловых систем

Существуют две функции, которые облегчают приложениям просмотр всех файлов каталога, включая файлы в подкаталогах. Рекурсивный просмотр всех элементов древовидной структуры (например, файловой системы) часто называется обходом (walk) дерева и он реализуется функциями ftw() и nftw(). nftw() представляет собой усовершенствованную версию ftw.

14.7.1. Использование ftw()

#include <ftw.h>

int ftw(const char *dir, ftwFunctionPointer callback, int depth);

Функция ftw() начинает с каталога dir и вызывает указанную в callback функцию для каждого файла в этом каталоге и его подкаталогах. Функция вызывается для всех типов файлов, включая символические ссылки и каталоги. Реализация ftw() открывает каждый найденный каталог (с помощью файлового дескриптора) и для увеличения производительности не закрывает их, пока не закончит чтение всех элементов каталога. Это означает, что он использует количество файловых дескрипторов, равное количеству уровней подкаталогов. Чтобы предотвратить недостаток файловых дескрипторов в приложении, параметр depth ограничивает количество файловых дескрипторов ftw(), остающихся одновременно открытыми. Если этот предел достигается, производительность снижается, поскольку каталоги необходимо часто открывать и закрывать.

Функция, на которую указывает callback, определяется следующим образом:

int ftwCallbackFunction(const char * file, const struct stat * sb, int flag);

Эта функция вызывается один раз для каждого файла в дереве каталогов, а первый параметр, file, представляет собой имя файла, начинающееся с dir, которое передается ftw(). Например, если бы аргумент dir принимал значение ., одним из файловых имен было бы ./bashrc. Если бы вместо этого использовалось /etc, имя файла выглядело бы как /etc/hosts.

Следующий аргумент обратного вызова, sb, указывает на структуру struct stat как на результат применения stat() к файлу[102]. Аргумент flag предоставляет информацию о файле и принимает одно из следующих значений.

FTW_F Файл не является символической ссылкой или каталогом. FTW_D Файл является каталогом либо символической ссылкой, указывающей на каталог. FTW_DNR Файл является каталогом, полномочий на чтение которого у приложения нет (то есть его обход невозможен). FTW_SL Файл является символической ссылкой. FTW_NS Файл является объектом, к которому не удалось применить stat(). Примером может служить файл в каталоге, права на чтение которого приложение имеет (приложение может получить список файлов этого каталога), но не имеет права на выполнение (что предотвращает успешный вызов stat() применительно к файлам этого каталога).

Когда файл является символической ссылкой, ftw() пытается последовать за этой ссылкой и вернуть информацию о файле, на который она указывает (ftw() проходит один и тот же каталог несколько раз, если на него имеется несколько символических ссылок). Однако для поврежденной ссылки не определено, вернется FTW_SL или FTW_NS. Это хорошая причина, чтобы использовать nftw().

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

14.7.2. Обход дерева файлов с помощью nft()

Новая версия ftw() — nftw() — решает неоднозначность символических ссылок, присущих ftw(), и содержит несколько дополнительных свойств. С целью правильного определения nftw() заголовочными файлами значение _XOPEN_SOURCE в приложении должно быть определено 500 или больше. Ниже показан прототип nftw().

1 ... 65 66 67 68 69 70 71 72 73 ... 150
На этой странице вы можете бесплатно читать книгу Разработка приложений в среде Linux. Второе издание - Майкл Джонсон бесплатно.
Похожие на Разработка приложений в среде Linux. Второе издание - Майкл Джонсон книги

Оставить комментарий