Строки 52–58 являются главным циклом над нашими аргументами; строки 53–57 проверяют ошибки; когда они появляются, код выводит диагностическое сообщение и увеличивает значение переменной errors.
Строки 60–64 являются частью эксперимента с FTW_CHDIR, выводящего начальный и конечный каталоги, если было использовано -с.
По-настоящему интересной функцией является process(); это функция обратного вызова, которая обрабатывает каждый файл. Она использует базовый шаблон для функции обратного вызова nftw(), который является оператором switch для значения flag.
69 /* process --- выводит каждый файл на нужном уровне */
70
71 int process(const char "file, const struct stat *sb,
72 int flag, struct FTW *s)
73 {
74 int retval = 0;
75 const char *name = file + s->base;
76
77 printf("%*s", s->level * 4, ""); /* сделать отступ */
78
79 switch (flag) {
80 case FTW_F:
81 printf("%s (file)\n", name);
82 break;
83 case FTW_D:
84 printf("%s (directory)\n", name);
85 break;
86 case FTW_DNR:
87 printf("%s (unreadable directory)\n", name);
88 break;
89 case FTW_SL:
90 printf("%s (symbolic link)\n", name);
91 break;
92 case FTW_NS:
93 printf("%s (stat failed): %s\n", name, strerror(errno));
94 break;
95 case FTW_DP:
96 case FTW_SLN:
97 printf("%s: FTW_DP or FTW_SLN: can't happen'\n", name);
98 retval = 1;
99 break;
100 default:
101 printf("%s: unknown flag %d: can't happen'\n", name, flag);
102 retval = 1;
103 break;
104 }
105
106 return retval;
107 }
Строка 75 использует 'file + s->base' для получения имени из полного пути. Это значение указателя сохраняется в переменной name для повторного использования в функции.
Строка 77 делает отступ нужного размера, используя красивый трюк. Используя %*s, printf() получает от первого аргумента ширину поля. Это вычисляется динамически как 'level * 4'. Строка, которая должна быть выведена — «», пустая строка. Конечным результатом является то, что printf() создает для нас отступ нужного размера без необходимости запуска цикла.
Строки 79–104 являются оператором switch. В данном случае он не делает ничего весьма интересного, кроме вывода имени файла и его типа (файл, каталог и т.д.)
Хотя эта программа не использует struct stat, должно быть ясно, что вы могли бы сделать в функции обратного вызова все, что хотите.
ЗАМЕЧАНИЕ. Джим Мейеринг (Jim Meyering), сопроводитель GNU Coreutils, замечает, что дизайн nftw() несовершенен из-за ее рекурсивной природы. (Она рекурсивно вызывает себя при обработке подкаталогов.) Если иерархия каталогов становится действительно глубокой, в диапазоне уровней 20 000–40 000 (!), nftw() может выйти за пределы размера стека, уничтожив программу. Есть также и другие проблемы, связанные с дизайном nftw(). Версия GNU Coreutils после 5.0 исправляет это путем использования набора процедур fts() (см.
8.5. Обход дерева файлов: GNU du
GNU версия du в GNU Coreutils использует nftw() для обхода одной или более иерархии файлов, собирая и выводя сведения, касающиеся количества используемого дискового пространства. У нее большое число опций, которые управляют ее поведением но отношению к символическим ссылкам, форматом вывода чисел и т.д. Это делает разбор кода труднее, чем могло бы быть при более простой версии. (Однако, мы не собираемся позволить этому остановить нас.) Вот сводка опций du, которые вскоре будут полезны, когда мы рассмотрим код.
$ du --help
Usage: du [OPTION]... [FILE]...