diff --git a/userspace/libraries/LibC/include/stdio.h b/userspace/libraries/LibC/include/stdio.h index a23454c8..fbf974c9 100644 --- a/userspace/libraries/LibC/include/stdio.h +++ b/userspace/libraries/LibC/include/stdio.h @@ -56,6 +56,7 @@ extern FILE* __stderr; extern FILE* __stddbg; #define stddbg __stddbg +int asprintf(char** __restrict ptr, const char* __restrict format, ...); void clearerr(FILE* stream); char* ctermid(char* s); int dprintf(int fildes, const char* __restrict format, ...); @@ -116,6 +117,7 @@ char* tempnam(const char* dir, const char* pfx); FILE* tmpfile(void); char* tmpnam(char* s); int ungetc(int c, FILE* stream); +int vasprintf(char** __restrict ptr, const char* __restrict format, va_list ap); int vdprintf(int fildes, const char* __restrict format, va_list ap); int vfprintf(FILE* __restrict stream, const char* __restrict format, va_list ap); int vfscanf(FILE* __restrict stream, const char* __restrict format, va_list arg); diff --git a/userspace/libraries/LibC/stdio.cpp b/userspace/libraries/LibC/stdio.cpp index a1db96ea..43709a13 100644 --- a/userspace/libraries/LibC/stdio.cpp +++ b/userspace/libraries/LibC/stdio.cpp @@ -120,6 +120,15 @@ static void _init_stdio() s_files[STDDBG_FILENO].buffer_type = _IOLBF; } +int asprintf(char** __restrict ptr, const char* __restrict format, ...) +{ + va_list arguments; + va_start(arguments, format); + int ret = vasprintf(ptr, format, arguments); + va_end(arguments); + return ret; +} + void clearerr(FILE* file) { ScopeLock _(file); @@ -1023,6 +1032,62 @@ int ungetc(int c, FILE* stream) return ungetc_unlocked(c, stream); } + +int vasprintf(char** __restrict ptr, const char* __restrict format, va_list ap) +{ + struct print_info + { + char* buffer; + size_t capacity; + size_t length; + }; + print_info info { + .buffer = nullptr, + .capacity = 0, + .length = 0, + }; + + info.buffer = static_cast(malloc(16)); + if (info.buffer == nullptr) + return -1; + info.capacity = 16; + + const int ret = printf_impl(format, ap, + [](int c, void* _info) -> int + { + auto& info = *static_cast(_info); + + if (info.length + 1 >= info.capacity) + { + const size_t new_capacity = info.capacity * 2; + void* new_buffer = realloc(info.buffer, new_capacity); + if (new_buffer == nullptr) + { + free(info.buffer); + info.buffer = nullptr; + return EOF; + } + + info.buffer = static_cast(new_buffer); + info.capacity = new_capacity; + } + + info.buffer[info.length++] = c; + return 0; + }, &info + ); + + if (info.buffer == nullptr) + return -1; + + ASSERT(info.length < info.capacity); + info.buffer[info.length] = '\0'; + + *ptr = info.buffer; + + return ret; +} + int vdprintf(int fildes, const char* __restrict format, va_list arguments) { struct print_info