#ifndef VLIBC_STDIO_H #define VLIBC_STDIO_H /* * vlibc — . * * Buffered stream I/O (todo 15). The FILE object is opaque to consumers; * the layout lives in src/stdio/stdio_impl.h. stdin/stdout/stderr are * pre-wired streams over fds 0/1/2 and are initialized lazily on first * use. On Linux there is no text/binary distinction, so the 'b' mode * character is accepted and ignored. * * Buffering modes for setvbuf: _IOFBF (fully buffered), _IOLBF (line * buffered: flush on newline), _IONBF (unbuffered). A stream opened on a * terminal defaults to line buffering for stdout and full buffering for * stdin; stderr is always unbuffered. * * getc/putc/getchar/putchar are declared as functions (address-taking and * #undef work) and additionally defined as macros over fgetc/fputc; the * macro arguments are evaluated exactly once. * * Level 2 (muslmimic) adds tmpnam/ctermid/setbuffer/setlinebuf and the * fopen64 name alias (identical ABI on LP64). */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* * The opaque stream object. The underlying struct tag is vlibc_FILE (see * src/stdio/stdio_impl.h); consumers only ever use FILE *. */ typedef struct vlibc_FILE FILE; /* The three pre-wired standard streams (fds 0, 1, 2). */ extern FILE *stdin; extern FILE *stdout; extern FILE *stderr; /* End of file indicator for character functions. */ #define EOF (-1) /* Minimum number of simultaneously open files. */ #define FOPEN_MAX 16 /* Default buffer size for setvbuf/setbuf. */ #define BUFSIZ 8192 /* Maximum length of a path argument for stdio functions. */ #define FILENAME_MAX 4096 /* Minimum number of distinct tmpnam-generated names. */ #define TMP_MAX 238328 /* Buffer sizes for tmpnam and ctermid results. */ #define L_tmpnam 20 #define L_ctermid 9 /* Seek positions for fseek/fseeko. */ #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 /* setvbuf modes. */ #define _IOFBF 0 // NOLINT(bugprone-reserved-identifier) #define _IOLBF 1 // NOLINT(bugprone-reserved-identifier) #define _IONBF 2 // NOLINT(bugprone-reserved-identifier) /* Opaque file position type for fgetpos/fsetpos. */ typedef off_t fpos_t; /* * Open the file at path with the given mode. The mode is 'r', 'w', or 'a', * optionally followed by '+' (update: read and write), 'b' (ignored on * Linux), and/or 'x' (exclusive create, C11). Returns NULL with errno set * on failure. */ FILE * fopen(const char *restrict path, const char *restrict mode); /* * Wrap an existing descriptor in a stream. The requested mode must be * compatible with the descriptor's access mode (basic check via fcntl). * The descriptor is not duplicated; fclose closes it. */ FILE * fdopen(int fd, const char *mode); /* * Rebind stream to path. The old descriptor is flushed and closed first. * With path == NULL only the mode changes and the descriptor stays open. * Returns NULL with errno set on failure. */ FILE * freopen(const char *restrict path, const char *restrict mode, FILE *restrict stream); /* * Flush pending output, close the descriptor, and release the stream. * Returns EOF if flushing or closing failed. */ int fclose(FILE *stream); /* * Flush pending output of stream. fflush(NULL) flushes all open streams * with pending output. On a stream with no pending writes (read mode) the * unread buffered data is discarded and the position rewound; this never * corrupts the stream. Returns EOF on error. */ int fflush(FILE *stream); /* * Set the buffer of stream to buf. buf == NULL selects unbuffered I/O; * otherwise the buffer is used with full buffering and BUFSIZ size. Must * be called before the first operation on the stream. */ void setbuf(FILE *restrict stream, char *restrict buf); /* * Set the buffering mode of stream: _IOFBF, _IOLBF, or _IONBF. With * buf != NULL the caller supplies size bytes of storage; with buf == NULL * the buffer is allocated lazily on first use (size is then ignored, * except that _IONBF needs no buffer). Returns 0, or -1 with errno EINVAL * for an invalid mode or a non-NULL buf with size 0 (except _IONBF). */ int setvbuf(FILE *restrict stream, char *restrict buf, int mode, size_t size); /* * Read up to size * nmemb bytes in items of size bytes each. Returns the * number of complete items read; fewer than nmemb means end of file or an * error (distinguishable via feof/ferror). size or nmemb zero returns 0 * without touching the stream. */ size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream); /* * Write size * nmemb bytes in items of size bytes each. Returns the number * of complete items written; fewer than nmemb means an error (see * ferror). */ size_t fwrite(const void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream); /* Read the next character as unsigned char, or EOF. */ int fgetc(FILE *stream); /* Write c as unsigned char; returns it, or EOF on error. */ int fputc(int c, FILE *stream); /* Same as fgetc/fputc; also provided as macros (arguments evaluated once). */ int getc(FILE *stream); int putc(int c, FILE *stream); int getchar(void); int putchar(int c); /* * Read at most n-1 characters into s, stopping after (and keeping) a * newline, then NUL-terminate. Returns s, or NULL if no character was read * (end of file or error). */ char * fgets(char *restrict s, int n, FILE *restrict stream); /* * Write the NUL-terminated string s to stream (no trailing newline is * added). Returns a non-negative value, or EOF on error. */ int fputs(const char *restrict s, FILE *restrict stream); /* * Push c back onto the input stream; the next read returns it again. One * byte of pushback is guaranteed. Returns c, or EOF on error (also for * ungetc(EOF)). A successful seek discards the pushed-back character. */ int ungetc(int c, FILE *stream); /* Position the stream (see SEEK_SET/SEEK_CUR/SEEK_END); clears feof. */ int fseek(FILE *stream, long offset, int whence); int fseeko(FILE *stream, off_t offset, int whence); /* Current stream position, -1 with errno set on error. */ long ftell(FILE *stream); /* * Not marked pure: the implementation can allocate the stream buffer on * first use (an observable side effect), so the compiler must not elide * or reorder the call. (feof/ferror/fileno below are genuinely read-only * and keep their pure attribute.) */ off_t ftello(FILE *stream); /* Rewind to the start and clear feof/ferror (equivalent to * fseeko(stream, 0, SEEK_SET) + clearerr). */ void rewind(FILE *stream); /* Get/set the opaque position via fpos_t. */ int fgetpos(FILE *restrict stream, fpos_t *restrict pos); int fsetpos(FILE *stream, const fpos_t *pos); /* End-of-file and error indicators. */ __attribute__((pure)) int feof(FILE *stream); __attribute__((pure)) int ferror(FILE *stream); void clearerr(FILE *stream); /* * Remove the file at path (a directory is removed like rmdir). Returns 0, * or -1 with errno set. */ int remove(const char *path); /* Rename oldpath to newpath. Returns 0, or -1 with errno set. */ int rename(const char *oldpath, const char *newpath); /* * Create an anonymous temporary file ("w+b"): the file is created in /tmp * and unlinked immediately, so it disappears on close. Returns the stream, * or NULL with errno set. */ FILE * tmpfile(void); /* The descriptor underlying the stream. */ __attribute__((pure)) int fileno(FILE *stream); /* * Run command in a subshell ("sh -c command") with a pipe attached to * its standard output (mode "r") or standard input (mode "w"). Only the * two POSIX modes are accepted (the glibc "re"/"we" close-on-exec * extension is not). Returns the stream, or NULL with errno set. * pclose closes the stream, waits for the shell, and returns its * termination status (the raw wait status, e.g. 0 for "exit 0"), or -1 * when the stream was not opened by popen or the wait failed. */ FILE * popen(const char *command, const char *mode); int pclose(FILE *stream); /* getc/putc/getchar/putchar as macros over fgetc/fputc (see above). */ #define getc(stream) fgetc(stream) #define putc(c, stream) fputc((c), (stream)) #define getchar() fgetc(stdin) #define putchar(c) fputc((c), stdout) #if VLIBC_LEVEL_GE(2) /* * Generate a name for a temporary file ("/tmp/vlibcXXXXXX" form; the file * is NOT created). With s == NULL a static buffer is used. Not thread-safe, * obsolescent. */ char * tmpnam(char *s); /* Controlling terminal path: copies "/dev/tty" into s (or a static * buffer when s == NULL) and returns it. */ char * ctermid(char *s); /* BSD: like setvbuf with _IOFBF/_IONBF and the given size. */ void setbuffer(FILE *stream, char *buf, size_t size); /* BSD: select line buffering (setvbuf with _IOLBF and NULL buffer). */ void setlinebuf(FILE *stream); /* glibc LFS name alias: identical to fopen on LP64. */ FILE * fopen64(const char *restrict path, const char *restrict mode); #endif /* VLIBC_LEVEL_GE(2) */ #ifdef __cplusplus } #endif /* formatted output (todo 16) */ int printf(const char *restrict format, ...); int fprintf(FILE *restrict stream, const char *restrict format, ...); int sprintf(char *restrict s, const char *restrict format, ...); int snprintf(char *restrict s, size_t n, const char *restrict format, ...); int vprintf(const char *restrict format, va_list ap); int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap); int vsprintf(char *restrict s, const char *restrict format, va_list ap); int vsnprintf(char *restrict s, size_t n, const char *restrict format, va_list ap); int dprintf(int fd, const char *restrict format, ...); int vdprintf(int fd, const char *restrict format, va_list ap); void perror(const char *s); #if VLIBC_LEVEL_GE(2) int asprintf(char **restrict strp, const char *restrict format, ...); int vasprintf(char **restrict strp, const char *restrict format, va_list ap); #endif /* line input, stream locking, and memory streams (todo 18) */ /* * Read one line from stream into a malloc'd, NUL-terminated buffer. On the * first call *lineptr may be NULL (a buffer is allocated); *n is the buffer * capacity and grows as needed. The newline is kept in the output; embedded * NUL bytes are preserved (the length comes from the return value, not * strlen). Returns the number of bytes read including the delimiter, or -1 * at end of file (nothing read) or on error. */ ssize_t getline(char **restrict lineptr, size_t *restrict n, FILE *restrict stream); /* * Like getline, but reads up to the given delimiter byte (which is kept in * the output). Reading stops at end of file without the delimiter; a partial * final line is still returned with its byte count. */ ssize_t getdelim(char **restrict lineptr, size_t *restrict n, int delim, FILE *restrict stream); /* Write s to stdout followed by a newline. Returns a non-negative value, * or EOF on error. */ int puts(const char *s); /* * Per-stream advisory locks (POSIX.1-2008 base). flockfile is recursive: * the owning thread may lock the same stream any number of times, and * funlockfile must be called once per successful flockfile. ftrylockfile * acquires without blocking: 0 on success, nonzero when the stream is * already locked. Single-threaded today; the lock fields become real * blocking locks when the thread runtime lands. */ void flockfile(FILE *stream); int ftrylockfile(FILE *stream); void funlockfile(FILE *stream); /* * Unlocked character I/O: the stream must already be locked by the caller * (see flockfile). Identical to fgetc/fputc over stdin/stdout without * taking the per-stream lock. */ int getc_unlocked(FILE *stream); int getchar_unlocked(void); int putc_unlocked(int c, FILE *stream); int putchar_unlocked(int c); /* * Open a stream over the memory region buf of size bytes. With buf == NULL * the stream allocates and owns a growable buffer of its own that is freed * on fclose. Modes are fopen-like ('r', 'w', 'a', optional '+' and 'b', * where 'b' is accepted but on Linux only disables the string semantics): * 'w' truncates the current length to zero, 'a' positions at the end of the * data currently in the buffer (the first NUL byte in string mode), and * writing past the buffer size is an error. Returns the stream, or NULL * with errno set. */ FILE * fmemopen(void *buf, size_t size, const char *mode); /* * Open a write-only dynamic memory stream. The stream owns a growable * buffer; after fflush or fclose the buffer is NUL-terminated at the current * data length, *ptr points at it (it may have moved), and *sizeloc holds the * length. The caller releases the buffer with free() after fclose. */ FILE * open_memstream(char **ptr, size_t *sizeloc); #endif /* VLIBC_STDIO_H */