diff --git a/libc/Makefile b/libc/Makefile index d8066586..d6f8cda9 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -64,6 +64,7 @@ signal/sigisemptyset.o \ signal/sigismember.o \ signal/signotset.o \ signal/sigorset.o \ +stdio/asprintf.o \ stdio/clearerr.o \ stdio/dprintf.o \ stdio/fbufsize.o \ @@ -112,6 +113,7 @@ stdio/snprintf.o \ stdio/sprintf.o \ stdio/sscanf.o \ stdio/ungetc.o \ +stdio/vasprintf.o \ stdio/vdprintf.o \ stdio/vfscanf.o \ stdio/vprintf_callback.o \ diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 0e27237c..35f077af 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -98,6 +98,7 @@ extern FILE* stderr; #define stdout stdout #define stderr stderr +int asprintf(char** __restrict, const char* __restrict, ...); void clearerr(FILE* stream); int dprintf(int fildes, const char* __restrict format, ...); int fclose(FILE* stream); @@ -152,6 +153,7 @@ int sscanf(const char* __restrict s, const char* __restrict format, ...); FILE* tmpfile(void); char* tmpnam(char* s); int ungetc(int c, FILE* stream); +int vasprintf(char** __restrict, const char* __restrict, __gnuc_va_list); int vdprintf(int fildes, const char* __restrict format, __gnuc_va_list ap); int vfprintf(FILE* __restrict stream, const char* __restrict format, __gnuc_va_list ap); int vfscanf(FILE* __restrict stream, const char* __restrict format, __gnuc_va_list arg); diff --git a/libc/stdio/asprintf.cpp b/libc/stdio/asprintf.cpp new file mode 100644 index 00000000..af1aa6e4 --- /dev/null +++ b/libc/stdio/asprintf.cpp @@ -0,0 +1,38 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/asprintf.cpp + Prints a string to a newly allocated buffer. + +*******************************************************************************/ + +#include +#include + +extern "C" +int asprintf(char** restrict result_ptr, + const char* restrict format, + ...) +{ + va_list list; + va_start(list, format); + int result = vasprintf(result_ptr, format, list); + va_end(list); + return result; +} diff --git a/libc/stdio/vasprintf.cpp b/libc/stdio/vasprintf.cpp new file mode 100644 index 00000000..584fecd7 --- /dev/null +++ b/libc/stdio/vasprintf.cpp @@ -0,0 +1,80 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/vasprintf.cpp + Prints a string to a newly allocated buffer. + +*******************************************************************************/ + +#include +#include +#include +#include + +struct vasprintf_state +{ + char* string; + size_t string_length; + size_t string_used; +}; + +static size_t vasprintf_callback(void* user, const char* string, size_t length) +{ + struct vasprintf_state* state = (struct vasprintf_state*) user; + if ( !state->string ) + return 0; + size_t needed_length = state->string_used + length + 1; + if ( state->string_length < needed_length ) + { + size_t new_length = 2 * state->string_used; + if ( new_length < needed_length ) + new_length = needed_length; + size_t new_size = new_length * sizeof(char); + char* new_string = (char*) realloc(state->string, new_size); + if ( !new_string ) + { + free(state->string); + state->string = NULL; + return 0; + } + state->string = new_string; + state->string_length = new_length; + } + memcpy(state->string + state->string_used, string, sizeof(char) * length); + state->string_used += length; + return length; +} + +extern "C" +int vasprintf(char** restrict result_ptr, + const char* restrict format, + va_list list) +{ + const size_t DEFAULT_SIZE = 32; + struct vasprintf_state state; + state.string_length = DEFAULT_SIZE; + state.string_used = 0; + if ( !(state.string = (char*) malloc(state.string_length * sizeof(char))) ) + return *result_ptr = NULL, -1; + vprintf_callback(vasprintf_callback, &state, format, list); + if ( !state.string ) + return *result_ptr = NULL, -1; + state.string[state.string_used] = '\0'; + return *result_ptr = state.string, (int) state.string_used; +}