diff options
author | Mattias Andrée <maandree@operamail.com> | 2015-09-03 03:14:05 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@operamail.com> | 2015-09-03 03:14:05 +0200 |
commit | 9ab366dc44785ed7b0910df98650c8c2d1d24524 (patch) | |
tree | 573818439baf7952130958d964f8221b32e6aaab | |
parent | misc (diff) | |
download | slibc-9ab366dc44785ed7b0910df98650c8c2d1d24524.tar.gz slibc-9ab366dc44785ed7b0910df98650c8c2d1d24524.tar.bz2 slibc-9ab366dc44785ed7b0910df98650c8c2d1d24524.tar.xz |
add printf functions, not fully implemented
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to '')
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | include/slibc-print.h | 252 | ||||
-rw-r--r-- | include/slibc/features.h | 6 | ||||
-rw-r--r-- | include/stdio.h | 845 | ||||
-rw-r--r-- | src/slibc-print.c | 193 | ||||
-rw-r--r-- | src/stdio/printf.c | 1212 |
6 files changed, 2491 insertions, 20 deletions
@@ -35,7 +35,7 @@ CCFLAGS_INCLUDES = -Iinclude CCFLAGS_OPTIIMISE = -Og -g # Warning flags. -CCFLAGS_WARNINGS = -Wall -Wextra -Wdouble-promotion -Wformat=2 -Winit-self -Wmissing-include-dirs \ +CCFLAGS_WARNINGS = -Wall -Wextra -Wdouble-promotion -Wno-format -Winit-self -Wmissing-include-dirs \ -Wtrampolines -Wfloat-equal -Wshadow -Wmissing-prototypes -Wmissing-declarations \ -Wredundant-decls -Wnested-externs -Winline -Wno-variadic-macros -Wsign-conversion \ -Wswitch-default -Wconversion -Wsync-nand -Wunsafe-loop-optimizations -Wcast-align \ @@ -45,6 +45,7 @@ CCFLAGS_WARNINGS = -Wall -Wextra -Wdouble-promotion -Wformat=2 -Winit-self -Wmis -Wunsuffixed-float-constants -Wsuggest-attribute=const -Wsuggest-attribute=noreturn \ -Wsuggest-attribute=pure -Wsuggest-attribute=format -Wnormalized=nfkc # -pedantic is excluded. +# -Wno-format is temporarily substituted for -Wformat=1 # All flags used required when compiling the library. diff --git a/include/slibc-print.h b/include/slibc-print.h new file mode 100644 index 0000000..b992537 --- /dev/null +++ b/include/slibc-print.h @@ -0,0 +1,252 @@ +/** + * 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/>. + */ +#ifndef _SLIBC_PRINT_H +#define _SLIBC_PRINT_H +#include <slibc/version.h> +#include <slibc/features.h> +#ifndef __PORTABLE + + + +/** + * `NULL`'s canonical header is <stddef.h> + */ +#ifndef NULL +# define NULL ((void*)0) +#endif + + +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_wchar_t +#define __NEED_intmax_t +#define __NEED_va_list +#include <bits/types.h> + + + +/** + * Structure used by extensions to `generic_printf`-function + * to request that additionally arguments be added before the + * function is called again. + */ +struct generic_printf_ext_queue +{ + /** + * Sizes, in bytes, of the missing arguments. + * Only 1, 2, 4 and 8 are allowed. + */ + char sizes[4]; + + /** + * The indices of the missing arguments. + */ + size_t indices[4]; + + /** + * The amount of missing arguments. + * `sizes` and `indices` can only hold up to + * 4 arguments, the function will be later + * again to retrieve information about the + * omitted arguments. To avoid a deadlock, + * add arguments in the order of their index + * if there are more than 4 missing arguments. + */ + size_t count; +}; + + +/** + * Function-type used by `generic_printf` and `vgeneric_wprintf` + * to write a string. + * + * @param text The text segment to print, it will only contain + * a NUL byte if that NUL byte shall be printed. + * @param length The length of `text`. + * @param data The value passed to `generic_printf` or + * `vgeneric_wprintf` via the parameter `data`. + * @return Zero on success, -1 on error. `errno` shall + * be set on error. + */ +typedef int (* generic_printf_write_func_t)(const char*, size_t, void*); + +/** + * Variant of `generic_printf_write_func_t` used for + * `generic_wprintf` and `vgeneric_wprintf`. + */ +typedef int (* generic_wprintf_write_func_t)(const wchar_t*, size_t, void*); + +/** + * Function-type used by `generic_printf` and `vgeneric_wprintf` + * to write a string if a custom formatting code was encountered. + * + * @param code The %-code, excluding the %. + * @param args Formatting arguments cased to `intmax`. + * @param argn The number of formatting arguments in `args`. + * @param silent Non-zero if the function must not perform a write. + * @param data The value passed to `generic_printf` or + * `vgeneric_wprintf` via the parameter `data`. + * @param queue_data Used to send information to the calling function + * about missing arguments. + * @return The number of written characters, -1 on error. + * `errno` shall be set on error. -2 shall be returned + * if argument index equal to or greater than the + * value of `argn`, if `queue_data` must be set. + * + * @throws EINVAL If `code` could not be recognised. + */ +typedef ssize_t (* generic_printf_ext_func_t)(const char*, intmax_t*, size_t, int, void*, + struct generic_printf_ext_queue*); + +/** + * Variant of `generic_printf_ext_func_t` used for + * `generic_wprintf` and `vgeneric_wprintf`. + */ +typedef ssize_t (* generic_wprintf_ext_func_t)(const wchar_t*, intmax_t*, size_t, int, void*, + struct generic_printf_ext_queue*); + + +/** + * An almost fully generic `printf`-function. + * + * @param write_function Function used to write the string. `NULL` if + * it shall not be printed but only measured. + * @param extension_function Function used to extend the functions formatting codes. + * `NULL` if not extensions are to be used. + * @param maximum_length The maximum amount of bytes to write, including the + * NUL byte, ignored if `limited_length` is zero. + * @param limited_length Whether `maximum_length` shall be used. + * @param actual_length Output parameter for the length of the printed string, + * this includes any text that was truncated but not the + * NUL character. Must not be `NULL`. + * @param terminate Whether a NUL character shall be printed at the end. + * @param data Data to pass to `write_function` and + * `extension_function`, it should contain + * the print-sink, and any state data neccessary + * since the functions may be called multiple times. + * @param format The formatting-string, see `fprintf` for details. + * @param ... The formatting-arguments. + * @return Zero on success, -1 on error. On error, `errno` + * is set to indicate the error. + * + * @throws Any error thrown by `write_function` or `extension_function`. + * @throws EINVAL `format` contained unsupported formatting codes. + */ +int generic_printf(generic_printf_write_func_t, generic_printf_ext_func_t, + size_t, int, size_t* restrict, int, void*, const char*, ...) + __GCC_ONLY(__attribute__((nonnull(5, 8), format(slibc_printf, 8, 9), warn_unused_result))); + +/** + * Variant of `generic_printf` that uses `va_list` + * instead of variadic arguments. + * + * @param write_function Function used to write the string. `NULL` if + * it shall not be printed but only measured. + * @param extension_function Function used to extend the functions formatting codes. + * `NULL` if not extensions are to be used. + * @param maximum_length The maximum amount of bytes to write, including the + * NUL byte, ignored if `limited_length` is zero. + * @param limited_length Whether `maximum_length` shall be used. + * @param actual_length Output parameter for the length of the printed string, + * this includes any text that was truncated but not the + * NUL character. Must not be `NULL`. + * @param terminate Whether a NUL character shall be printed at the end. + * @param data Data to pass to `write_function` and + * `extension_function`, it should contain + * the print-sink, and any state data neccessary + * since the functions may be called multiple times. + * @param format The formatting-string, see `fprintf` for details. + * @param args The formatting-arguments. + * @return Zero on success, -1 on error. On error, `errno` + * is set to indicate the error. + * + * @throws Any error thrown by `write_function` or `extension_function`. + * @throws EINVAL `format` contained unsupported formatting codes. + */ +int vgeneric_printf(generic_printf_write_func_t, generic_printf_ext_func_t, + size_t, int, size_t* restrict, int, void*, const char*, va_list) + __GCC_ONLY(__attribute__((nonnull(5, 8), warn_unused_result))); + +/** + * Variant of `generic_printf` uses `wchar_t` instead of `char`; + * + * @param write_function Function used to write the string. `NULL` if + * it shall not be printed but only measured. + * @param extension_function Function used to extend the functions formatting codes. + * `NULL` if not extensions are to be used. + * @param maximum_length The maximum amount of wide characters to write, + * including the NUL wide character, ignored if + * `limited_length` is zero. + * @param limited_length Whether `maximum_length` shall be used. + * @param actual_length Output parameter for the length of the printed string, + * this includes any text that was truncated but not the + * NUL character. Must not be `NULL`. + * @param terminate Whether a NUL character shall be printed at the end. + * @param data Data to pass to `write_function` and + * `extension_function`, it should contain + * the print-sink, and any state data neccessary + * since the functions may be called multiple times. + * @param format The formatting-string, see `fprintf` for details. + * @param ... The formatting-arguments. + * @return Zero on success, -1 on error. On error, `errno` + * is set to indicate the error. + * + * @throws Any error thrown by `write_function` or `extension_function`. + * @throws EINVAL `format` contained unsupported formatting codes. + */ +int generic_wprintf(generic_wprintf_write_func_t, generic_wprintf_ext_func_t, + size_t, int, size_t* restrict, int, void*, const wchar_t*, ...) + __GCC_ONLY(__attribute__((nonnull(5, 8), warn_unused_result))); + +/** + * Variant of `generic_wprintf` that uses `va_list` + * instead of variadic arguments. + * + * @param write_function Function used to write the string. `NULL` if + * it shall not be printed but only measured. + * @param extension_function Function used to extend the functions formatting codes. + * `NULL` if not extensions are to be used. + * @param maximum_length The maximum amount of wide characters to write, + * including the NUL wide character, ignored if + * `limited_length` is zero. + * @param limited_length Whether `maximum_length` shall be used. + * @param actual_length Output parameter for the length of the printed string, + * this includes any text that was truncated but not the + * NUL character. Must not be `NULL`. + * @param terminate Whether a NUL character shall be printed at the end. + * @param data Data to pass to `write_function` and + * `extension_function`, it should contain + * the print-sink, and any state data neccessary + * since the functions may be called multiple times. + * @param format The formatting-string, see `fprintf` for details. + * @param ... The formatting-arguments. + * @return Zero on success, -1 on error. On error, `errno` + * is set to indicate the error. + * + * @throws Any error thrown by `write_function` or `extension_function`. + * @throws EINVAL `format` contained unsupported formatting codes. + */ +int vgeneric_wprintf(generic_wprintf_write_func_t, generic_wprintf_ext_func_t, + size_t, int, size_t* restrict, int, void*, const wchar_t*, va_list) + __GCC_ONLY(__attribute__((nonnull(5, 8), warn_unused_result))); + + + +#endif +#endif + diff --git a/include/slibc/features.h b/include/slibc/features.h index 7363215..c5a1e1b 100644 --- a/include/slibc/features.h +++ b/include/slibc/features.h @@ -110,6 +110,12 @@ #endif +/** + * Format for the `format` GCC function attribute. + */ +#define slibc_printf printf /* TODO write GCC extension */ + + #endif diff --git a/include/stdio.h b/include/stdio.h index d23339d..598c6ef 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -26,35 +26,842 @@ #define __NEED_off_t #define __NEED_size_t #define __NEED_ssize_t +#define __NEED_wchar_t #define __NEED_va_list #if __STDC_VERSION__ >= 201112L # define __NEED_max_align_t #endif +#define FILE void /* TODO temporary */ #include <bits/types.h> /* TODO implement I/O */ -int fflush(void*); -#define stdin NULL -#define stdout NULL -#define stderr NULL -int printf(const char*, ...); -int fprintf(void*, const char*, ...); -int dprintf(int, const char*, ...); -int sprintf(char*, const char*, ...); -int snprintf(char*, size_t, const char*, ...); -#if (defined(_GNU_SOURCE) || defined(_SLIBC_SOURCE)) && !defined(__PORTABLE) -int asprintf(char**, const char*, ...); -#endif -int vprintf(const char*, va_list); -int vfprintf(void*, const char*, va_list); -int vdprintf(int, const char*, va_list); -int vsprintf(char*, const char*, va_list); -int vsnprintf(char*, size_t, const char*, va_list); -#if (defined(_GNU_SOURCE) || defined(_SLIBC_SOURCE)) && !defined(__PORTABLE) -int vasprintf(char**, const char*, va_list); +int fflush(FILE*); +#define stdin ((void*)1) /* TODO temporary */ +#define stdout ((void*)2) /* TODO temporary */ +#define stderr ((void*)3) /* TODO temporary */ + + +/** + * 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, ...) + __GCC_ONLY(__attribute__((nonnull(1), format(slibc_printf, 1, 2)))); + +/** + * 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, const char* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(1, 2), format(slibc_printf, 2, 3)))); + +#if defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, const char* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(1, 2), format(slibc_printf, 2, 3)))); +#endif + +/** + * 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, const char* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(2), format(slibc_printf, 2, 3)))); + +/** + * 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, const char* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(1, 2), format(slibc_printf, 2, 3)))); + +/** + * 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, size_t, const char* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(3), format(slibc_printf, 3, 4)))); + +#if defined(_GNU_SOURCE) && !defined(__PORTABLE) +/** + * 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, const char* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(1, 2), format(slibc_printf, 2, 3), warn_unused_result))); +#endif + +#if defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, size_t* restrict, size_t, int, const char* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(1, 2, 5), format(slibc_printf, 5, 6), warn_unused_result))); +#endif + + +/** + * 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, va_list) + __GCC_ONLY(__attribute__((nonnull(1)))); + +/** + * 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, const char* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 2)))); + +#if defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, const char* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 2)))); +#endif + +/** + * 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, const char* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(2)))); + +/** + * 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, const char* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 2)))); + +/** + * 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, size_t, const char* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 3)))); + +#if defined(_GNU_SOURCE) && !defined(__PORTABLE) +/** + * 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, const char* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 2), warn_unused_result))); +#endif + +#if defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, size_t* restrict, size_t, int, const char* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 2, 5), warn_unused_result))); +#endif + + +#if !defined(__PORTABLE) /* wchar_t is not portable. */ +/** + * 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, ...) + __GCC_ONLY(__attribute__((nonnull(1)))); + +/** + * 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, const wchar_t* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(1, 2)))); + +# if defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, const wchar_t* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(1, 2)))); + +/** + * 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, const wchar_t* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(2)))); +# endif + +/** + * 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, size_t, const wchar_t* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(3)))); + +# if defined(_GNU_SOURCE) && defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, const wchar_t* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(1, 2), warn_unused_result))); +# endif + +# if defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, size_t* restrict, size_t, int, const wchar_t* restrict, ...) + __GCC_ONLY(__attribute__((nonnull(1, 2, 5), warn_unused_result))); +# endif + + +/** + * 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, va_list) + __GCC_ONLY(__attribute__((nonnull(1)))); + +/** + * 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, const wchar_t* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 2)))); + +# if defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, const wchar_t* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 2)))); + +/** + * 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, const wchar_t* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(2)))); +# endif + +/** + * 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, size_t, const wchar_t* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(3)))); + +# if defined(_GNU_SOURCE) && defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, const wchar_t* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 2), warn_unused_result))); +# endif + +# if defined(_SLIBC_SOURCE) && !defined(__PORTABLE) +/** + * 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, size_t* restrict, size_t, int, const wchar_t* restrict, va_list) + __GCC_ONLY(__attribute__((nonnull(1, 2, 5), warn_unused_result))); +# endif #endif diff --git a/src/slibc-print.c b/src/slibc-print.c new file mode 100644 index 0000000..f1ed817 --- /dev/null +++ b/src/slibc-print.c @@ -0,0 +1,193 @@ +/** + * 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 <slibc-print.h> +#include <stdarg.h> + + + +/** + * An almost fully generic `printf`-function. + * + * @param write_function Function used to write the string. `NULL` if + * it shall not be printed but only measured. + * @param extension_function Function used to extend the functions formatting codes. + * `NULL` if not extensions are to be used. + * @param maximum_length The maximum amount of bytes to write, including the + * NUL byte, ignored if `limited_length` is zero. + * @param limited_length Whether `maximum_length` shall be used. + * @param actual_length Output parameter for the length of the printed string, + * this includes any text that was truncated but not the + * NUL character. Must not be `NULL`. + * @param terminate Whether a NUL character shall be printed at the end. + * @param data Data to pass to `write_function` and + * `extension_function`, it should contain + * the print-sink, and any state data neccessary + * since the functions may be called multiple times. + * @param format The formatting-string, see `fprintf` for details. + * @param ... The formatting-arguments. + * @return Zero on success, -1 on error. On error, `errno` + * is set to indicate the error. + * + * @throws Any error thrown by `write_function` or `extension_function`. + * @throws EINVAL `format` contained unsupported formatting codes. + */ +int generic_printf(generic_printf_write_func_t write_function, generic_printf_ext_func_t extension_function, + size_t maximum_length, int limited_length, size_t* restrict actual_length, int terminate, + void* data, const char* format, ...) +{ + int r; + va_list args; + va_start(args, format); + r = vgeneric_printf(write_function, extension_function, maximum_length, + limited_length, actual_length, terminate, data, format, args); + va_end(args); + return r; +} + + +/** + * Variant of `generic_printf` that uses `va_list` + * instead of variadic arguments. + * + * @param write_function Function used to write the string. `NULL` if + * it shall not be printed but only measured. + * @param extension_function Function used to extend the functions formatting codes. + * `NULL` if not extensions are to be used. + * @param maximum_length The maximum amount of bytes to write, including the + * NUL byte, ignored if `limited_length` is zero. + * @param limited_length Whether `maximum_length` shall be used. + * @param actual_length Output parameter for the length of the printed string, + * this includes any text that was truncated but not the + * NUL character. Must not be `NULL`. + * @param terminate Whether a NUL character shall be printed at the end. + * @param data Data to pass to `write_function` and + * `extension_function`, it should contain + * the print-sink, and any state data neccessary + * since the functions may be called multiple times. + * @param format The formatting-string, see `fprintf` for details. + * @param args The formatting-arguments. + * @return Zero on success, -1 on error. On error, `errno` + * is set to indicate the error. + * + * @throws Any error thrown by `write_function` or `extension_function`. + * @throws EINVAL `format` contained unsupported formatting codes. + */ +int vgeneric_printf(generic_printf_write_func_t write_function, generic_printf_ext_func_t extension_function, + size_t maximum_length, int limited_length, size_t* restrict actual_length, int terminate, + void* data, const char* format, va_list args) +{ + /* TODO vgeneric_printf */ + return 0; + (void) write_function; + (void) extension_function; + (void) maximum_length; + (void) limited_length; + (void) actual_length; + (void) terminate; + (void) data; + (void) format; + (void) args; +} + + +/** + * Variant of `generic_printf` uses `wchar_t` instead of `char`; + * + * @param write_function Function used to write the string. `NULL` if + * it shall not be printed but only measured. + * @param extension_function Function used to extend the functions formatting codes. + * `NULL` if not extensions are to be used. + * @param maximum_length The maximum amount of wide characters to write, + * including the NUL wide character, ignored if + * `limited_length` is zero. + * @param limited_length Whether `maximum_length` shall be used. + * @param actual_length Output parameter for the length of the printed string, + * this includes any text that was truncated but not the + * NUL character. Must not be `NULL`. + * @param terminate Whether a NUL character shall be printed at the end. + * @param data Data to pass to `write_function` and + * `extension_function`, it should contain + * the print-sink, and any state data neccessary + * since the functions may be called multiple times. + * @param format The formatting-string, see `fprintf` for details. + * @param ... The formatting-arguments. + * @return Zero on success, -1 on error. On error, `errno` + * is set to indicate the error. + * + * @throws Any error thrown by `write_function` or `extension_function`. + * @throws EINVAL `format` contained unsupported formatting codes. + */ +int generic_wprintf(generic_wprintf_write_func_t write_function, generic_wprintf_ext_func_t extension_function, + size_t maximum_length, int limited_length, size_t* restrict actual_length, int terminate, + void* data, const wchar_t* format, ...) +{ + int r; + va_list args; + va_start(args, format); + r = vgeneric_wprintf(write_function, extension_function, maximum_length, + limited_length, actual_length, terminate, data, format, args); + va_end(args); + return r; +} + + +/** + * Variant of `generic_wprintf` that uses `va_list` + * instead of variadic arguments. + * + * @param write_function Function used to write the string. `NULL` if + * it shall not be printed but only measured. + * @param extension_function Function used to extend the functions formatting codes. + * `NULL` if not extensions are to be used. + * @param maximum_length The maximum amount of wide characters to write, + * including the NUL wide character, ignored if + * `limited_length` is zero. + * @param limited_length Whether `maximum_length` shall be used. + * @param actual_length Output parameter for the length of the printed string, + * this includes any text that was truncated but not the + * NUL character. Must not be `NULL`. + * @param terminate Whether a NUL character shall be printed at the end. + * @param data Data to pass to `write_function` and + * `extension_function`, it should contain + * the print-sink, and any state data neccessary + * since the functions may be called multiple times. + * @param format The formatting-string, see `fprintf` for details. + * @param ... The formatting-arguments. + * @return Zero on success, -1 on error. On error, `errno` + * is set to indicate the error. + * + * @throws Any error thrown by `write_function` or `extension_function`. + * @throws EINVAL `format` contained unsupported formatting codes. + */ +int vgeneric_wprintf(generic_wprintf_write_func_t write_function, generic_wprintf_ext_func_t extension_function, + size_t maximum_length, int limited_length, size_t* restrict actual_length, int terminate, + void* data, const wchar_t* format, va_list args) +{ + /* TODO vgeneric_wprintf */ + return 0; + (void) write_function; + (void) extension_function; + (void) maximum_length; + (void) limited_length; + (void) actual_length; + (void) terminate; + (void) data; + (void) format; + (void) args; +} + 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); +} + |