[libc-commits] [libc] [libc][stdio] Implement getline and getdelim POSIX functions (PR #219601)
via libc-commits
libc-commits at lists.llvm.org
Fri Aug 28 16:52:08 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: yahia (afnrow)
<details>
<summary>Changes</summary>
Add support for getline and getdelim POSIX functions by defining a __getline helper function and route getline and getdelim through it.
---
Full diff: https://github.com/llvm/llvm-project/pull/219601.diff
9 Files Affected:
- (modified) libc/config/linux/x86_64/entrypoints.txt (+2)
- (modified) libc/include/stdio.yaml (+17)
- (modified) libc/src/stdio/CMakeLists.txt (+32)
- (added) libc/src/stdio/getdelim.cpp (+17)
- (added) libc/src/stdio/getdelim.h (+14)
- (added) libc/src/stdio/getline.cpp (+19)
- (added) libc/src/stdio/getline.h (+16)
- (added) libc/src/stdio/inline_getline.h (+72)
- (modified) libc/utils/docgen/stdio.yaml (+2-2)
``````````diff
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index e78b4d47edd9f..0abd8f6c72a0f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -285,6 +285,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.vsnprintf
libc.src.stdio.vsprintf
libc.src.stdio.vasprintf
+ libc.src.stdio.getline
+ libc.src.stdio.getdelim
# sys/epoll.h entrypoints
libc.src.sys.epoll.epoll_create
diff --git a/libc/include/stdio.yaml b/libc/include/stdio.yaml
index ef725dd4fe619..9f481b2783a38 100644
--- a/libc/include/stdio.yaml
+++ b/libc/include/stdio.yaml
@@ -288,6 +288,23 @@ functions:
return_type: int
arguments:
- type: FILE *
+ - name: getline
+ standards:
+ - posix
+ return_type: ssize_t
+ arguments:
+ - type: char **__restrict
+ - type: size_t *__restrict
+ - type: FILE *
+ - name: getdelim
+ standards:
+ - posix
+ return_type: ssize_t
+ arguments:
+ - type: char **__restrict
+ - type: size_t *__restrict
+ - type: int
+ - type: FILE *
- name: getchar
standards:
- stdc
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 3ef6e4f7b7d01..52d874460df4c 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -40,6 +40,38 @@ add_entrypoint_object(
libc.src.__support.File.platform_file
)
+add_entrypoint_object(
+ getline
+ SRCS
+ getline.cpp
+ HDRS
+ getline.h
+ inline_getline.h
+ DEPENDS
+ libc.hdr.func.malloc
+ libc.hdr.func.realloc
+ libc.hdr.types.FILE
+ libc.hdr.types.ssize_t
+ libc.src.__support.File.file
+ libc.src.__support.libc_errno
+)
+
+add_entrypoint_object(
+ getdelim
+ SRCS
+ getdelim.cpp
+ HDRS
+ getdelim.h
+ inline_getline.h
+ DEPENDS
+ libc.hdr.func.malloc
+ libc.hdr.func.realloc
+ libc.hdr.types.FILE
+ libc.hdr.types.ssize_t
+ libc.src.__support.File.file
+ libc.src.__support.libc_errno
+)
+
add_entrypoint_object(
funlockfile
SRCS
diff --git a/libc/src/stdio/getdelim.cpp b/libc/src/stdio/getdelim.cpp
new file mode 100644
index 0000000000000..2e50f20da69e9
--- /dev/null
+++ b/libc/src/stdio/getdelim.cpp
@@ -0,0 +1,17 @@
+#include "src/stdio/getdelim.h"
+
+#include "hdr/types/FILE.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/File/file.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/inline_getline.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+ LLVM_LIBC_FUNCTION(ssize_t, getdelim, (char **__restrict lineptr, size_t *__restrict n,
+ int delimiter, ::FILE *__restrict stream)) {
+ return LIBC_NAMESPACE::__getline(lineptr, n, delimiter, stream);
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/getdelim.h b/libc/src/stdio/getdelim.h
new file mode 100644
index 0000000000000..050e8bca13c44
--- /dev/null
+++ b/libc/src/stdio/getdelim.h
@@ -0,0 +1,14 @@
+#ifndef LLVM_LIBC_SRC_STDIO_GETDELIM_H
+#define LLVM_LIBC_SRC_STDIO_GETDELIM_H
+
+#include "hdr/types/FILE.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+ssize_t getdelim(char **__restrict lineptr, size_t *__restrict n, int delimiter,
+ ::FILE *__restrict stream);
+} // namespace LIBC_NAMESPACE_DECL
+#endif
diff --git a/libc/src/stdio/getline.cpp b/libc/src/stdio/getline.cpp
new file mode 100644
index 0000000000000..d4524a5eb6c94
--- /dev/null
+++ b/libc/src/stdio/getline.cpp
@@ -0,0 +1,19 @@
+#include "src/stdio/getline.h"
+
+#include "hdr/types/FILE.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/File/file.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/inline_getline.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(ssize_t, getline,
+ (char **__restrict lineptr, size_t *__restrict n,
+ ::FILE *__restrict stream)) {
+ return LIBC_NAMESPACE::__getline(lineptr, n, '\n', stream);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/getline.h b/libc/src/stdio/getline.h
new file mode 100644
index 0000000000000..de090b3a93780
--- /dev/null
+++ b/libc/src/stdio/getline.h
@@ -0,0 +1,16 @@
+#ifndef LLVM_LIBC_SRC_STDIO_GETLINE_H
+#define LLVM_LIBC_SRC_STDIO_GETLINE_H
+
+#include "hdr/types/FILE.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+ssize_t getline(char **__restrict lineptr, size_t *__restrict n,
+ ::FILE *__restrict stream);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif
diff --git a/libc/src/stdio/inline_getline.h b/libc/src/stdio/inline_getline.h
new file mode 100644
index 0000000000000..0cae435312222
--- /dev/null
+++ b/libc/src/stdio/inline_getline.h
@@ -0,0 +1,72 @@
+#ifndef LLVM_LIBC_SRC_STDIO_INLINE_GETLINE_H
+#define LLVM_LIBC_SRC_STDIO_INLINE_GETLINE_H
+
+#include "hdr/func/free.h"
+#include "hdr/func/malloc.h"
+#include "hdr/func/realloc.h"
+#include "hdr/types/FILE.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/File/file.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+constexpr int INIT_BASE = 32;
+
+namespace LIBC_NAMESPACE_DECL {
+
+LIBC_INLINE ssize_t __getline(char **__restrict lineptr, size_t *__restrict n,
+ int del, ::FILE *__restrict stream) {
+ if (!lineptr || !n || !stream) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ auto *file = reinterpret_cast<LIBC_NAMESPACE::File *>(stream);
+
+ if (*lineptr == nullptr) {
+ *n = (*n == 0) ? INIT_BASE : *n;
+ *lineptr = static_cast<char *>(malloc(*n));
+ if (!*lineptr) {
+ libc_errno = ENOMEM;
+ return -1;
+ }
+ }
+ uint8_t c = 0;
+ size_t bytes_read = 0;
+ file->lock();
+ while (true) {
+ auto result = file->read_unlocked(&c, 1);
+ if (result.has_error()) {
+ file->unlock();
+ libc_errno = result.error;
+ return EOF;
+ }
+ if (result.value != 1)
+ break;
+ if ((bytes_read + 2) > *n) {
+ size_t new_size =
+ ((bytes_read + 2) >= (*n * 2)) ? bytes_read + 2 : *n * 2;
+ char *tmpptr = static_cast<char *>(realloc(*lineptr, new_size));
+ if (!tmpptr) {
+ file->unlock();
+ libc_errno = ENOMEM;
+ return -1;
+ }
+ *lineptr = tmpptr;
+ *n = new_size;
+ }
+ (*lineptr)[bytes_read++] = static_cast<char>(c);
+
+ if (c == del)
+ break;
+ }
+ file->unlock();
+ if (bytes_read == 0)
+ return -1;
+ (*lineptr)[bytes_read] = '\0';
+ return bytes_read;
+}
+} // namespace LIBC_NAMESPACE_DECL
+#endif
diff --git a/libc/utils/docgen/stdio.yaml b/libc/utils/docgen/stdio.yaml
index 9dabee44a51c8..a3e419fe3b2dc 100644
--- a/libc/utils/docgen/stdio.yaml
+++ b/libc/utils/docgen/stdio.yaml
@@ -207,9 +207,9 @@ functions:
funlockfile:
in-latest-posix: ''
getdelim:
- in-latest-posix: ''
+ in-latest-posix: 'YES'
getline:
- in-latest-posix: ''
+ in-latest-posix: 'YES'
open_memstream:
in-latest-posix: ''
pclose:
``````````
</details>
https://github.com/llvm/llvm-project/pull/219601
More information about the libc-commits
mailing list