Linux программирование в примерах - Роббинс Арнольд
Шрифт:
Интервал:
Закладка:
92 {
93 n_alloc = info->level * 2; /* Удвоить сумму */
94 sum_ent = XREALLOC(sum_ent, uintmax_t, realloc); /* И выделить повторно */
95 sum_subdir = XREALLOC(sum_subdir, uintmax_t, n_alloc);
96 }
97 }
98
99 size_to_print = size;
Строки 78–97 управляют динамической памятью, используемой для хранения статистики о размере файла, first_call является статической переменной (строка 12), которая равна true при первом вызове process_file(). В этом случае вызывается calloc() (через упаковывающий макрос в строках 81–82; это обсуждалось в разделе 3.2.1.8 «Пример чтение строк произвольной длины»). Остальную часть времени first_call равно false, и используется realloc() (снова через упаковывающий макрос, строки 91–96).
Строка 99 заносит значение size в size_to_print; эта переменная может обновляться в зависимости от того, должна ли она включать размеры дочерних элементов. Хотя size могла бы использоваться повторно, отдельная переменная упрощает чтение кода.
101 if (!first_call)
102 {
103 if ((size_t)info->level == prev_level)
104 {
105 /* Обычно самый частый случай. Ничего не делать. */
106 }
107 else if ((size_t)info->level > prev_level)
108 {
109 /* Нисхождение по иерархии.
110 Очистить аккумуляторы для *всех* уровней между prev_level
111 и текущим. Глубина может значительно меняться,
112 например, от 1 до 10. */
113 int i;
114 for (i = prev_level +1; i <= info->level; i++)
115 sum_ent[i] = sum_subdir[i] = 0;
116 }
117 else /* info->level < prev_level */
118 {
119 /* Восхождение по иерархии.
120 nftw обрабатывает каталог лишь после всех элементов,
121 в которых был обработан каталог. Когда глубина уменьшается,
122 передать суммы от детей (prev_level) родителям.
123 Здесь текущий уровень всегда меньше, чем
124 предыдущий. */
125 assert (<size_t) info->level == prev_level - 1);
126 size_to_print += sum_ent[prev_level];
127 if (!opt_separate_dirs)
128 size_to_print += sum_subdir[prev_level];
129 sum_subdir[info->level] += (sum_ent[prev_level]
130 + sum_subdir[prev_level]);
131 }
132 }
Строки 101–132 сравнивают текущий уровень с предыдущим. Возможны три случая.
Уровни те же самые
В этом случае нет необходимости беспокоиться о статистике дочерних элементов. (Строки 103–106.)
Текущий уровень выше предыдущего
В этом случае мы спустились по иерархии, и статистику нужно восстановить (строки 107–116). Термин «аккумулятор» в комментарии подходящий: каждый элемент аккумулирует общее дисковое пространство, использованное на этом уровне. (На заре вычислительной техники регистры центрального процессора часто назывались «аккумуляторами».)
Текущий уровень ниже предыдущего
В этом случае мы завершили обработку всех дочерних элементов каталога и только что вернулись обратно в родительский каталог (строки 117–131). Код обновляет суммы, включая size_to_print.
134 prev_level = info->level; /* Установить статические переменные */
135 first_call = 0;
136
137 /* Включить элемент каталога в общую сумму для содержащего
138 каталога, если не указана --separate-dirs (-S). */
139 if (!(opt_separate_dirs && IS_FTW_DIR_TYPE(file_type)))
140 sum_ent[info->level] += size;
141
142 /* Даже если каталог нельзя прочесть или перейти в него,
143 включить его размер в общую сумму, ... */
144 tot_size += size;
145
146 /* ...но не выводить для него итог, поскольку без размера(-ов)
147 потенциальных элементов, это может сильно запутывать. */
148 if (file_type == FTW_DNR || file_type == FTW_DCH)
149 return 0;
150
151 /* Если мы не считаем элемент, например, потому что это прямая
152 ссылка на файл, который уже посчитан (и --count-links), не
153 выводить для него строку. */
154 if (!print)
155 return 0;
Строки 134–135 устанавливают статические переменные prev_level и first_call таким образом, что они содержат правильные значения для последующего вызова process_file(), гарантируя, что весь предыдущий код работает правильно.
Строки 137–144 выверяют статистику на основе опций и типа файла. Комментарии и код достаточно просты. Строки 146–155 сразу завершают функцию, если сведения не должны выводиться.
157 /* FIXME: Это выглядит подозрительно годным для упрощения. */
158 if ((IS_FTW_DIR_TYPE(file_type) &&
159 (info->level <= max_depth || info->level == 0))