464 lines
14 KiB
C
464 lines
14 KiB
C
#ifndef VLIBC_STDIO_H
|
|
#define VLIBC_STDIO_H
|
|
|
|
/*
|
|
* vlibc — <stdio.h>.
|
|
*
|
|
* 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 <vlibc/features.h>
|
|
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <sys/types.h>
|
|
|
|
#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);
|
|
|
|
/* formatted input (todo 17) */
|
|
|
|
/*
|
|
* Read formatted input. scanf reads from stdin, fscanf from the stream,
|
|
* sscanf from the string. The conversion directives are %d %i %u %o %x %X
|
|
* %f %F %e %E %g %G %a %A %c %s %[ %p %n and %% (with assignment
|
|
* suppression '*', a decimal field width, and the length modifiers hh h l
|
|
* ll j z t, plus L for the float conversions). A conversion fails to match
|
|
* without consuming its offending character; the return value is the
|
|
* number of assigned (non-suppressed) input items, or EOF if an input
|
|
* failure occurs before the first one. Integer overflow stores a saturated
|
|
* value and sets errno = ERANGE (nothing else touches errno).
|
|
*/
|
|
int
|
|
scanf(const char *restrict format, ...);
|
|
|
|
int
|
|
fscanf(FILE *restrict stream, const char *restrict format, ...);
|
|
|
|
int
|
|
sscanf(const char *restrict s, const char *restrict format, ...);
|
|
|
|
int
|
|
vscanf(const char *restrict format, va_list ap);
|
|
|
|
int
|
|
vfscanf(FILE *restrict stream, const char *restrict format, va_list ap);
|
|
|
|
int
|
|
vsscanf(const char *restrict s, const char *restrict format, va_list ap);
|
|
|
|
#endif /* VLIBC_STDIO_H */
|