[libc-commits] [libc] [libc] Add strfromf128 entrypoint. (PR #227743)
Alex Strelnikov via libc-commits
libc-commits at lists.llvm.org
Wed Sep 30 07:47:17 PDT 2026
https://github.com/strel-12 created https://github.com/llvm/llvm-project/pull/227743
The implementation of each strfrom* function moves to a single function template in stdlib/str_from_util.h, since #225805 removed the only difference between them: `strfroml()` previously needed to manually override `FormatSection::length_modifier`. This also fixes a mistaken duplicate `if (result < 0)` check added to `strfroml()` in that PR.
Similarly to the other strfrom* tests, the added unit test focuses more on correct parsing of the format, as the numerical correctness of the conversions is more exhaustively covered elsewhere.
>From 88cb55a3ee5388f2304d0fb35e889640efecab60 Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Wed, 30 Sep 2026 14:32:03 +0000
Subject: [PATCH] Add strfromf128 entrypoint.
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/include/stdlib.yaml | 10 ++
libc/src/stdlib/CMakeLists.txt | 28 +++--
libc/src/stdlib/str_from_util.h | 34 +++++-
libc/src/stdlib/strfromd.cpp | 26 +---
libc/src/stdlib/strfromf.cpp | 26 +---
libc/src/stdlib/strfromf128.cpp | 26 ++++
libc/src/stdlib/strfromf128.h | 28 +++++
libc/src/stdlib/strfroml.cpp | 29 +----
libc/test/src/stdlib/CMakeLists.txt | 14 +++
libc/test/src/stdlib/strfromf128_test.cpp | 142 ++++++++++++++++++++++
12 files changed, 278 insertions(+), 87 deletions(-)
create mode 100644 libc/src/stdlib/strfromf128.cpp
create mode 100644 libc/src/stdlib/strfromf128.h
create mode 100644 libc/test/src/stdlib/strfromf128_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 140f3dde5329c..f3a5af13b091d 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -244,6 +244,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.srand
libc.src.stdlib.strfromd
libc.src.stdlib.strfromf
+ libc.src.stdlib.strfromf128
# TODO: long double support is buggy with clang-11. Re-enable when buildbots are upgraded.
# libc.src.stdlib.strfroml
libc.src.stdlib.strtod
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index e3facf92e81de..6dfe08cdf8c85 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -268,6 +268,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.srand
libc.src.stdlib.strfromd
libc.src.stdlib.strfromf
+ libc.src.stdlib.strfromf128
libc.src.stdlib.strfroml
libc.src.stdlib.strtod
libc.src.stdlib.strtof
diff --git a/libc/include/stdlib.yaml b/libc/include/stdlib.yaml
index 4c2f3337cd45c..bd13d6fadb236 100644
--- a/libc/include/stdlib.yaml
+++ b/libc/include/stdlib.yaml
@@ -287,6 +287,16 @@ functions:
- type: size_t
- type: const char *__restrict
- type: float
+ - name: strfromf128
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: char *__restrict
+ - type: size_t
+ - type: const char *__restrict
+ - type: float128
+ guard: LIBC_TYPES_HAS_NATIVE_FLOAT128
- name: strfroml
standards:
- stdc
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index faa31c62d1d8e..28f93be03d92b 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -115,8 +115,18 @@ add_entrypoint_object(
strfromf.h
DEPENDS
.str_from_util
- libc.src.__support.CPP.limits
- libc.src.__support.printf_core.error_mapper
+ libc.hdr.types.size_t
+)
+
+add_entrypoint_object(
+ strfromf128
+ SRCS
+ strfromf128.cpp
+ HDRS
+ strfromf128.h
+ DEPENDS
+ .str_from_util
+ libc.hdr.types.size_t
)
add_entrypoint_object(
@@ -127,8 +137,7 @@ add_entrypoint_object(
strfromd.h
DEPENDS
.str_from_util
- libc.src.__support.CPP.limits
- libc.src.__support.printf_core.error_mapper
+ libc.hdr.types.size_t
)
add_entrypoint_object(
@@ -139,8 +148,7 @@ add_entrypoint_object(
strfroml.h
DEPENDS
.str_from_util
- libc.src.__support.CPP.limits
- libc.src.__support.printf_core.error_mapper
+ libc.hdr.types.size_t
)
add_header_library(
@@ -148,11 +156,17 @@ add_header_library(
HDRS
str_from_util.h
DEPENDS
+ libc.hdr.types.size_t
+ libc.src.__support.CPP.limits
+ libc.src.__support.CPP.type_traits
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
libc.src.__support.printf_core.converter
libc.src.__support.printf_core.core_structs
+ libc.src.__support.printf_core.error_mapper
libc.src.__support.printf_core.writer
libc.src.__support.str_to_integer
- libc.src.__support.CPP.type_traits
+ libc.src.errno.errno
)
add_entrypoint_object(
diff --git a/libc/src/stdlib/str_from_util.h b/libc/src/stdlib/str_from_util.h
index 1b0d45d539537..87d77100d9c98 100644
--- a/libc/src/stdlib/str_from_util.h
+++ b/libc/src/stdlib/str_from_util.h
@@ -17,21 +17,20 @@
#ifndef LLVM_LIBC_SRC_STDLIB_STRFROM_UTIL_H
#define LLVM_LIBC_SRC_STDLIB_STRFROM_UTIL_H
+#include "hdr/types/size_t.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/type_traits.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/__support/printf_core/converter_atlas.h"
#include "src/__support/printf_core/core_structs.h"
+#include "src/__support/printf_core/error_mapper.h"
#include "src/__support/printf_core/writer.h"
#include "src/__support/str_to_integer.h"
-#include <stddef.h>
-
namespace LIBC_NAMESPACE_DECL {
namespace internal {
-template <typename T>
-using storage_type = typename fputil::FPBits<T>::StorageType;
-
template <typename T, printf_core::OverflowMode overflow_mode>
LIBC_INLINE int strfromfloat_convert(printf_core::Writer<overflow_mode> *writer,
const char *__restrict format, T fp) {
@@ -109,6 +108,31 @@ LIBC_INLINE int strfromfloat_convert(printf_core::Writer<overflow_mode> *writer,
__builtin_unreachable();
}
+template <typename T>
+LIBC_INLINE int strfromfloat_impl(char *__restrict s, size_t n,
+ const char *__restrict format, T fp) {
+ LIBC_ASSERT(s != nullptr);
+
+ printf_core::Writer writer =
+ printf_core::make_drop_overflow_writer(s, (n > 0 ? n - 1 : 0));
+ int result = strfromfloat_convert(&writer, format, fp);
+ if (result < 0)
+ return result;
+
+ if (n > 0) {
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
+ wb.buff[wb.buff_cur] = '\0';
+ }
+
+ if (writer.get_chars_written() >
+ static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+ return static_cast<int>(writer.get_chars_written());
+}
+
} // namespace internal
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp
index e54b35b22b869..d6988e28cebcb 100644
--- a/libc/src/stdlib/strfromd.cpp
+++ b/libc/src/stdlib/strfromd.cpp
@@ -7,10 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strfromd.h"
-#include "src/__support/CPP/limits.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/printf_core/core_structs.h"
-#include "src/__support/printf_core/error_mapper.h"
+#include "hdr/types/size_t.h"
#include "src/stdlib/str_from_util.h"
namespace LIBC_NAMESPACE_DECL {
@@ -18,26 +15,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, strfromd,
(char *__restrict s, size_t n, const char *__restrict format,
double fp)) {
- LIBC_ASSERT(s != nullptr);
-
- printf_core::Writer writer =
- printf_core::make_drop_overflow_writer(s, (n > 0 ? n - 1 : 0));
- int result = internal::strfromfloat_convert(&writer, format, fp);
- if (result < 0)
- return result;
-
- if (n > 0) {
- printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
- wb.buff[wb.buff_cur] = '\0';
- }
-
- if (writer.get_chars_written() >
- static_cast<size_t>(cpp::numeric_limits<int>::max())) {
- libc_errno =
- printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
- return -1;
- }
- return static_cast<int>(writer.get_chars_written());
+ return internal::strfromfloat_impl(s, n, format, fp);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strfromf.cpp b/libc/src/stdlib/strfromf.cpp
index 558cf9ff93750..f1dc8aa9622d3 100644
--- a/libc/src/stdlib/strfromf.cpp
+++ b/libc/src/stdlib/strfromf.cpp
@@ -7,10 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strfromf.h"
-#include "src/__support/CPP/limits.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/printf_core/core_structs.h"
-#include "src/__support/printf_core/error_mapper.h"
+#include "hdr/types/size_t.h"
#include "src/stdlib/str_from_util.h"
namespace LIBC_NAMESPACE_DECL {
@@ -18,26 +15,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, strfromf,
(char *__restrict s, size_t n, const char *__restrict format,
float fp)) {
- LIBC_ASSERT(s != nullptr);
-
- printf_core::Writer writer =
- printf_core::make_drop_overflow_writer(s, (n > 0 ? n - 1 : 0));
- int result = internal::strfromfloat_convert(&writer, format, fp);
- if (result < 0)
- return result;
-
- if (n > 0) {
- printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
- wb.buff[wb.buff_cur] = '\0';
- }
-
- if (writer.get_chars_written() >
- static_cast<size_t>(cpp::numeric_limits<int>::max())) {
- libc_errno =
- printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
- return -1;
- }
- return static_cast<int>(writer.get_chars_written());
+ return internal::strfromfloat_impl(s, n, format, fp);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strfromf128.cpp b/libc/src/stdlib/strfromf128.cpp
new file mode 100644
index 0000000000000..aaf14ad182803
--- /dev/null
+++ b/libc/src/stdlib/strfromf128.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of strfromf128.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strfromf128.h"
+#include "hdr/types/size_t.h"
+#include "src/stdlib/str_from_util.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, strfromf128,
+ (char *__restrict s, size_t n, const char *__restrict format,
+ float128 fp)) {
+ return internal::strfromfloat_impl(s, n, format, fp);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strfromf128.h b/libc/src/stdlib/strfromf128.h
new file mode 100644
index 0000000000000..27862b1eb5084
--- /dev/null
+++ b/libc/src/stdlib/strfromf128.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Function declaration of strfromf128.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRFROMF128_H
+#define LLVM_LIBC_SRC_STDLIB_STRFROMF128_H
+
+#include "hdr/types/size_t.h"
+#include "include/llvm-libc-types/float128.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int strfromf128(char *__restrict s, size_t n, const char *__restrict format,
+ float128 fp);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRFROMF128_H
diff --git a/libc/src/stdlib/strfroml.cpp b/libc/src/stdlib/strfroml.cpp
index ef87d5fd7578c..c859649ef7fd8 100644
--- a/libc/src/stdlib/strfroml.cpp
+++ b/libc/src/stdlib/strfroml.cpp
@@ -7,10 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strfroml.h"
-#include "src/__support/CPP/limits.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/printf_core/core_structs.h"
-#include "src/__support/printf_core/error_mapper.h"
+#include "hdr/types/size_t.h"
#include "src/stdlib/str_from_util.h"
namespace LIBC_NAMESPACE_DECL {
@@ -18,29 +15,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, strfroml,
(char *__restrict s, size_t n, const char *__restrict format,
long double fp)) {
- LIBC_ASSERT(s != nullptr);
-
- printf_core::Writer writer =
- printf_core::make_drop_overflow_writer(s, (n > 0 ? n - 1 : 0));
- int result = internal::strfromfloat_convert(&writer, format, fp);
- if (result < 0)
- return result;
-
- if (result < 0)
- return result;
-
- if (n > 0) {
- printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
- wb.buff[wb.buff_cur] = '\0';
- }
-
- if (writer.get_chars_written() >
- static_cast<size_t>(cpp::numeric_limits<int>::max())) {
- libc_errno =
- printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
- return -1;
- }
- return static_cast<int>(writer.get_chars_written());
+ return internal::strfromfloat_impl(s, n, format, fp);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt
index 40167c1638cc7..bc705754b64a5 100644
--- a/libc/test/src/stdlib/CMakeLists.txt
+++ b/libc/test/src/stdlib/CMakeLists.txt
@@ -194,6 +194,20 @@ add_libc_test(
${strfrom_test_copts}
)
+add_libc_test(
+ strfromf128_test
+ SUITE
+ libc-stdlib-tests
+ SRCS
+ strfromf128_test.cpp
+ DEPENDS
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.macros.properties.architectures
+ libc.src.stdlib.strfromf128
+ COMPILE_OPTIONS
+ ${strfrom_test_copts}
+)
+
add_libc_test(
strfromd_test
SUITE
diff --git a/libc/test/src/stdlib/strfromf128_test.cpp b/libc/test/src/stdlib/strfromf128_test.cpp
new file mode 100644
index 0000000000000..93fde1c136639
--- /dev/null
+++ b/libc/test/src/stdlib/strfromf128_test.cpp
@@ -0,0 +1,142 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for strfromf128.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/properties/architectures.h"
+#include "src/stdlib/strfromf128.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+#define EXPECT_STREQ_LEN(str_size_needed, actual_str, expected_str) \
+ EXPECT_EQ(str_size_needed, static_cast<int>(sizeof(expected_str) - 1)); \
+ EXPECT_STREQ(actual_str, expected_str);
+
+namespace {
+
+using LlvmLibcStrfromlTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::fputil::FPBits;
+
+TEST_F(LlvmLibcStrfromlTest, DecimalFormat) {
+ char buff[64];
+ int result;
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%f", 1.0);
+ EXPECT_STREQ_LEN(result, buff, "1.000000");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%.F", -2.5);
+ EXPECT_STREQ_LEN(result, buff, "-2");
+}
+
+TEST_F(LlvmLibcStrfromlTest, HexExponentFormat) {
+ char buff[64];
+ int result;
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%a", 1.0);
+ EXPECT_STREQ_LEN(result, buff, "0x1p+0");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%A", -1.0);
+ EXPECT_STREQ_LEN(result, buff, "-0X1P+0");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%a", -0x1.abcdef12345p0);
+ EXPECT_STREQ_LEN(result, buff, "-0x1.abcdef12345p+0");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%.5A", 0x1.abcdef12345p0);
+ EXPECT_STREQ_LEN(result, buff, "0X1.ABCDFP+0");
+}
+
+TEST_F(LlvmLibcStrfromlTest, DecimalExponentFormat) {
+ char buff[64] = {};
+ int result;
+
+ result =
+ LIBC_NAMESPACE::strfromf128(buff, 63, "%.9e", 1000000000500000000.1L);
+ EXPECT_STREQ_LEN(result, buff, "1.000000001e+18");
+
+ result =
+ LIBC_NAMESPACE::strfromf128(buff, 63, "%.9E", 1000000000500000000.0L);
+ EXPECT_STREQ_LEN(result, buff, "1.000000000E+18");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%e", -1e100L);
+ EXPECT_STREQ_LEN(result, buff, "-1.000000e+100");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%E", 1.0L);
+ EXPECT_STREQ_LEN(result, buff, "1.000000E+00");
+}
+
+TEST_F(LlvmLibcStrfromlTest, DecimalAutoFormat) {
+ char buff[64] = {};
+ int result;
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%g", 9.99999999999e-100L);
+ EXPECT_STREQ_LEN(result, buff, "1e-99");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%G", 1e100L);
+ EXPECT_STREQ_LEN(result, buff, "1E+100");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%g", 1.0);
+ EXPECT_STREQ_LEN(result, buff, "1");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, "%g", -0.1);
+ EXPECT_STREQ_LEN(result, buff, "-0.1");
+}
+
+TEST_F(LlvmLibcStrfromlTest, InsufficientBufferSize) {
+ char buff[6] = {'a', 'b', 'c', 'd', 'e', '\0'};
+ int result;
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 0, "%g", 1.0);
+ EXPECT_EQ(result, 1);
+ ASSERT_STREQ(buff, "abcde");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 5, "%f", 1234567890.0L);
+ EXPECT_EQ(result, 17);
+ ASSERT_STREQ(buff, "1234");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 5, "%.5f", 1.05);
+ EXPECT_EQ(result, 7);
+ ASSERT_STREQ(buff, "1.05");
+}
+
+TEST_F(LlvmLibcStrfromlTest, InfNanValues) {
+ char buff[64] = {};
+ int result;
+
+ float128 inf = FPBits<float128>::inf().get_val();
+ float128 nan = FPBits<float128>::quiet_nan().get_val();
+
+ const char *lower_formats[] = {"%f", "%e", "%a", "%g"};
+ const char *upper_formats[] = {"%F", "%E", "%A", "%G"};
+
+ for (int i = 0; i < 4; ++i) {
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, lower_formats[i], inf);
+ EXPECT_STREQ_LEN(result, buff, "inf");
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, lower_formats[i], -inf);
+ EXPECT_STREQ_LEN(result, buff, "-inf");
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, lower_formats[i], nan);
+ EXPECT_STREQ_LEN(result, buff, "nan");
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, lower_formats[i], -nan);
+ EXPECT_STREQ_LEN(result, buff, "-nan");
+
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, upper_formats[i], inf);
+ EXPECT_STREQ_LEN(result, buff, "INF");
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, upper_formats[i], -inf);
+ EXPECT_STREQ_LEN(result, buff, "-INF");
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, upper_formats[i], nan);
+ EXPECT_STREQ_LEN(result, buff, "NAN");
+ result = LIBC_NAMESPACE::strfromf128(buff, 63, upper_formats[i], -nan);
+ EXPECT_STREQ_LEN(result, buff, "-NAN");
+ }
+}
+
+} // namespace
More information about the libc-commits
mailing list