Skip to content

Commit

Permalink
[libc] Implement vasprintf and asprintf (llvm#98824)
Browse files Browse the repository at this point in the history
[libc] Implement vasprintf and asprintf

---------

Co-authored-by: Izaak Schroeder <[email protected]>
  • Loading branch information
tszhin-swe and izaakschroeder authored Aug 1, 2024
1 parent 2a5f7e5 commit a5e67fb
Show file tree
Hide file tree
Showing 20 changed files with 515 additions and 39 deletions.
2 changes: 2 additions & 0 deletions libc/config/baremetal/arm/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.remove
libc.src.stdio.snprintf
libc.src.stdio.sprintf
libc.src.stdio.asprintf
libc.src.stdio.vprintf
libc.src.stdio.vsnprintf
libc.src.stdio.vsprintf
libc.src.stdio.vasprintf

# stdbit.h entrypoints
libc.src.stdbit.stdc_bit_ceil_uc
Expand Down
2 changes: 2 additions & 0 deletions libc/config/baremetal/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.remove
libc.src.stdio.snprintf
libc.src.stdio.sprintf
libc.src.stdio.asprintf
libc.src.stdio.vprintf
libc.src.stdio.vsnprintf
libc.src.stdio.vsprintf
libc.src.stdio.vasprintf

# stdbit.h entrypoints
libc.src.stdbit.stdc_bit_ceil_uc
Expand Down
10 changes: 10 additions & 0 deletions libc/config/darwin/arm/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.calloc
libc.src.stdlib.realloc
libc.src.stdlib.free

# stdio.h external entrypoints
libc.src.stdio.snprintf
libc.src.stdio.sprintf
libc.src.stdio.asprintf
libc.src.stdio.asprintf
libc.src.stdio.vprintf
libc.src.stdio.vsnprintf
libc.src.stdio.vsprintf
libc.src.stdio.vasprintf
)

