Files
Sprinter-SDCC/libc/file/_file.h
T
snark13 48d552bf3a libc: FILE* v2 — буферизация потоков (вариант B+)
- единый ленивый буфер BUFSIZ=512 на чтение и запись с
  автопереключением направления (_F_DIROUT, _file_sync: запись
  сбрасывается write()-ом, readahead откатывается lseek-ом)
- статическая таблица OPEN_MAX=8 слотов вместо malloc для FILE;
  _fclosall через atexit — exit() сбрасывает несброшенную запись
- fread/fwrite: мелкое через буфер (memcpy), блоки >= BUFSIZ — мимо
  буфера одним syscall; горячие пути fgetc/fputc и сканер строк
  fgets (LDI до '\n') — на asm, SDCC на эти цепочки генерит ~90
  инструкций с IX-фреймом
- новое: ungetc (1 байт через hold, работает и на stdin),
  fprintf/vfprintf (vsprintf+fwrite), fflush(NULL) = все потоки
- фиксы stdio-review: fwrite ставит _F_ERROR при короткой записи
  (issue 3), fgets(n=1) возвращает пустую строку (issue 4)
- замер (MAME, HDD, 100 КБ): небуферизованная оценка ~144 с →
  fgetc 5 с (×29), fgets ~1 с; дизайн и отвергнутые варианты —
  docs/file-buffering-design.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 16:09:13 +03:00

39 lines
2.0 KiB
C

/*
* _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 <stdio.h>
/* Таблица потоков (_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