Книга: Разработка приложений в среде Linux. Второе издание
14.6.2. Добавление универсализации файловых имен
14.6.2. Добавление универсализации файловых имен
Универсализацию файловых имен, при которой оболочка разворачивает символы *
, []
и ?
в соответствующие файловые имена, в определенной мере сложно реализовать из-за разнообразных методов применения кавычек. Первая модификация заключается в построении каждого аргумента в виде строки, подходящей для передачи в glob()
. Если символ универсализации помещен в кавычки, принятые в оболочке (например, двойные кавычки), тогда символу универсализации предшествует с целью предотвращения его разворачивания в glob()
. Этот процесс реализуется легко, хотя с первого взгляда может показаться сложным.
Две части синтаксического разбора команд в parseCommand(
) необходимо слегка изменить. Последовательности "
и '
обрабатываются ближе к началу цикла, что обеспечивает разделение командной строки на аргументы. Если во время синтаксического разбора мы находимся в середине строки в кавычках и сталкиваемся с символом универсализации, мы заключаем его в кавычки с предваряющим символом , что выглядит следующим образом.
189: } else if (quote) {
190: if (*src == '') {
191: src++;
192: if (!*src) {
193: fprintf(stderr,
194: "после ожидался символn");
195: freeJob(job);
196: return 1;
197: }
198:
199: /* в оболочке "'" должен дать ' */
200: if (* src ! = quote) *buf++ = '';
201: } else if (*src = '*' | | *src == '?' || *src == '[' ||
202: *src == ']')
203: *buf++ = '';
204: *buf++ = *src;
205: } else if (isspace(*src)) {
В код были добавлены только средний else if
и оператор присваивания в его теле. Похожий код потребуется предусмотреть для обработки символов , встречающихся вне строк в кавычках. Это реализовано в конце главного цикла parseCommand()
. Ниже приведен измененный код.
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.6. Добавление к ladsh возможностей работы с каталогами и универсализацией
- Ширина и глубина ассортимента
- Резервное копирование многофайловых баз данных
- Восстановление из резервных копий многофайловых баз данных
- Категорийный менеджмент. Курс управления ассортиментом в рознице
- Имена индексов ограничений
- Пример применения метода «пять почему»
- Имена объектов длиной 68 символов
- 6.3. Добавление фоновой музыки
- Ценовая сегментация ассортимента
- 5.12.2 Открытие поименованного канала
- Сохранение рабочей книги с именем, представляющим собой текущую дату