forked from OSchip/llvm-project
[libc] add sprintf
This adds the sprintf entrypoint, as well as unit tests. Currently sprintf only supports %%, %s, and %c, but the other conversions are on the way. Reviewed By: sivachandra, lntue Differential Revision: https://reviews.llvm.org/D125573
This commit is contained in:
parent
dbf3b5f114
commit
ff6fe39eca
|
@ -268,6 +268,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
|||
libc.src.stdio.funlockfile
|
||||
libc.src.stdio.fwrite
|
||||
libc.src.stdio.fwrite_unlocked
|
||||
libc.src.stdio.sprintf
|
||||
|
||||
# signal.h entrypoints
|
||||
# TODO: Enable signal.h entrypoints after fixing signal.h
|
||||
|
|
|
@ -532,6 +532,13 @@ def StdC : StandardSpec<"stdc"> {
|
|||
ArgSpec<SizeTType>,
|
||||
ArgSpec<FILERestrictedPtr>]
|
||||
>,
|
||||
FunctionSpec<
|
||||
"sprintf",
|
||||
RetValSpec<IntType>,
|
||||
[ArgSpec<CharRestrictedPtr>,
|
||||
ArgSpec<ConstCharRestrictedPtr>,
|
||||
ArgSpec<VarArgType>]
|
||||
>,
|
||||
]
|
||||
>;
|
||||
|
||||
|
|
|
@ -202,3 +202,17 @@ add_entrypoint_object(
|
|||
libc.include.stdio
|
||||
libc.src.__support.File.file
|
||||
)
|
||||
|
||||
|
||||
add_entrypoint_object(
|
||||
sprintf
|
||||
SRCS
|
||||
sprintf.cpp
|
||||
HDRS
|
||||
sprintf.h
|
||||
DEPENDS
|
||||
libc.include.stdio
|
||||
libc.src.stdio.printf_core.printf_main
|
||||
libc.src.stdio.printf_core.string_writer
|
||||
libc.src.stdio.printf_core.writer
|
||||
)
|
||||
|
|
|
@ -51,3 +51,16 @@ add_object_library(
|
|||
.writer
|
||||
.core_structs
|
||||
)
|
||||
|
||||
|
||||
add_header_library(
|
||||
printf_main
|
||||
HDRS
|
||||
printf_main.h
|
||||
DEPENDS
|
||||
.parser
|
||||
.converter
|
||||
.writer
|
||||
.core_structs
|
||||
libc.src.__support.arg_list
|
||||
)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
namespace __llvm_libc {
|
||||
namespace printf_core {
|
||||
|
||||
void convert_char(Writer *writer, FormatSection to_conv) {
|
||||
void convert_char(Writer *writer, const FormatSection &to_conv) {
|
||||
char c = to_conv.conv_val_raw;
|
||||
|
||||
if (to_conv.min_width > 1) {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
namespace __llvm_libc {
|
||||
namespace printf_core {
|
||||
|
||||
void convert(Writer *writer, FormatSection to_conv) {
|
||||
void convert(Writer *writer, const FormatSection &to_conv) {
|
||||
if (!to_conv.has_conv) {
|
||||
writer->write(to_conv.raw_string, to_conv.raw_len);
|
||||
return;
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace printf_core {
|
|||
// convert will call a conversion function to convert the FormatSection into
|
||||
// its string representation, and then that will write the result to the
|
||||
// writer.
|
||||
void convert(Writer *writer, FormatSection to_conv);
|
||||
void convert(Writer *writer, const FormatSection &to_conv);
|
||||
|
||||
} // namespace printf_core
|
||||
} // namespace __llvm_libc
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace __llvm_libc {
|
|||
namespace printf_core {
|
||||
|
||||
int printf_main(Writer *writer, const char *__restrict str,
|
||||
internal::ArgList args) {
|
||||
internal::ArgList &args) {
|
||||
Parser parser(str, args);
|
||||
|
||||
for (FormatSection cur_section = parser.get_next_section();
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
namespace __llvm_libc {
|
||||
namespace printf_core {
|
||||
|
||||
void convert_string(Writer *writer, FormatSection to_conv) {
|
||||
void convert_string(Writer *writer, const FormatSection &to_conv) {
|
||||
int string_len = 0;
|
||||
|
||||
for (char *cur_str = reinterpret_cast<char *>(to_conv.conv_val_ptr);
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
//===-- Implementation of sprintf -------------------------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "src/stdio/sprintf.h"
|
||||
|
||||
#include "src/__support/arg_list.h"
|
||||
#include "src/stdio/printf_core/printf_main.h"
|
||||
#include "src/stdio/printf_core/string_writer.h"
|
||||
#include "src/stdio/printf_core/writer.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
LLVM_LIBC_FUNCTION(int, sprintf,
|
||||
(char *__restrict buffer, const char *__restrict format,
|
||||
...)) {
|
||||
va_list vlist;
|
||||
va_start(vlist, format);
|
||||
internal::ArgList args(vlist); // This holder class allows for easier copying
|
||||
// and pointer semantics, as well as handing
|
||||
// destruction automatically.
|
||||
va_end(vlist);
|
||||
printf_core::StringWriter str_writer(buffer);
|
||||
printf_core::Writer writer(reinterpret_cast<void *>(&str_writer),
|
||||
printf_core::write_to_string);
|
||||
|
||||
int ret_val = printf_core::printf_main(&writer, format, args);
|
||||
str_writer.terminate();
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header of sprintf ------------------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC_STDIO_SPRINTF_H
|
||||
#define LLVM_LIBC_SRC_STDIO_SPRINTF_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int sprintf(char *__restrict buffer, const char *__restrict format, ...);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_STDIO_SPRINTF_H
|
|
@ -63,6 +63,16 @@ add_libc_unittest(
|
|||
LibcMemoryHelpers
|
||||
)
|
||||
|
||||
add_libc_unittest(
|
||||
sprintf_test
|
||||
SUITE
|
||||
libc_stdio_unittests
|
||||
SRCS
|
||||
sprintf_test.cpp
|
||||
DEPENDS
|
||||
libc.src.stdio.sprintf
|
||||
)
|
||||
|
||||
add_subdirectory(printf_core)
|
||||
|
||||
add_subdirectory(testdata)
|
||||
|
|
|
@ -53,6 +53,7 @@ TEST(LlvmLibcPrintfParserTest, EvalRaw) {
|
|||
expected.raw_string = str;
|
||||
|
||||
ASSERT_FORMAT_EQ(expected, format_arr[0]);
|
||||
// TODO: add checks that the format_arr after the last one has length 0
|
||||
}
|
||||
|
||||
TEST(LlvmLibcPrintfParserTest, EvalSimple) {
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
//===-- Unittests for sprintf ---------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "src/stdio/sprintf.h"
|
||||
|
||||
#include "utils/UnitTest/Test.h"
|
||||
|
||||
TEST(LlvmLibcSPrintfTest, SimpleNoConv) {
|
||||
char buff[64];
|
||||
int written;
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "A simple string with no conversions.");
|
||||
EXPECT_EQ(written, 36);
|
||||
ASSERT_STREQ(buff, "A simple string with no conversions.");
|
||||
}
|
||||
|
||||
TEST(LlvmLibcSPrintfTest, PercentConv) {
|
||||
char buff[64];
|
||||
int written;
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%%");
|
||||
EXPECT_EQ(written, 1);
|
||||
ASSERT_STREQ(buff, "%");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "abc %% def");
|
||||
EXPECT_EQ(written, 9);
|
||||
ASSERT_STREQ(buff, "abc % def");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%%%%%%");
|
||||
EXPECT_EQ(written, 3);
|
||||
ASSERT_STREQ(buff, "%%%");
|
||||
}
|
||||
|
||||
TEST(LlvmLibcSPrintfTest, CharConv) {
|
||||
char buff[64];
|
||||
int written;
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%c", 'a');
|
||||
EXPECT_EQ(written, 1);
|
||||
ASSERT_STREQ(buff, "a");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%3c %-3c", '1', '2');
|
||||
EXPECT_EQ(written, 7);
|
||||
ASSERT_STREQ(buff, " 1 2 ");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%*c", 2, '3');
|
||||
EXPECT_EQ(written, 2);
|
||||
ASSERT_STREQ(buff, " 3");
|
||||
}
|
||||
|
||||
TEST(LlvmLibcSPrintfTest, StringConv) {
|
||||
char buff[64];
|
||||
int written;
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%s", "abcDEF123");
|
||||
EXPECT_EQ(written, 9);
|
||||
ASSERT_STREQ(buff, "abcDEF123");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%10s %-10s", "centered", "title");
|
||||
EXPECT_EQ(written, 21);
|
||||
ASSERT_STREQ(buff, " centered title ");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%-5.4s%-4.4s", "words can describe",
|
||||
"soups most delicious");
|
||||
EXPECT_EQ(written, 9);
|
||||
ASSERT_STREQ(buff, "word soup");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%*s %.*s %*.*s", 10, "beginning", 2,
|
||||
"isn't", 12, 10, "important. Ever.");
|
||||
EXPECT_EQ(written, 26);
|
||||
ASSERT_STREQ(buff, " beginning is important.");
|
||||
}
|
||||
|
||||
#ifndef LLVM_LIBC_PRINTF_DISABLE_INDEX_MODE
|
||||
TEST(LlvmLibcSPrintfTest, IndexModeParsing) {
|
||||
char buff[64];
|
||||
int written;
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%1$s", "abcDEF123");
|
||||
EXPECT_EQ(written, 9);
|
||||
ASSERT_STREQ(buff, "abcDEF123");
|
||||
|
||||
written = __llvm_libc::sprintf(buff, "%1$s %%", "abcDEF123");
|
||||
EXPECT_EQ(written, 11);
|
||||
ASSERT_STREQ(buff, "abcDEF123 %");
|
||||
|
||||
written =
|
||||
__llvm_libc::sprintf(buff, "%3$s %1$s %2$s", "is", "hard", "ordering");
|
||||
EXPECT_EQ(written, 16);
|
||||
ASSERT_STREQ(buff, "ordering is hard");
|
||||
|
||||
written = __llvm_libc::sprintf(
|
||||
buff, "%10$s %9$s %8$c %7$s %6$s, %6$s %5$s %4$-*1$s %3$.*11$s %2$s. %%",
|
||||
6, "pain", "alphabetical", "such", "is", "this", "do", 'u', "would",
|
||||
"why", 1);
|
||||
EXPECT_EQ(written, 45);
|
||||
ASSERT_STREQ(buff, "why would u do this, this is such a pain. %");
|
||||
}
|
||||
#endif // LLVM_LIBC_PRINTF_DISABLE_INDEX_MODE
|
Loading…
Reference in New Issue