Merge "Add __freadahead."
diff --git a/docs/status.md b/docs/status.md
index ef60ce2..20a1309 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -54,6 +54,7 @@
New libc functions in U (API level 34):
* `close_range` and `copy_file_range` (Linux-specific GNU extensions).
* `memset_explicit` in <string.h> (C23 addition).
+ * `__freadahead` in <stdio_ext.h> (in musl but not glibc).
New libc behavior in U (API level 34):
* Support for `%b` and `%B` in the printf/wprintf family, `%b` in the
diff --git a/libc/include/stdio_ext.h b/libc/include/stdio_ext.h
index 3aa183d..eda5919 100644
--- a/libc/include/stdio_ext.h
+++ b/libc/include/stdio_ext.h
@@ -96,13 +96,21 @@
/**
* [__fpending(3)](http://man7.org/linux/man-pages/man3/__fpending.3.html) returns the number of
- * bytes in the output buffer.
+ * bytes in the output buffer. See __freadahead() for the input buffer.
*
* Available since API level 23.
*/
size_t __fpending(FILE* __fp) __INTRODUCED_IN(23);
/**
+ * __freadahead(3) returns the number of bytes in the input buffer.
+ * See __fpending() for the output buffer.
+ *
+ * Available since API level 34.
+ */
+size_t __freadahead(FILE* __fp) __INTRODUCED_IN(34);
+
+/**
* [_flushlbf(3)](http://man7.org/linux/man-pages/man3/_flushlbf.3.html) flushes all
* line-buffered streams.
*
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 0f41878..e8d03b9 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1578,6 +1578,7 @@
LIBC_U { # introduced=UpsideDownCake
global:
+ __freadahead;
close_range;
copy_file_range;
memset_explicit;
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
index 945813e..99a8af7 100644
--- a/libc/stdio/stdio_ext.cpp
+++ b/libc/stdio/stdio_ext.cpp
@@ -67,6 +67,12 @@
return fp->_p - fp->_bf._base;
}
+size_t __freadahead(FILE* fp) {
+ // Normally _r is the amount of input already available.
+ // When there's ungetc() data, _r counts that and _ur is the previous _r.
+ return fp->_r + (HASUB(fp) ? fp->_ur : 0);
+}
+
void _flushlbf() {
// If we flush all streams, we know we've flushed all the line-buffered streams.
fflush(nullptr);
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index fce600a..dce1a66 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -78,6 +78,24 @@
fclose(fp);
}
+TEST(stdio_ext, __freadahead) {
+#if defined(__GLIBC__)
+ GTEST_SKIP() << "glibc doesn't have __freadahead";
+#else
+ FILE* fp = tmpfile();
+ ASSERT_NE(EOF, fputs("hello", fp));
+ rewind(fp);
+
+ ASSERT_EQ('h', fgetc(fp));
+ ASSERT_EQ(4u, __freadahead(fp));
+
+ ASSERT_EQ('H', ungetc('H', fp));
+ ASSERT_EQ(5u, __freadahead(fp));
+
+ fclose(fp);
+#endif
+}
+
TEST(stdio_ext, __fpurge) {
FILE* fp = tmpfile();