/** * 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 . */ #include #include #include #include #include #include #include #include #include #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; /** * Pointer to the size of the buffer, in number of elements. */ size_t* size; /** * The write offset. */ size_t off; /** * Whether `EXTALLOC_CLEAR`, `secure_realloc`, * or `secure_free` 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 file. * * @param text The text to write, not NUL terminated. * @param length The length of `text`. * @param input Element 0: pointer to the file descriptor of the file. * Element 1: flags for `send`. * @return Zero on success, -1 on error. * * @throws Any error specified for `write`. */ static int send_fd(const char* text, size_t length, int* input) { int fd = input[0], flags = input[1]; /* TODO send_fd */ return 0; (void) text, (void) length, (void) fd, (void) flags; } /** * Write a string segment to a file. * * @param text The text to write, not NUL terminated. * @param length The length of `text`. * @param input Element 0: pointer to the file descriptor of the file. * Element 1: flags for `send`. * @return Zero on success, -1 on error. * * @throws Any error specified for `write`. */ static int wsend_fd(const wchar_t* text, size_t length, int* input) { int fd = input[0], flags = input[1]; /* TODO wsend_fd */ return 0; (void) text, (void) length, (void) fd, (void) flags; } /** * 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 wwrite_stream(const wchar_t* text, size_t length, FILE* stream) { /* TODO wwrite_stream */ 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) { enum extalloc_mode flags = EXTALLOC_MALLOC | (buffer->secure ? EXTALLOC_CLEAR : 0); char* new; if (buffer->off + length > *(buffer->size)) { if (buffer->off || !*(buffer->size)) new = (buffer->secure ? secure_realloc : fast_realloc) (buffer->buf.str, *(buffer->size) * sizeof(char)); else new = extalloc(buffer->buf.str, *(buffer->size) * sizeof(char), flags); 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) { enum extalloc_mode flags = EXTALLOC_MALLOC | (buffer->secure ? EXTALLOC_CLEAR : 0); wchar_t* new; if (buffer->off + length > *(buffer->size)) { if (buffer->off || !*(buffer->size)) new = (buffer->secure ? secure_realloc : fast_realloc) (buffer->buf.wcs, *(buffer->size) * sizeof(wchar_t)); else new = extalloc(buffer->buf.wcs, *(buffer->size) * sizeof(wchar_t), flags); 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 `dprintf`, * except it uses `send` instead of `write` * and supports transmissions flags. * * This is a slibc extension added for completeness. * * @param fd The file descriptor. * @param flags Flags to pass to `send`, see `send` * for more information. * @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 sockprintf(int fd, int flags, const char* format restrict, ...) { V(sockprintf(fd, flags, format, args)); } /** * This function is identical to `fprintf`, * it prints to a buffer rather than a stream. * * This is identical to `snprintf` 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 `dprintf`, * 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 `sockprintf`, * except it uses `va_list` instead of variadic argument. * * This is a slibc extension added for completeness. * * @param fd The file descriptor. * @param flags Flags to pass to `send`, see `send` * for more information. * @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 vsockprintf(int fd, int flags, const char* restrict format, va_list args) { int input[] = {fd, flags}; P_CHAR(send_fd, 0, 0, 0, input); } /** * 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 `sockprintf` * except it uses wide characters. * * This is a slibc extension added for completeness. * * @param fd The file descriptor. * @param flags Flags to pass to `send`, see `send` * for more information. * @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 sockwprintf(int fd, int flags, const wchar_t* restrict format, ...) { V(sockwprintf(fd, flags, 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(wwrite_stream, 0, 0, 0, stream); } /** * This function is identical to `dwprintf`, * 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 `sockwprintf` * except it uses `va_list` instead of variadic argument. * * This is a slibc extension added for completeness. * * @param fd The file descriptor. * @param flags Flags to pass to `send`, see `send` * for more information. * @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 vsockwprintf(int fd, int flags, const wchar_t* restrict format, va_list args) { int input[] = {fd, flags}; P_WCHAR(wsend_fd, 0, 0, 0, input); } /** * 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); }