Linux программирование в примерах - Роббинс Арнольд
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] == ' ')
43 fi = stdin;
44 else {
45 if ((fi = fopen(*argv, "r")) == NULL) {
46 fprintf(stderr, "cat: can't open %sn", *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 outputn",
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*.) Идея в основе этого кода заключается в том, чтобы убедиться, что входной и выходной файлы не совпадают. Это предназначено для предотвращения бесконечного роста файла, в случае подобной команды:
$ <b>cat myfile >> myfile</b> /* Добавить копию myfile к себе? */
И конечно же, проверка работает:
$ <b>echo hi > myfile</b> /* Создать файл */
$ <b>v7cat myfile >> myfile</b> /* Попытка добавить файл к себе */
cat: input myfile is output
Если вы попробуете это с ch04-cat, программа продолжит работу, и myfile будет расти до тех пор, пока вы не прервете ее. GNU версия 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 получила возможность исследовать файл! В разделе 5.4.4.2 «Возвращаясь к V7 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 (тип смещения) является знаковым целым, представляющим позиции байтов (смещений от начала) внутри файла. На 32-разрядных системах тип представлен обычно как long. Однако, многие современные системы допускают очень большие файлы, в этом случае off_t может быть более необычным типом, таким, как C99 int64_t или какой-нибудь другой расширенный тип. lseek() принимает три следующих аргумента.
int fd
Дескриптор открытого файла.
off_t offset
Позиция, в которую нужно переместиться. Интерпретация этого значения зависит от параметра whence. offset может быть положительным или отрицательным; отрицательные значения перемещают к началу файла; положительные значения перемещают к концу файла.
Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Linux программирование в примерах - Роббинс Арнольд, относящееся к жанру Интернет. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.


