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;
+}