Linux программирование в примерах - Роббинс Арнольд
Шрифт:
Интервал:
Закладка:
Давайте свяжем все это воедино в примере программы. ch08-nftw.c обрабатывает каждый файл или каталог, указанный в командной строке, запуская для них nftw(). Функция, обрабатывающая каждый файл, выводите отступом имя и тип файла, показывая иерархическое положение каждого файла. Для разнообразия мы сначала покажем результаты, а затем покажем и обсудим программу:
$ <b>pwd</b> /* Где мы находимся */
/ home/аrnold/work/prenhall/progex
$ <b>code/ch08/ch08-nftw code</b> /* Обойти каталог 'code' */
code (directory) /* Каталог верхнего уровня */
ch02 (directory) /* Подкаталоги с отступом на один уровень */
ch02-printenv.c (file) /* Файлы в подкаталоге с отступом
на два уровня */
ch03 (directory)
ch03-memaddr.c (file)
ch04 (directory)
ch04-holes.c (file)
ch04-cat.с (file)
ch04-maxfds.c (file)
v7cat.c (file)
...
Вот сама программа:
1 /* ch08-nftw.c --- демонстрирует nftw() */
2
3 #define _XOPEN_SOURCE 1 /* Требуется под GLIBC для nftw() */
4 #define _XOPEN_SOURCE_EXTENDED 1 /* To же */
5
6 #include <stdio.h>
7 #include <errno.h>
8 #include <getopt.h>
9 #include <ftw.h> /* получает для нас <sys/types.h> и <sys/stat.h> */
10 #include <limits.h> /* для PATH_MAX */
11 #include <unistd.h> /* для объявлений getdtablesize(), getcwd() */
12
13 #define SPARE_FDS 5 /* fds для использования другими функциями, см. текст */
14
15 extern int process(const char *file, const struct stat *sb,
16 int flag, struct FTW *s);
17
18 /* usage --- print message and die */
19
20 void usage(const char *name)
21 {
22 fprintf(stderr, "usage: %s (-c) directory ...n", name);
23 exit(1);
24 }
25
26 /* main --- вызвать nftw() для каждого аргумента командной строки */
27
28 int main(int argc, char **argv)
29 {
30 int i, c, nfds;
31 int errors = 0;
32 int flags = FTW_PHYS;
33 char start[PATH_MAX], finish[PATH_MAX];
34
35 while ((c = getopt(argc, argv, "с")) != -1) {
36 switch (c) {
37 case 'c':
38 flags |= FTW_CHDIR;
39 break;
40 default:
41 usage(argv[0]);
42 break;
43 }
44 }
45
46 if (optind == argc)
47 usage(argv[0]);
48
49 getcwd(start, sizeof start);
50
51 nfds = getdtablesize() - SPARE_FDS; /* оставить несколько запасных дескрипторов */
52 for (i = optind; i < argc; i++) {
53 if (nftw(argv[i], process, nfds, flags) != 0) {
54 fprintf(stderr, "%s: %s: stopped earlyn",
55 argv[0], argv[i]);
56 errors++;
57 }
58 }
59
60 if ((flags & FTW_CHDIR) != 0) {
61 getcwd(finish, sizeof finish);
62 printf("Starting dir: %sn", start);
63 printf("Finishing dir: %sn", finish);
64 }
65
66 return (errors != 0);
67 }
Строки 3–11 включают заголовочные файлы. По крайней мере в GLIBC 2.3.2 перед включением любого заголовочного файла необходимы #define для _XOPEN_SOURCE и _XOPEN_SOURCE_EXTENDED. Они дают возможность получить объявления и значения флагов, которые nftw() предоставляет свыше предоставляемых ftw(). Это специфично для GLIBC. Потребность в этом в конечном счете исчезнет, когда GLIBC станет полностью совместимой со стандартом POSIX 2001.
Строки 35–44 обрабатывают опции. Опция -с добавляет к флагам nftw() FTW_CHDIR. Это эксперимент с целью увидеть, сможете ли вы оказаться где-то в другом месте от того, где начинали. Кажется, это возможно, если nftw() завершается неудачей, в противном случае вы заканчиваете там же, где начинали. (POSIX не документирует это явным образом, но целью, похоже, было действительно заканчивать там же, где начинали. Стандарт не говорит, что функция обратного вызова не должна менять текущий каталог.)