#ifndef VLIBC_STDIO_STDIO_IMPL_H #define VLIBC_STDIO_STDIO_IMPL_H /* * vlibc — internal FILE layout and stream helpers (todo 15). * * struct vlibc_FILE is the object behind the opaque FILE of . * Position invariant (authoritative): * * - Read mode: `pos` is the file offset of buf[0]. The logical position * (offset of the byte at rpos) is pos + (rpos - buf), and the kernel * position is pos + (rstop - buf); with an empty buffer * (rpos == rstop) the kernel sits exactly at the logical position. * - Write mode: `pos` is the file offset of buf[0]; the next written byte * lands at pos + (wpos - buf). With an empty buffer the kernel sits at * pos. A flush advances pos by the number of bytes written. * * Mode switching: reading while write data is pending flushes it first; * writing while unread buffered data is pending seeks the kernel back to * the logical position (discarding the unread data). F_PUSHED marks the * single guaranteed ungetc pushback byte in `ungot`; a successful seek * discards it. * * The helper prototypes below are shared with the formatted-I/O todos * (16: vfprintf, 17: vfscanf) so they operate on the same buffer state. */ #include #include "../internal/libc.h" struct vlibc_FILE { unsigned char *buf; /* buffer base: library- or user-supplied */ unsigned char *rpos; /* read mode: next byte to deliver */ unsigned char *rstop; /* read mode: end of valid buffered data */ unsigned char *wpos; /* write mode: next byte to store */ unsigned char *wstop; /* write mode: end of the buffer */ int fd; /* underlying descriptor; -1 when closed */ int flags; /* F_* bits below */ size_t buf_size; /* usable buffer size; 0 = not yet sized */ off_t pos; /* position per the invariant above */ struct vlibc_FILE *next; /* registry link for fflush(NULL) */ unsigned char ungot; /* pushed-back byte when F_PUSHED */ }; /* Stream flags. */ #define F_READ 0x001 /* reads are enabled by the open mode */ #define F_WRITE 0x002 /* writes are enabled by the open mode */ #define F_EOF 0x004 /* end of file has been seen */ #define F_ERR 0x008 /* an I/O error occurred */ #define F_LINEBUF 0x010 /* line buffered: flush on newline */ #define F_UNBUF 0x020 /* unbuffered: 1-byte buffer */ #define F_APPEND 0x040 /* append mode: writes land at end of file */ #define F_OWNBUF 0x080 /* buf was allocated by the library */ #define F_HEAP 0x100 /* the FILE struct itself is heap-allocated */ #define F_PUSHED 0x200 /* ungot holds a pushed-back byte */ /* Flush pending write data; returns 0, or -1 with F_ERR set. */ hidden int stdio_flush(FILE *f); /* Refill the read buffer from the descriptor (read mode only). */ hidden void stdio_refill(FILE *f); /* Discard unread buffered data, seeking the kernel back to pos. */ hidden int stdio_discard_read(FILE *f); /* Allocate the buffer lazily (std streams, setvbuf with NULL). */ hidden void stdio_init_if_needed(FILE *f); /* Allocate and register a FILE over an open descriptor. */ hidden FILE * stdio_alloc_file(int fd, int m); /* * Parse a fopen-style mode string. On success stores the F_READ/F_WRITE * capability bits in *m, the openat flags in *oflags, and returns 1; * returns 0 for an invalid mode. */ hidden int stdio_parse_mode(const char *mode, int *m, int *oflags); /* * Raw lseek with errno translation. Separate from syscall_ret() because * syscall_ret narrows results to int and would truncate large offsets. */ hidden off_t stdio_lseek(int fd, off_t off, int whence); #endif /* VLIBC_STDIO_STDIO_IMPL_H */