могут переместить меньше байтов, чем запрошено. Код приложения (т.е. ваш код) всегда должен учитывать это.
4.4.4. Пример: Unix
cat
Как и было обещано, вот версия cat V7 [47] . Она начинается с проверки опций,
cat
V7 принимает единственную опцию,
– u
, для осуществления небуферированного вывода.
Общая структура сходна с той, которую мы видели ранее; программа перечисляет файлы, указанные в аргументах командной строки и читает каждый файл, по одному символу за раз, посылая этот символ в стандартный вывод. В отличие от нашей версии, она использует возможности
<stdio.h>
. Во многих случаях код, использующий стандартную библиотеку ввода/вывода, проще читать и писать, поскольку все проблемы с буферами скрыты библиотекой.
47
См.
/usr/src/cmd/cat.c
в дистрибутиве V7. Программа без изменений компилируется для GNU/Linux. — Примеч. автора.
1 /*
2 * Объединение файлов.
3 */
4
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8
9 char stdbuf[BUFSIZ];
10
11 main(argc, argv) /* int main(int argc, char **argv) */
46 fprintf(stderr, "cat: can't open %s\n", *argv);
47 continue;
48 }
49 }
50 fstat(fileno(fi), &statb); /* Строки 50-56 объясняются в главе 5 */
51 if (statb.st_dev == dev && statb.st_ino == ino) {
52 fprintf(stderr, "cat: input %s is output\n",
53 fflg ? "-" : *argv);
54 fclose(fi);
55 continue;
56 }
57 while ((c=getc(fi)) != EOF) /* Копировать содержимое в stdout */
58 putchar(с);
59 if (fi != stdin)
60 fclose(fi);
61 }
62 return(0);
63 }
Следует заметить, что программа всегда завершается успешно (строка 62); можно было написать ее так, чтобы отмечать ошибки и указывать их в возвращаемом значении
main
. (Механизм завершения процесса и значение различных кодов завершения обсуждаются в разделе 9.1.5.1 «Определение статуса завершения процесса».)
Код, работающий с
struct stat
и функцией
fstat
(строки 31–36 и 50–56), без сомнения, непрозрачен, поскольку мы еще не рассматривали эти функции и не будем рассматривать до следующей главы (Но обратите внимание на использование
fileno
в строке 50 для получения нижележащего дескриптора файла, связанного с переменными
FILE*
.) Идея в основе этого кода заключается в том, чтобы убедиться, что входной и выходной файлы не совпадают. Это предназначено для предотвращения бесконечного роста файла, в случае подобной команды: