[libc-commits] [libc] [libc][stdio] Add support for the %m modifier (PR #218312)
via libc-commits
libc-commits at lists.llvm.org
Sun Aug 23 21:01:39 PDT 2026
https://github.com/afnrow created https://github.com/llvm/llvm-project/pull/218312
Add support for the %m modifier and it's derivatives as per
POSIX 2008.1 by leveraging the preexisting FormatFlags::Allocate
and allocating 32 bytes at a time that scale by 2x on each iteration
till it reaches the desired outcome.
>From 8d7e917c8b17224a3dd5ddeffe55ccc84cac5e98 Mon Sep 17 00:00:00 2001
From: yahia ahmed <yahia.a.abdrabou at gmail.com>
Date: Mon, 24 Aug 2026 07:00:01 +0300
Subject: [PATCH] [libc][stdio] Add support for the %m modifier
---
libc/src/stdio/scanf_core/CMakeLists.txt | 1 +
libc/src/stdio/scanf_core/parser.h | 9 ++--
libc/src/stdio/scanf_core/string_converter.h | 51 +++++++++++++++++--
libc/test/src/stdio/scanf_core/CMakeLists.txt | 1 +
4 files changed, 53 insertions(+), 9 deletions(-)
diff --git a/libc/src/stdio/scanf_core/CMakeLists.txt b/libc/src/stdio/scanf_core/CMakeLists.txt
index fd68f5d21ae7f..e566103afa904 100644
--- a/libc/src/stdio/scanf_core/CMakeLists.txt
+++ b/libc/src/stdio/scanf_core/CMakeLists.txt
@@ -105,6 +105,7 @@ add_header_library(
libc.src.__support.CPP.limits
libc.src.__support.char_vector
libc.src.__support.str_to_float
+ libc.src.__support.CPP.new
${use_system_file}
)
diff --git a/libc/src/stdio/scanf_core/parser.h b/libc/src/stdio/scanf_core/parser.h
index 1e2f26e0d3fdd..37e49e6878796 100644
--- a/libc/src/stdio/scanf_core/parser.h
+++ b/libc/src/stdio/scanf_core/parser.h
@@ -81,11 +81,10 @@ template <typename ArgProvider> class Parser {
cur_pos = cur_pos + static_cast<size_t>(result.parsed_len);
}
- // TODO(michaelrj): add posix allocate flag support.
- // if (str[cur_pos] == 'm') {
- // ++cur_pos;
- // section.flags = FormatFlags::ALLOCATE;
- // }
+ if (str[cur_pos] == 'm') {
+ ++cur_pos;
+ section.flags = FormatFlags::ALLOCATE;
+ }
LengthModifier lm = parse_length_modifier(&cur_pos);
section.length_modifier = lm;
diff --git a/libc/src/stdio/scanf_core/string_converter.h b/libc/src/stdio/scanf_core/string_converter.h
index 3879f8c995899..6ed9ea26dcc49 100644
--- a/libc/src/stdio/scanf_core/string_converter.h
+++ b/libc/src/stdio/scanf_core/string_converter.h
@@ -10,10 +10,14 @@
#define LLVM_LIBC_SRC_STDIO_SCANF_CORE_STRING_CONVERTER_H
#include "src/__support/CPP/limits.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
#include "src/__support/ctype_utils.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/stdio/scanf_core/core_structs.h"
#include "src/stdio/scanf_core/reader.h"
+#include "src/string/memory_utils/inline_memcpy.h"
#include <stddef.h>
@@ -40,8 +44,21 @@ int convert_string(Reader<T> *reader, const FormatSection &to_conv) {
}
}
- char *output = reinterpret_cast<char *>(to_conv.output_ptr);
-
+ char *output;
+ size_t value;
+ AllocChecker ac;
+ if ((to_conv.flags & NO_WRITE) == 0 && (to_conv.flags & ALLOCATE) != 0) {
+ if (to_conv.conv_name == 'c')
+ value = max_width + 1;
+ else
+ value = (max_width < 32) ? max_width + 1 : 32;
+ output = new (ac) char[value];
+ if (!ac) {
+ libc_errno = ENOMEM;
+ return MATCHING_FAILURE;
+ }
+ } else
+ output = reinterpret_cast<char *>(to_conv.output_ptr);
char cur_char = reader->getc();
size_t i = 0;
for (; i < max_width && cur_char != '\0'; ++i) {
@@ -53,7 +70,24 @@ int convert_string(Reader<T> *reader, const FormatSection &to_conv) {
}
// if the NO_WRITE flag is not set, write to the output.
if ((to_conv.flags & NO_WRITE) == 0)
- output[i] = cur_char;
+ if ((to_conv.flags & NO_WRITE) == 0) {
+ output[i] = cur_char;
+ if ((to_conv.flags & ALLOCATE) != 0) {
+ if ((i + 1) == value && value < max_width) {
+ value *= 2;
+ char *tmp = new (ac) char[value];
+ if (!ac) {
+ delete[] output;
+ libc_errno = ENOMEM;
+ reader->ungetc(cur_char);
+ return MATCHING_FAILURE;
+ }
+ inline_memcpy(tmp, output, i + 1);
+ delete[] output;
+ output = tmp;
+ }
+ }
+ }
cur_char = reader->getc();
}
@@ -70,8 +104,17 @@ int convert_string(Reader<T> *reader, const FormatSection &to_conv) {
output[i] = '\0';
}
- if (i == 0)
+ if (i == 0) {
+ if ((to_conv.flags & ALLOCATE) != 0 && output)
+ delete[] output;
return MATCHING_FAILURE;
+ }
+
+ if ((to_conv.flags & ALLOCATE) != 0) {
+ char **outptr = reinterpret_cast<char **>(to_conv.output_ptr);
+ *outptr = output;
+ }
+
return READ_OK;
}
diff --git a/libc/test/src/stdio/scanf_core/CMakeLists.txt b/libc/test/src/stdio/scanf_core/CMakeLists.txt
index 6fdee7b3d5d51..0b234c6054721 100644
--- a/libc/test/src/stdio/scanf_core/CMakeLists.txt
+++ b/libc/test/src/stdio/scanf_core/CMakeLists.txt
@@ -47,6 +47,7 @@ add_libc_test(
libc.src.stdio.scanf_core.converter
libc.src.stdio.scanf_core.string_reader
libc.src.__support.CPP.string_view
+ libc.src.__support.CPP.new
COMPILE_OPTIONS
${use_system_file}
)
More information about the libc-commits
mailing list