Книга: Разработка приложений в среде 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-сайте издательства, а также на сайте, посвященном книге.

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


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