/* * stdio.h — extends SDCC's z80 stdio with a buffered FILE * stream API. * * The bottom of the stack is the existing POSIX-style fd I/O (open/ * read/write/close/lseek). FILE * adds a per-stream 512-byte buffer, * lazily malloc'ed on first buffered operation, shared between reading * (readahead) and writing (accumulation) with automatic direction * switching — see docs/file-buffering-design.md (variant B+). * * FILE objects live in a static table of OPEN_MAX slots (no malloc); * a slot is free when flags == 0. exit() flushes and closes all open * streams via an atexit-registered _fclosall (armed by first fopen). * * stdin / stdout / stderr are predefined "virtual" FILE * pointers * that talk to the console via putchar()/getchar() (NOT through a fd) * and are never buffered. That keeps printf-routed output going * through our CR/LF mapping. */ #ifndef STDIO_H #define STDIO_H #include #include /* size_t */ #include #ifndef EOF #define EOF (-1) #endif /* ---- printf family (linked from SDCC's z80.lib) -------------------- */ int printf (const char *, ...); int sprintf(char *, const char *, ...); int vprintf(const char *, va_list); int vsprintf(char *, const char *, va_list); /* puts / putchar / getchar — overridden by our libc to use ESTEX. */ char puts (const char *); int putchar(int); int getchar(void); /* ---- FILE * (buffered, variant B+) --------------------------------- */ /* Максимум одновременно открытых fopen-потоков (консольные псевдо- * потоки не в счёт). DSS сам ограничивает число манипуляторов * (ошибка 06h "Too many open files"); наша таблица зеркалит его. */ #define OPEN_MAX 8 #define FOPEN_MAX OPEN_MAX /* Размер ленивого буфера потока. */ #define BUFSIZ 512 /* Internal layout — opaque to user. Слот таблицы свободен, когда * flags == 0. level — число байт: непрочитанный readahead (направление * «чтение») либо ещё не сброшенная запись (направление «запись», * флаг _F_DIROUT). */ typedef struct __FILE { int fd; /* POSIX fd (манипулятор DSS) */ uint8_t flags; /* см. _F_* ниже; 0 = слот свободен */ uint8_t *buf; /* ленивый буфер BUFSIZ байт или NULL */ uint8_t *curp; /* текущая позиция в буфере */ uint16_t level; /* байт в буфере (смысл зависит от _F_DIROUT) */ int hold; /* байт от ungetc, EOF = пусто */ } FILE; #define _F_READ 0x01 #define _F_WRITE 0x02 #define _F_APPEND 0x04 #define _F_DIROUT 0x08 /* буфер сейчас копит запись (иначе readahead) */ #define _F_EOF 0x10 #define _F_ERROR 0x20 #define _F_CONIN 0x40 /* console pseudo-stream — uses getchar() */ #define _F_CONOUT 0x80 /* console pseudo-stream — uses putchar() */ extern FILE *const stdin; extern FILE *const stdout; extern FILE *const stderr; /* fseek whence — same numeric values as SEEK_SET/CUR/END in unistd.h. */ #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif /* Тип позиции файла для fgetpos/fsetpos. */ typedef long fpos_t; FILE *fopen (const char *path, const char *mode); FILE *fdopen (int fd, const char *mode); FILE *freopen(const char *path, const char *mode, FILE *fp); int fclose (FILE *fp); void fclosall(void); int fflush (FILE *fp); /* fflush(NULL) — все потоки */ int fputc (int c, FILE *fp); int fgetc (FILE *fp); int fputs (const char *s, FILE *fp); char *fgets (char *buf, int n, FILE *fp); int ungetc(int c, FILE *fp); int fprintf (FILE *fp, const char *fmt, ...); int vfprintf(FILE *fp, const char *fmt, va_list ap); /* scanf-семейство (семантика Solid-C, реализация своя — в SDCC z80 * его нет). Конверсии: %d %u %x %o %c %s (+ модификатор l, ширина, * подавление '*', %%). Возврат: число присвоенных полей, EOF если * ввод кончился до первого совпадения. */ int scanf (const char *fmt, ...); int fscanf(FILE *fp, const char *fmt, ...); int sscanf(const char *s, const char *fmt, ...); /* Переименование файла (ESTEX RENAME $10). */ int rename(const char *oldpath, const char *newpath); size_t fread (void *ptr, size_t size, size_t nmemb, FILE *fp); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp); int fseek (FILE *fp, long off, int whence); long ftell (FILE *fp); void rewind(FILE *fp); int fgetpos(FILE *fp, fpos_t *pos); int fsetpos(FILE *fp, const fpos_t *pos); /* НЕ inline (замерено 2026-07-10, filetest +56 Б): тело с NULL-проверкой * ~12-15 байт — при 2+ сайтах вызова инлайн крупнее call+общее тело. */ int feof (FILE *fp); int ferror(FILE *fp); void clearerr(FILE *fp); /* Aliases to fputc/fgetc — POSIX says they may be macros. */ #define putc(c, fp) fputc(c, fp) #define getc(fp) fgetc(fp) /* Read line from stdin into buf until '\n' or EOF; '\n' is not stored. * Returns buf, or NULL on EOF with empty input. Solid-C/POSIX semantic. * Note: dangerous, no length check — caller must size buf appropriately. */ char *gets(char *buf); /* Solid-C decimal/hex helpers — print uint as decimal/hex without args. */ void hex8 (uint8_t v); /* prints two hex digits */ void hex16(uint16_t v); /* prints four hex digits */ void hex32(uint32_t v); /* prints eight hex digits */ void dec8 (uint8_t v); /* prints up to 3 decimal digits, no padding */ void dec16(uint16_t v); /* prints up to 5 decimal digits */ void dec32(uint32_t v); /* prints up to 10 decimal digits */ #endif