[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