Linux программирование в примерах
Часть 185 из 253 Информация о книге
Для демонстрации регулярных выражений
предусматривает базовую реализацию стандартной программыch12-grep.c, которая отыскивает соответствие шаблону. Наша версия использует по умолчанию базовые регулярные выражения. Для использования вместо этого расширенных регулярных выражений она принимает опциюgrep, а для игнорирования регистра символов опцию-E. Как и настоящая-i, если в командной строке не указаны файлы, нашаgrepчитает со стандартного ввода, а для обозначения стандартного ввода, как и в настоящейgrep, может быть использовано имя файла 'grep'. (Эта методика полезна для поиска в стандартном вводе наряду с другими файлами.) Вот программа:-1 /* ch12-grep.c - Простая версия grep, использующая функции POSIX */23 #define _GNU_SOURCE 1 /* для getline)) */4 #include <stdio.h>5 #include <errno.h>6 #include <regex.h>7 #include <unistd.h>8 #include <sys/types.h>910 char *myname; /* для сообщений об ошибках */11 int ignore_case = 0; /* опция -i: игнорировать регистр */12 int extended = 0; /* опция -E: использовать расширенные регулярные выражения */13 int errors = 0; /* число ошибок */1415 regex_t pattern; /* шаблон для поиска */1617 void compile_pattern(const char *pat);18 void process(const char *name, FILE *fp);19 void usage(void);Строки 10–15 объявляют глобальные переменные программы. Первый набор (строки 10–13) для опций и сообщений об ошибках. Строка 15 объявляет
, в которой хранится откомпилированный шаблон. Строки 17–19 объявляют другие функции программы.pattern21 /* main --- обработка опций, открывание файлов */2223 int main(int argc, char **argv)24 {25 int с;26 int i;27 FILE *fp;2829 myname = argv[0];30 while ((c = getopt(argc, argv, ":iE")) != -1) {31 switch (c) {32 case 'i':33 ignore_case = 1;34 break;35 case 'E':36 extended = 1;37 break;38 case '?':39 usage();40 break;41 }42 }4344 if (optind == argc) /* проверка исправности */45 usage();4647 compile_pattern(argv[optind]); /* компилировать шаблон */48 if (errors) /* ошибка компиляции */49 return 1;50 else51 optind++;В строке 29 устанавливается значение
, а строки 30–45 анализируют опции. Строки 47–51 компилируют регулярное выражение, помещая результаты вmyname,patternувеличивает значениеcompilе_раttern(), если была проблема. (Соединение функций посредством глобальной переменной, как здесь, обычно считается плохой манерой. Для небольших программ, подобным этой, это сойдет, но для более крупных программ такое сопряжение может стать проблемой.) Если не было ошибок, строка 51 увеличивает значениеerrorsтак, что оставшиеся аргументы представляют файлы для обработки.optind53 if (optind == argc) /* файлов нет, по умолчанию stdin */54 process("standard input", stdin);55 else {56 /* цикл с файлами */57 for (i = optind; i < argc; i++) {58 if (strcmp(argv[i], "-") == 0)59 process("standard input", stdin);60 else if ((fp = fopen(argv[i], "r")) != NULL) {61 process(argv[i], fp);62 fclose(fp);63 } else {64 fprintf(stderr, "%s: %s: could not open: %s\n",65 argv[0], argv[i], strerror(errno));66 errors++;67 }68 }69 }7071 regfree(&pattern);72 return errors != 0;73 }Строки 53–69 обрабатывают файлы, отыскивая соответствующие шаблону строки. Строки 53–54 обрабатывают случай, когда файлы не указаны: программа читает со стандартного ввода. В противном случае, строки 57–68 обрабатывают в цикле файлы. Строка 58 обрабатывает особый случай '
', обозначающий стандартный ввод, строки 60–62 обрабатывают обычные файлы, а строки 63–67 обрабатывают ошибки.-75 /* compile_pattern --- компиляция шаблона */7677 void compile_pattern(const char *pat)