24 break;
25 case 'u':
26 setbuf(stdout, (char*)NULL);
27 continue;
28 }
29 break;
30 }
31 fstat(fileno(stdout), &statb); /* Строки 31-36 объясняются в главе 5 */
32 statb.st_mode &= S_IFMT;
33 if (statb.st_mode != S_IFCHR && statb.st_mode != S_IPBLK) {
34 dev = statb.st_dev;
35 ino = statb.st_ino;
36 }
37 if (argc < 2) {
38 argc = 2;
39 fflg++;
40 }
41 while (--argc > 0) { // Loop over files
42 if (fflg || (*++argv)[0] == '-' && (*argv)[1] == '\0')
43 fi = stdin;
44 else {
45 if ((fi = fopen(*argv, "r")) == NULL) {
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()
Код, работающий с
struct stat
fstat()
fileno()
FILE*
$ <b>cat myfile >> myfile</b> /* Добавить копию myfile к себе? */
И конечно же, проверка работает:
$ <b>echo hi > myfile</b> /* Создать файл */
$ <b>v7cat myfile >> myfile</b> /* Попытка добавить файл к себе */
cat: input myfile is output
Если вы попробуете это с
ch04-cat
myfile
cat
cat
$ <b>v7cat < myfile > myfile</b>
cat: input - is output
$ <b>ls -l myfile</b>
-rw-r--r-- 1 arnold devel 0 Mar 24 14:17 myfile
В данном случае это слишком поздно, поскольку оболочка урезала файл
myfile
>
cat
struct stat
4.5. Произвольный доступ: перемещения внутри файла
До сих пор мы обсуждали последовательный ввод/вывод, при котором данные читаются или записываются с начала файла и продолжаются до его конца. Часто это все, что требуется программе. Однако, возможно осуществление произвольного ввода/вывода; т.е. читать данные из произвольного положения в файле без необходимости предварительного чтения всего, что находится перед этим местом.
Смещение дескриптора файла является положением внутри открытого файла, начиная с которого будет осуществляться следующая операция чтения или записи. Программа устанавливает смещение с помощью системного вызова
lseek()
#include <sys/types.h> /* для off_t; POSIX */
#include <unistd.h> /* объявления lseek() и значений whence */
off_t lseek(int fd, off_t offset, int whence);
Тип
off_t
long
off_t
int64_t
lseek()
int fd
Дескриптор открытого файла.
off_t offset
Позиция, в которую нужно переместиться. Интерпретация этого значения зависит от параметра
whence
offset