/* * _file.h — внутренности буферизованного FILE* (вариант B+, НЕ * публичный заголовок). Дизайн: docs/file-buffering-design.md. * * Инварианты: * - слот таблицы свободен, когда flags == 0; * - level < BUFSIZ на входе в любую операцию записи (конвенция * «сброс ПЕРЕД записью в буфер»); * - hold != EOF означает отложенный байт ungetc; логическая позиция * потока на 1 меньше учтённой в level; * - консольные псевдопотоки (_F_CONIN/_F_CONOUT) буфер не заводят * и в _file_sync не попадают. */ #ifndef _FILE_INTERNAL_H #define _FILE_INTERNAL_H #include /* Таблица потоков (_file_slots.c); свободный слот: flags == 0. */ extern FILE _file_slots[OPEN_MAX]; /* Обеспечить буфер: вернуть fp->buf, при необходимости malloc(BUFSIZ). * NULL = malloc не дал — вызывающий уходит на небуферизованный путь * (прямой syscall на 1 байт), поток продолжает работать. */ uint8_t *_file_buf(FILE *fp); /* Нейтрализовать буфер (перед seek/tell/close и при смене направления): * - направление «запись»: write() несброшенного хвоста; * - направление «чтение»: lseek(fd, -(level + hold), SEEK_CUR) — * откат непрочитанного readahead и ungetc-байта. * После вызова: level = 0, hold = EOF, _F_DIROUT снят, curp = buf. * Возврат 0 или EOF (ставит _F_ERROR). */ int _file_sync(FILE *fp); /* fclose всех открытых слотов; вешается на atexit первым fopen. */ void _fclosall(void); #endif