446: printf(JOB_STATUS_FORMAT, job->jobId, 'Выполняется',
447: job -> text);
448: return 0;
449: }
14.6.2. Добавление универсализации файловых имен
Универсализацию файловых имен, при которой оболочка разворачивает символы *, [] и ? в соответствующие файловые имена, в определенной мере сложно реализовать из-за разнообразных методов применения кавычек. Первая модификация заключается в построении каждого аргумента в виде строки, подходящей для передачи в glob(). Если символ универсализации помещен в кавычки, принятые в оболочке (например, двойные кавычки), тогда символу универсализации предшествует с целью предотвращения его разворачивания в glob(). Этот процесс реализуется легко, хотя с первого взгляда может показаться сложным.
Две части синтаксического разбора команд в parseCommand() необходимо слегка изменить. Последовательности ' и ' обрабатываются ближе к началу цикла, что обеспечивает разделение командной строки на аргументы. Если во время синтаксического разбора мы находимся в середине строки в кавычках и сталкиваемся с символом универсализации, мы заключаем его в кавычки с предваряющим символом , что выглядит следующим образом.
189: } else if (quote) {
190: if (*src == '\') {
191: src++;
192: if (!*src) {
193: fprintf(stderr,
194: 'после \ ожидался символ
');
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, 'после \ ожидался символ
');
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;