set(TARGET_LIBM_ENTRYPOINTS
Expand Down
2 changes: 2 additions & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,12 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.rename
libc.src.stdio.snprintf
libc.src.stdio.sprintf
libc.src.stdio.asprintf
#libc.src.stdio.scanf
#libc.src.stdio.sscanf
libc.src.stdio.vsnprintf
libc.src.stdio.vsprintf
libc.src.stdio.vasprintf

# sys/mman.h entrypoints
libc.src.sys.mman.madvise
Expand Down
2 changes: 2 additions & 0 deletions libc/config/linux/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,14 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.scanf
libc.src.stdio.snprintf
libc.src.stdio.sprintf
libc.src.stdio.asprintf
libc.src.stdio.sscanf
libc.src.stdio.vsscanf
libc.src.stdio.vfprintf
libc.src.stdio.vprintf
libc.src.stdio.vsnprintf
libc.src.stdio.vsprintf
libc.src.stdio.vasprintf

# sys/epoll.h entrypoints
libc.src.sys.epoll.epoll_create
Expand Down
2 changes: 2 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,14 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.scanf
libc.src.stdio.snprintf
libc.src.stdio.sprintf
libc.src.stdio.asprintf
libc.src.stdio.sscanf
libc.src.stdio.vsscanf
libc.src.stdio.vfprintf
libc.src.stdio.vprintf
libc.src.stdio.vsnprintf
libc.src.stdio.vsprintf
libc.src.stdio.vasprintf

# sys/epoll.h entrypoints
libc.src.sys.epoll.epoll_create
Expand Down
16 changes: 16 additions & 0 deletions libc/newhdrgen/yaml/stdio.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,22 @@ functions:
arguments:
- type: const char *__restrict
- type: va_list
- name: asprintf
standards:
- GNUExtensions
return_type: int
arguments:
- type: char **__restrict
- type: const char *__restrict
- type: ...
- name: vasprintf
standards:
- GNUExtensions
return_type: int
arguments:
- type: char **__restrict
- type: const char *__restrict
- type: va_list
- name: sscanf
standards:
- stdc
Expand Down
14 changes: 14 additions & 0 deletions libc/spec/stdc.td
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,13 @@ def StdC : StandardSpec<"stdc"> {
ArgSpec<ConstCharRestrictedPtr>,
ArgSpec<VarArgType>]
>,
FunctionSpec<
"asprintf",
RetValSpec<IntType>,
[ArgSpec<CharRestrictedPtrPtr>,
ArgSpec<ConstCharRestrictedPtr>,
ArgSpec<VarArgType>]
>,
FunctionSpec<
"vsprintf",
RetValSpec<IntType>,
Expand Down Expand Up @@ -1004,6 +1011,13 @@ def StdC : StandardSpec<"stdc"> {
RetValSpec<IntType>,
[ArgSpec<IntType>, ArgSpec<FILEPtr>]
>,
FunctionSpec<
"vasprintf",
RetValSpec<IntType>,
[ArgSpec<CharRestrictedPtrPtr>,
ArgSpec<ConstCharRestrictedPtr>,
ArgSpec<VaListType>]
>,
],
[
ObjectSpec<
Expand Down
20 changes: 20 additions & 0 deletions libc/src/stdio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,16 @@ add_entrypoint_object(
libc.src.stdio.printf_core.writer
)

add_entrypoint_object(
asprintf
SRCS
asprintf.cpp
HDRS
asprintf.h
DEPENDS
libc.src.stdio.printf_core.vasprintf_internal
)

add_entrypoint_object(
vsprintf
SRCS
Expand All @@ -197,6 +207,16 @@ add_entrypoint_object(
libc.src.stdio.printf_core.writer
)

add_entrypoint_object(
vasprintf
SRCS
vasprintf.cpp
HDRS
vasprintf.h
DEPENDS
libc.src.stdio.printf_core.vasprintf_internal
)

add_subdirectory(printf_core)
add_subdirectory(scanf_core)

Expand Down
28 changes: 28 additions & 0 deletions libc/src/stdio/asprintf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===-- Implementation of asprintf -----------------------------*- 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/asprintf.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/vasprintf_internal.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, asprintf,
(char **__restrict buffer, const char *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 handling
// destruction automatically.
va_end(vlist);
int ret = printf_core::vasprintf_internal(buffer, format, args);
return ret;
}

} // namespace LIBC_NAMESPACE
22 changes: 22 additions & 0 deletions libc/src/stdio/asprintf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Implementation header of asprintf ----------------------*- 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_ASPRINTF_H
#define LLVM_LIBC_SRC_STDIO_ASPRINTF_H

#include "src/__support/macros/config.h"
#include <stdarg.h>
#include <stdio.h>

namespace LIBC_NAMESPACE {

int asprintf(char **__restrict s, const char *format, ...);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDIO_ASPRINTF_H
12 changes: 12 additions & 0 deletions libc/src/stdio/printf_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,15 @@ add_header_library(
libc.src.stdio.printf_core.writer
${use_system_file}
)

add_header_library(
vasprintf_internal
HDRS
vasprintf_internal.h
DEPENDS
libc.src.__support.arg_list
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
libc.src.stdlib.malloc
libc.src.stdlib.realloc
)
2 changes: 1 addition & 1 deletion libc/src/stdio/printf_core/core_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ constexpr int FILE_STATUS_ERROR = -2;
constexpr int NULLPTR_WRITE_ERROR = -3;
constexpr int INT_CONVERSION_ERROR = -4;
constexpr int FIXED_POINT_CONVERSION_ERROR = -5;

constexpr int ALLOCATION_ERROR = -6;
} // namespace printf_core
} // namespace LIBC_NAMESPACE_DECL

Expand Down
67 changes: 67 additions & 0 deletions libc/src/stdio/printf_core/vasprintf_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//===-- Internal Implementation of asprintf ---------------------*- 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/__support/arg_list.h"
#include "src/stdio/printf.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
#include <stdlib.h> // malloc, realloc, free

namespace LIBC_NAMESPACE {
namespace printf_core {

LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) {
printf_core::WriteBuffer *wb =
reinterpret_cast<printf_core::WriteBuffer *>(target);
size_t new_size = new_str.size() + wb->buff_cur;
const bool isBuffOnStack = (wb->buff == wb->init_buff);
char *new_buff = static_cast<char *>(
isBuffOnStack ? malloc(new_size + 1)
: realloc(wb->buff, new_size + 1)); // +1 for null
if (new_buff == nullptr) {
if (wb->buff != wb->init_buff)
free(wb->buff);
return printf_core::ALLOCATION_ERROR;
}
if (isBuffOnStack)
inline_memcpy(new_buff, wb->buff, wb->buff_cur);
wb->buff = new_buff;
inline_memcpy(wb->buff + wb->buff_cur, new_str.data(), new_str.size());
wb->buff_cur = new_size;
wb->buff_len = new_size;
return printf_core::WRITE_OK;
}

constexpr size_t DEFAULT_BUFFER_SIZE = 200;

LIBC_INLINE int vasprintf_internal(char **ret, const char *format,
internal::ArgList args) {
char init_buff_on_stack[DEFAULT_BUFFER_SIZE];
printf_core::WriteBuffer wb(init_buff_on_stack, DEFAULT_BUFFER_SIZE,
resize_overflow_hook);
printf_core::Writer writer(&wb);

auto ret_val = printf_core::printf_main(&writer, format, args);
if (ret_val < 0) {
*ret = nullptr;
return -1;
}
if (wb.buff == init_buff_on_stack) {
*ret = static_cast<char *>(malloc(ret_val + 1));
if (ret == nullptr)
return printf_core::ALLOCATION_ERROR;
inline_memcpy(*ret, wb.buff, ret_val);
} else {
*ret = wb.buff;
}
(*ret)[ret_val] = '\0';
return ret_val;
}
} // namespace printf_core
} // namespace LIBC_NAMESPACE
Loading

0 comments on commit a5e67fb

Please sign in to comment.