aboutsummaryrefslogtreecommitdiffstats
path: root/src/stdio/printf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdio/printf.c')
-rw-r--r--src/stdio/printf.c1212
1 files changed, 1212 insertions, 0 deletions
diff --git a/src/stdio/printf.c b/src/stdio/printf.c
new file mode 100644
index 0000000..f63de94
--- /dev/null
+++ b/src/stdio/printf.c
@@ -0,0 +1,1212 @@
+/**
+ * slibc — Yet another C library
+ * Copyright © 2015 Mattias Andrée (maandree@member.fsf.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <slibc-print.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <slibc-alloc.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdio.h>
+
+
+#define INT_MAX 0x7FFFFFFF /* TODO temporary */
+
+#define V(C) \
+ int r; \
+ va_list args; \
+ va_start(args, format); \
+ r = v##C; \
+ va_end(args); \
+ return r
+
+#define P_CHAR(UNDERLAYING, MAXIMUM, LIMITED, TERMINATE, DATA) \
+ size_t length; \
+ int r = vgeneric_printf((generic_printf_write_func_t)UNDERLAYING, NULL, \
+ MAXIMUM, LIMITED, &length, TERMINATE, DATA, format, args); \
+ return r < 0 ? -1 : length < INT_MAX ? (int)length : INT_MAX
+
+#define P_WCHAR(UNDERLAYING, MAXIMUM, LIMITED, TERMINATE, DATA) \
+ size_t length; \
+ int r = vgeneric_wprintf((generic_wprintf_write_func_t)UNDERLAYING, NULL, \
+ MAXIMUM, LIMITED, &length, TERMINATE, DATA, format, args); \
+ return r < 0 ? -1 : length < INT_MAX ? (int)length : INT_MAX
+
+#define FLOCK(F) /* TODO lock stream */
+#define FUNLOCK(F) /* TODO unlock stream */
+
+
+
+/**
+ * Buffer information.
+ */
+struct buffer
+{
+ /**
+ * The buffer.
+ */
+ union
+ {
+ /**
+ * Byte-oriented buffer.
+ */
+ char* str;
+
+ /**
+ * Wide character-oriented buffer.
+ */
+ wchar_t* wcs;
+
+ } buf;
+
+ /**
+ * The size of the buffer, in number of elements.
+ */
+ size_t size;
+
+ /**
+ * The write offset.
+ */
+ size_t off;
+
+ /**
+ * Whether `secure_realloc` shall be used.
+ */
+ int secure;
+
+ /**
+ * Whether `.buf` shall be freed on error.
+ */
+ int free_on_error;
+};
+
+
+/**
+ * Write a string segment to a buffer.
+ *
+ * @param text The text to write, not NUL terminated.
+ * @param length The length of `text`.
+ * @param buffer Pointer to the output buffer, will be
+ * updated to point to the end of the write.
+ * @return Zero on success, -1 on error.
+ * This function is always successful.
+ */
+static int write_string(const char* text, size_t length, char* restrict* buffer)
+{
+ memcpy(*buffer, text, length);
+ (*buffer) += length;
+ return 0;
+}
+
+
+/**
+ * Write a string segment to a buffer.
+ *
+ * @param text The text to write, not NUL terminated.
+ * @param length The length of `text`.
+ * @param buffer Pointer to the output buffer, will be
+ * updated to point to the end of the write.
+ * @return Zero on success, -1 on error.
+ * This function is always successful.
+ */
+static int wwrite_string(const wchar_t* text, size_t length, wchar_t* restrict* buffer)
+{
+ wmemcpy(*buffer, text, length);
+ (*buffer) += length;
+ return 0;
+}
+
+
+/**
+ * Write a string segment to a file.
+ *
+ * @param text The text to write, not NUL terminated.
+ * @param length The length of `text`.
+ * @param fdp Pointer to the file descriptor of the file.
+ * @return Zero on success, -1 on error.
+ *
+ * @throws Any error specified for `write`.
+ */
+static int write_fd(const char* text, size_t length, int* fdp)
+{
+ /* TODO write_fd */
+ /*
+ ssize_t wrote;
+ size_t ptr = 0;
+ while (ptr < length)
+ {
+ wrote = write(*fdp, text + ptr, length - ptr);
+ if (wrote < 0)
+ return -1;
+ ptr += (size_t)wrote;
+ }
+ return 0;
+ */
+ return 0;
+ (void) text, (void) length, (void) fdp;
+}
+
+
+/**
+ * Write a string segment to a file.
+ *
+ * @param text The text to write, not NUL terminated.
+ * @param length The length of `text`.
+ * @param fdp Pointer to the file descriptor of the file.
+ * @return Zero on success, -1 on error.
+ *
+ * @throws Any error specified for `write`.
+ */
+static int wwrite_fd(const wchar_t* text, size_t length, int* fdp)
+{
+ /* TODO wwrite_fd */
+ return 0;
+ (void) text, (void) length, (void) fdp;
+}
+
+
+/**
+ * Write a string segment to a stream.
+ *
+ * @param text The text to write, not NUL terminated.
+ * @param length The length of `text`.
+ * @param stream The output stream.
+ * @return Zero on success, -1 on error.
+ *
+ * @throws Any error specified for `fwrite_unlocked`.
+ */
+static int write_stream(const char* text, size_t length, FILE* stream)
+{
+ /* TODO write_stream */
+ /*
+ size_t wrote = fwrite_unlocked(text, 1, length, stream);
+ return wrote == length ? 0 : -1;
+ */
+ return 0;
+ (void) text, (void) length, (void) stream;
+}
+
+
+/**
+ * Write a string segment to a stream.
+ *
+ * @param text The text to write, not NUL terminated.
+ * @param length The length of `text`.
+ * @param stream The output stream.
+ * @return Zero on success, -1 on error.
+ *
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ *
+ * @throws Any error specified for `fwrite_unlocked`.
+ */
+static int write_wstream(const wchar_t* text, size_t length, FILE* stream)
+{
+ /* TODO write_wstream */
+ return 0;
+ (void) text, (void) length, (void) stream;
+}
+
+
+/**
+ * Write a string segment to a buffer and reallocate it necessary.
+ *
+ * @param text The text to write, not NUL terminated.
+ * @param length The length of `text`.
+ * @param buffer Information about the buffer.
+ * @return Zero on success, -1 on error.
+ *
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ */
+static int write_buffer(const char* text, size_t length, struct buffer* buffer)
+{
+ char* new;
+ if (buffer->off + length > buffer->size)
+ {
+ new = (buffer->secure ? secure_realloc : fast_realloc)
+ (buffer->buf.str, buffer->size * sizeof(char));
+ if (new == NULL)
+ {
+ if (buffer->free_on_error)
+ (buffer->secure ? secure_free : fast_free)(buffer->buf.str),
+ buffer->buf.str = NULL;
+ return -1;
+ }
+ buffer->size = buffer->off + length;
+ buffer->buf.str = new;
+ }
+ memcpy(buffer->buf.str, text, length);
+ buffer->off += length;
+ return 0;
+}
+
+
+/**
+ * Write a string segment to a buffer and reallocate it necessary.
+ *
+ * @param text The text to write, not NUL terminated.
+ * @param length The length of `text`.
+ * @param buffer Information about the buffer.
+ * @return Zero on success, -1 on error.
+ */
+static int wwrite_buffer(const wchar_t* text, size_t length, struct buffer* buffer)
+{
+ wchar_t* new;
+ if (buffer->off + length > buffer->size)
+ {
+ new = (buffer->secure ? secure_realloc : fast_realloc)
+ (buffer->buf.wcs, buffer->size * sizeof(wchar_t));
+ if (new == NULL)
+ {
+ if (buffer->free_on_error)
+ (buffer->secure ? secure_free : fast_free)(buffer->buf.wcs),
+ buffer->buf.wcs = NULL;
+ return -1;
+ }
+ buffer->size = buffer->off + length;
+ buffer->buf.wcs = new;
+ }
+ wmemcpy(buffer->buf.wcs, text, length);
+ buffer->off += length;
+ return 0;
+}
+
+
+
+/**
+ * This function is identical to `fprintf` with
+ * `stdout` as the first argument.
+ *
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written bytes.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` bytes are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite`.
+ */
+int printf(const char* restrict format, ...)
+{
+ V(printf(format, args));
+}
+
+
+/**
+ * Print a formatted string to a stream.
+ *
+ * TODO list format rules for fprintf
+ *
+ * @param stream The output stream.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written bytes.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` bytes are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite`.
+ */
+int fprintf(FILE* restrict stream, const char* restrict format, ...)
+{
+ V(fprintf(stream, format, args));
+}
+
+
+/**
+ * This function is identical to `fprintf`,
+ * except it does not lock the stream.
+ *
+ * This is a slibc extension.
+ *
+ * @param stream The output stream.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written bytes.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` bytes are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite_unlocked`.
+ */
+int fprintf_unlocked(FILE* restrict stream, const char* restrict format, ...)
+{
+ V(fprintf_unlocked(stream, format, args));
+}
+
+
+/**
+ * This function is identical to `fprintf`,
+ * except it is limited to file descriptor-backed
+ * streams, and uses the file descriptor as the
+ * first argument rather than the stream.
+ *
+ * @param fd The file descriptor.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written bytes.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` bytes are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `write`.
+ */
+int dprintf(int fd, const char* restrict format, ...)
+{
+ V(dprintf(fd, format, args));
+}
+
+
+/**
+ * This function is identical to `fprintf`,
+ * except it is limited to buffer-backed
+ * streams, and uses the buffer as the first
+ * argument rather than then the stream.
+ *
+ * This is identical to `sprintf` with
+ * `SIZE_MAX` as the second argument.
+ *
+ * @param buffer The output buffer.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written bytes, excluding
+ * the NUL byte. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * bytes are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ */
+int sprintf(char* restrict buffer, const char* restrict format, ...)
+{
+ V(sprintf(buffer, format, args));
+}
+
+
+/**
+ * This function is identical to `sprintf`,
+ * expect it truncates the output.
+ *
+ * @param buffer The output buffer.
+ * @param size The allocation size of `buffer`.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written bytes, excluding
+ * the NUL byte, that would have been written
+ * if `size` was ignored. On error, a negative
+ * value (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * bytes would have been written; in slibc,
+ * `INT_MAX` is returned if more would have
+ * been written, you can use "%zn" to find the
+ * actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ */
+int snprintf(char* restrict buffer, size_t size, const char* restrict format, ...)
+{
+ V(snprintf(buffer, size, format, args));
+}
+
+
+/**
+ * This function is identical to `sprintf`,
+ * except it allocates a sufficiently large
+ * buffer.
+ *
+ * This is a GNU extension.
+ *
+ * @param buffer Output parameter for the output buffer.
+ * On error the content of this pointer is undefined.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written bytes, excluding
+ * the NUL byte. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * bytes are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ */
+int asprintf(char** restrict buffer, const char* restrict format, ...)
+{
+ V(asprintf(buffer, format, args));
+}
+
+
+/**
+ * This function is identical to `asprintf`,
+ * except it can reuse allocated buffers.
+ *
+ * This is a slibc extension.
+ *
+ * @param buffer Reference parameter for the output buffer.
+ * It should point to the buffer than shall
+ * be used, or point to `NULL` if a new buffer
+ * shall be allocated. It will be updated with
+ * a new buffer if it points to `NULL`, or the
+ * new pointer if `buffer` needed to be reallocated.
+ * On error, this pointer will only have been
+ * updated if the buffer was reallocated during
+ * the call; if it pointed to `NULL`, it will
+ * still point to `NULL`.
+ * @param size Reference parameter for the buffer size.
+ * It shall point to a variable whose value is
+ * the allocation size of `*buffer`, or point to
+ * a variable whose value is zero if `*buffer`
+ * is `NULL`
+ * @param offset The offset in the buffer where the function
+ * shall start the printing.
+ * @param secure Non-zero if the function must override the
+ * buffer with zero before freeing it if it
+ * creates a new allocation.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written bytes, excluding
+ * the NUL byte. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * bytes are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ */
+int bprintf(char** restrict buffer, size_t* restrict size, size_t offset,
+ int secure, const char* restrict format, ...)
+{
+ V(bprintf(buffer, size, offset, secure, format, args));
+}
+
+
+/**
+ * This function is identical to `printf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written bytes.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` bytes are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite`.
+ */
+int vprintf(const char* restrict format, va_list args)
+{
+ return vfprintf(stdout, format, args);
+}
+
+
+/**
+ * This function is identical to `fprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * @param stream The output stream.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written bytes.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` bytes are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite`.
+ */
+int vfprintf(FILE* restrict stream, const char* restrict format, va_list args)
+{
+ int r, saved_errno;
+ FLOCK(stream);
+ r = vfprintf_unlocked(stream, format, args);
+ saved_errno = errno;
+ FUNLOCK(stream);
+ return errno = saved_errno, r;
+}
+
+
+/**
+ * This function is identical to `fprintf_unlocked`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * This is a slibc extension.
+ *
+ * @param stream The output stream.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written bytes.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` bytes are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite_unlocked`.
+ */
+int vfprintf_unlocked(FILE* restrict stream, const char* restrict format, va_list args)
+{
+ P_CHAR(write_stream, 0, 0, 0, stream);
+}
+
+
+/**
+ * This function is identical to `vdprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * @param fd The file descriptor.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written bytes.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` bytes are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `write`.
+ */
+int vdprintf(int fd, const char* restrict format, va_list args)
+{
+ P_CHAR(write_fd, 0, 0, 0, &fd);
+}
+
+
+/**
+ * This function is identical to `sprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * @param buffer The output buffer.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written bytes, excluding
+ * the NUL byte. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * bytes are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ */
+int vsprintf(char* restrict buffer, const char* restrict format, va_list args)
+{
+ char* buf = buffer;
+ P_CHAR(write_string, 0, 0, 1, &buf);
+}
+
+
+/**
+ * This function is identical to `snprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * @param buffer The output buffer.
+ * @param size The allocation size of `buffer`.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written bytes, excluding
+ * the NUL byte, that would have been written
+ * if `size` was ignored. On error, a negative
+ * value (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * bytes would have been written; in slibc,
+ * `INT_MAX` is returned if more would have
+ * been written, you can use "%zn" to find the
+ * actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ */
+int vsnprintf(char* restrict buffer, size_t size, const char* restrict format, va_list args)
+{
+ char* buf = buffer;
+ P_CHAR(write_string, size, 1, 1, &buf);
+}
+
+
+/**
+ * This function is identical to `asprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * This is a GNU extension.
+ *
+ * @param buffer Output parameter for the output buffer.
+ * On error the content of this pointer is undefined.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written bytes, excluding
+ * the NUL byte. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * bytes are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ */
+int vasprintf(char** restrict buffer, const char* restrict format, va_list args)
+{
+ char* buf = NULL;
+ size_t _size = 0;
+ int r = vbprintf(&buf, &_size, 0, 0, format, args);
+ return r ? r : (*buffer = buf, 0);
+}
+
+
+/**
+ * This function is identical to `bprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * This is a slibc extension.
+ *
+ * @param buffer Reference parameter for the output buffer.
+ * It should point to the buffer than shall
+ * be used, or point to `NULL` if a new buffer
+ * shall be allocated. It will be updated with
+ * a new buffer if it points to `NULL`, or the
+ * new pointer if `buffer` needed to be reallocated.
+ * On error, this pointer will only have been
+ * updated if the buffer was reallocated during
+ * the call; if it pointed to `NULL`, it will
+ * still point to `NULL`.
+ * @param size Reference parameter for the buffer size.
+ * It shall point to a variable whose value is
+ * the allocation size of `*buffer`, or point to
+ * a variable whose value is zero if `*buffer`
+ * is `NULL`
+ * @param offset The offset in the buffer where the function
+ * shall start the printing.
+ * @param secure Non-zero if the function must override the
+ * buffer with zero before freeing it if it
+ * creates a new allocation.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written bytes, excluding
+ * the NUL byte. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * bytes are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ */
+int vbprintf(char** restrict buffer, size_t* restrict size, size_t offset,
+ int secure, const char* restrict format, va_list args)
+{
+ struct buffer buf =
+ {
+ .buf.str = *buffer,
+ .size = *size,
+ .off = offset,
+ .secure = secure,
+ .free_on_error = buffer == NULL,
+ };
+ P_CHAR(write_buffer, 0, 0, 1, &buf);
+}
+
+
+/**
+ * This function is identical to `printf` except
+ * it uses wide characters.
+ *
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written characters.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` characters are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite`.
+ */
+int wprintf(const wchar_t* restrict format, ...)
+{
+ V(wprintf(format, args));
+}
+
+
+/**
+ * This function is identical to `fprintf` except
+ * it uses wide characters.
+ *
+ * @param stream The output stream.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written characters.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` characters are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite`.
+ */
+int fwprintf(FILE* restrict stream, const wchar_t* restrict format, ...)
+{
+ V(fwprintf(stream, format, args));
+}
+
+
+/**
+ * This function is identical to `fprintf_unlocked` except
+ * it uses wide characters.
+ *
+ * This is a slibc extension added for completeness.
+ *
+ * @param stream The output stream.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written characters.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` characters are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite_unlocked`.
+ */
+int fwprintf_unlocked(FILE* restrict stream, const wchar_t* restrict format, ...)
+{
+ V(fwprintf_unlocked(stream, format, args));
+}
+
+
+/**
+ * This function is identical to `dprintf` except
+ * it uses wide characters.
+ *
+ * This is a slibc extension added for completeness.
+ *
+ * @param fd The file descriptor.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written characters.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` characters are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `write`.
+ */
+int dwprintf(int fd, const wchar_t* restrict format, ...)
+{
+ V(dwprintf(fd, format, args));
+}
+
+
+/**
+ * This function is identical to `snprintf`
+ * (not `sprintf`) except it uses wide characters.
+ *
+ * @param buffer The output buffer.
+ * @param size The allocation size of `buffer`.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written characters, excluding
+ * the NUL character, that would have been written
+ * if `size` was ignored. On error, a negative
+ * value (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * characters would have been written; in slibc,
+ * `INT_MAX` is returned if more would have
+ * been written, you can use "%zn" to find the
+ * actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ */
+int swprintf(wchar_t* restrict buffer, size_t size, const wchar_t* restrict format, ...)
+{
+ V(swprintf(buffer, size, format, args));
+}
+
+
+/**
+ * This function is identical to `aswprintf` except
+ * it uses wide characters.
+ *
+ * This is a slibc extension added for completeness.
+ * This is only available if GNU extensions are enabled.
+ *
+ * @param buffer Output parameter for the output buffer.
+ * On error the content of this pointer is undefined.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written characters, excluding
+ * the NUL character. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * characters are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ */
+int aswprintf(wchar_t** restrict buffer, const wchar_t* restrict format, ...)
+{
+ V(aswprintf(buffer, format, args));
+}
+
+
+/**
+ * This function is identical to `bprintf` except
+ * it uses wide characters.
+ *
+ * This is a slibc extension added for completeness.
+ *
+ * @param buffer Reference parameter for the output buffer.
+ * It should point to the buffer than shall
+ * be used, or point to `NULL` if a new buffer
+ * shall be allocated. It will be updated with
+ * a new buffer if it points to `NULL`, or the
+ * new pointer if `buffer` needed to be reallocated.
+ * On error, this pointer will only have been
+ * updated if the buffer was reallocated during
+ * the call; if it pointed to `NULL`, it will
+ * still point to `NULL`.
+ * @param size Reference parameter for the buffer size,
+ * in `wchar_t`.
+ * It shall point to a variable whose value is
+ * the allocation size of `*buffer`, or point to
+ * a variable whose value is zero if `*buffer`
+ * is `NULL`
+ * @param offset The offset in the buffer where the function
+ * shall start the printing.
+ * @param secure Non-zero if the function must override the
+ * buffer with zero before freeing it if it
+ * creates a new allocation.
+ * @param format The formatting-string.
+ * @param ... The formatting-arguments.
+ * @return The number of written characters, excluding
+ * the NUL character. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * characters are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ */
+int bwprintf(wchar_t** restrict buffer, size_t* restrict size, size_t offset,
+ int secure, const wchar_t* restrict format, ...)
+{
+ V(bwprintf(buffer, size, offset, secure, format, args));
+}
+
+
+/**
+ * This function is identical to `wprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written characters.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` characters are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite`.
+ */
+int vwprintf(const wchar_t* restrict format, va_list args)
+{
+ return vfwprintf(stdout, format, args);
+}
+
+
+/**
+ * This function is identical to `fwprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * @param stream The output stream.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written characters.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` characters are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite`.
+ */
+int vfwprintf(FILE* restrict stream, const wchar_t* restrict format, va_list args)
+{
+ int r, saved_errno;
+ FLOCK(stream);
+ r = vfwprintf_unlocked(stream, format, args);
+ saved_errno = errno;
+ FUNLOCK(stream);
+ return errno = saved_errno, r;
+}
+
+
+/**
+ * This function is identical to `fwprintf_unlocked`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * This is a slibc extension added for completeness.
+ *
+ * @param stream The output stream.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written characters.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` characters are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `fwrite_unlocked`.
+ */
+int vfwprintf_unlocked(FILE* restrict stream, const wchar_t* restrict format, va_list args)
+{
+ P_WCHAR(write_wstream, 0, 0, 0, stream);
+}
+
+
+/**
+ * This function is identical to `vdprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * This is a slibc extension added for completeness.
+ *
+ * @param fd The file descriptor.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written characters.
+ * On error, a negative value (namely -1
+ * in this implementation) is returned.
+ * It is unspecified what shall happen if
+ * more than `INT_MAX` characters are written;
+ * in slibc, `INT_MAX` is returned if more
+ * is written, you can use "%zn" to find
+ * the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws Any error specified for `write`.
+ */
+int vdwprintf(int fd, const wchar_t* restrict format, va_list args)
+{
+ P_WCHAR(wwrite_fd, 0, 0, 0, &fd);
+}
+
+
+/**
+ * This function is identical to `swprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * @param buffer The output buffer.
+ * @param size The allocation size of `buffer`.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written characters, excluding
+ * the NUL character, that would have been written
+ * if `size` was ignored. On error, a negative
+ * value (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * characters would have been written; in slibc,
+ * `INT_MAX` is returned if more would have
+ * been written, you can use "%zn" to find the
+ * actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ */
+int vswprintf(wchar_t* restrict buffer, size_t size, const wchar_t* restrict format, va_list args)
+{
+ wchar_t* buf = buffer;
+ P_WCHAR(wwrite_string, size, 1, 1, &buf);
+}
+
+
+/**
+ * This function is identical to `aswprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * This is a slibc extension added for completeness.
+ * This is only available if GNU extensions are enabled.
+ *
+ * @param buffer Output parameter for the output buffer.
+ * On error the content of this pointer is undefined.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written characters, excluding
+ * the NUL character. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * characters are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ */
+int vaswprintf(wchar_t** restrict buffer, const wchar_t* restrict format, va_list args)
+{
+ wchar_t* buf = NULL;
+ size_t _size = 0;
+ int r = vbwprintf(&buf, &_size, 0, 0, format, args);
+ return r ? r : (*buffer = buf, 0);
+}
+
+
+/**
+ * This function is identical to `bwprintf`,
+ * except it uses `va_list` instead of variadic argument.
+ *
+ * This is a slibc extension added for completeness.
+ *
+ * @param buffer Reference parameter for the output buffer.
+ * It should point to the buffer than shall
+ * be used, or point to `NULL` if a new buffer
+ * shall be allocated. It will be updated with
+ * a new buffer if it points to `NULL`, or the
+ * new pointer if `buffer` needed to be reallocated.
+ * On error, this pointer will only have been
+ * updated if the buffer was reallocated during
+ * the call; if it pointed to `NULL`, it will
+ * still point to `NULL`.
+ * @param size Reference parameter for the buffer size,
+ * in `wchar_t`.
+ * It shall point to a variable whose value is
+ * the allocation size of `*buffer`, or point to
+ * a variable whose value is zero if `*buffer`
+ * is `NULL`
+ * @param offset The offset in the buffer where the function
+ * shall start the printing.
+ * @param secure Non-zero if the function must override the
+ * buffer with zero before freeing it if it
+ * creates a new allocation.
+ * @param format The formatting-string.
+ * @param args The formatting-arguments.
+ * @return The number of written characters, excluding
+ * the NUL character. On error, a negative value
+ * (namely -1 in this implementation) is
+ * returned. It is unspecified what shall
+ * happen if more than `INT_MAX` non-NUL
+ * characters are written; in slibc, `INT_MAX`
+ * is returned if more is written, you can
+ * use "%zn" to find the actual length.
+ *
+ * @throws EINVAL `format` contained unsupported formatting codes.
+ * @throws ENOMEM The process cannot allocation the
+ * sufficient amount of memory.
+ */
+int vbwprintf(wchar_t** restrict buffer, size_t* restrict size, size_t offset,
+ int secure, const wchar_t* restrict format, va_list args)
+{
+ struct buffer buf =
+ {
+ .buf.wcs = *buffer,
+ .size = *size,
+ .off = offset,
+ .secure = secure,
+ .free_on_error = buffer == NULL,
+ };
+ P_WCHAR(wwrite_buffer, 0, 0, 1, &buf);
+}
+