24 if (strcmp(gr->gr_mem[i], argv[i]) == 0) /* Если пользователь найден... */
25 print_group(gr); /* Вывести запись */
26
27 endgrent();
28
29 exit(0);
30 }
Функция main()
сначала проверяет ошибки (строки 17–20). Основным компонентом программы является вложенный цикл. Внешний цикл (строка 22) перечисляет все записи базы данных группы. Внутренний цикл (строка 23) перечисляет всех членов массива gr_mem
. Если один из членов соответствует имени из командной строки (строка 24), для печати записи вызывается print_group()
(строка 25):
32 /* print_group --- печать записи группы */
33
34 void
35 print_group(const struct group *gr)
36 {
37 int i;
38
39 printf("%s:%s:%ld:gr->gr_name, gr->gr_passwd, (long)gr->gr_gid);
40
41 for (i = 0; gr->gr_mem[i] != NULL; i++) {
42 printf("%s", gr->gr_mem[i]);
43 if (gr->gr_mem[i+1) != NULL)
44 putchar(',');
45 }
46
47 putchar('\n');
48 }
Функция print_group()
(строки 34–48) проста, ее логика подобна логике main()
для печати списка членов. Члены списка группы разделены запятыми; поэтому тело цикла до вывода запятой должно проверить, что NULL
. Этот код работает правильно, даже если в группе нет членов. Однако мы знаем, что для этой программы есть члены, иначе print_group()
не была бы вызвана! Вот что происходит при запуске программы:
$ ch06-groupinfo arnold
mail:x:12:mail,postfix,arnold
uucp:x:14:uucp,arnold
floppy:x:19:arnold
devel:x:42:miriam,arnold
arnold:x:2076:arnold
6.4. Терминалы: isatty()
Модель стандартного ввода, стандартного вывода и стандартной ошибки Linux/Unix препятствует специальной трактовке устройств ввода и вывода. Программам обычно не нужно знать или беспокоиться о том, направляется ли их вывод на терминал, в файл, канал, физическое устройство или что-то еще.
Однако иногда бывают моменты, когда программе действительно нужно знать, с какого рода файлом связан файловый дескриптор. Семейство вызовов stat()
часто предоставляет достаточно сведений обычный файл, каталог, устройство и т.д. Хотя иногда даже этого недостаточно, и для интерактивных программ, в частности, вам может потребоваться знать, не представляет ли дескриптор файла tty
.
Различить можно с помощью isatty()
.
#include
int isacty(int desc);
Эта функция возвращает 1, если дескриптор файла desc
представляет терминал, в противном случае 0. В соответствии с POSIX isatty()
может установить errno
для указания ошибки; поэтому до вызова isatty()
следует установить errno в 0, а затем проверить ее значение, если был возвращен 0. (Справочная страница GNU/Linux errno
.) Стандарт POSIX также указывает, что просто возврат isatty()
1 не означает, что на другом конце дескриптора файла находится человек!
Одним местом, где используется isatty()
, является современная версия ls
, в которой имена файлов по умолчанию печатаются в столбцы, если терминалом является стандартный вывод, а если нет, они печатаются по одной на строчку.
6.5. Рекомендуемая литература
1.
Эта книга предоставляет практическое, утилитарное введение в алгоритмы и структуры данных с использованием С, освещая среди прочих вещей таблицы хэшей, деревья, сортировку и поиск.
2.