2017-04-03 13:07:53 +02:00
/* 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/>.
*
*/
/** printing utilities to replace the large printf from the standard library (code)
* @ file print . c
* @ author King Kévin < kingkevin @ cuvoodoo . info >
* @ date 2017
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdlib.h> // standard definitions
# include <stdbool.h> // boolean types
# include <stdarg.h> // variadic utilities
2017-12-14 10:23:31 +01:00
# include <math.h> // mathematics utilities to handle floating points
2017-04-03 13:07:53 +02:00
/* own libraries */
# include "print.h" // printing utilities
2017-12-13 13:48:29 +01:00
uint8_t print_error ;
/** add printed length to total printed length, and sets error if maximum size is exceeded
* @ param [ in , out ] length total printed length
* @ param [ in ] printed printed length
*/
static void print_printed ( size_t * length , size_t printed )
{
if ( NULL = = length ) { // check if total is provided
return ;
}
if ( * length > SIZE_MAX - printed ) { // prevent integer overflow
* length = SIZE_MAX ; // set to maximum
print_error | = PRINT_ERROR_MAX ; // set error
} else {
* length + = printed ; // save printed length
}
}
2017-04-03 13:07:53 +02:00
/** print character
* @ param [ out ] str string to print character on ( use NULL to print on user output )
* @ param [ in , out ] size size of string
* @ param [ in ] c character to be printed
* @ return number of characters printed
* */
static size_t print_char ( char * * str , size_t * size , char c )
{
size_t length = 1 ; // remember how many characters have been printed or should have been added on string (normally just one)
if ( 0 = = c ) { // don't print string termination character
length = 0 ; // remember we didn't print anything
} else if ( NULL = = str | | NULL = = * str | | NULL = = size ) { // character should not be saved on string
length = putc ( c ) ; // print on user define output
2017-12-13 13:48:29 +01:00
} else if ( * size > 1 ) { // there is enough space in the string to store the character
2017-04-03 13:07:53 +02:00
* * str = c ; // add provided character to string
* str + = 1 ; // go to next character on string
* size - = 1 ; // remember we used one character on string
2017-12-13 13:48:29 +01:00
} else { // string is reached its end
print_error | = PRINT_ERROR_TRUNCATED ; // indicate we did not save the character
2017-04-03 13:07:53 +02:00
}
return length ;
}
/** print string
* @ param [ out ] str string to print string on ( use NULL to print on user output )
* @ param [ in , out ] size size of string
* @ param [ in ] s string to be printed
* @ return number of characters printed
* */
static size_t print_string ( char * * str , size_t * size , const char * s )
{
size_t length = 0 ; // number of characters printed
while ( * s ) { // stop at end of string
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , * ( s + + ) ) ) ; // print character
2017-04-03 13:07:53 +02:00
}
return length ;
}
2017-12-14 10:23:31 +01:00
/** print unsigned integer
* @ param [ out ] str string to print unsigned integer on ( use NULL to print on user output )
2017-04-03 13:07:53 +02:00
* @ param [ in , out ] size size of string
2017-12-14 10:23:31 +01:00
* @ param [ in ] u unsigned integer to be printed
2017-04-03 13:07:53 +02:00
* @ param [ in ] padding number of 0 ' s to pad
* @ param [ in ] sign if sign should be printed
* @ return number of characters printed
* */
2017-12-13 12:30:16 +01:00
static size_t print_unsigned ( char * * str , size_t * size , uint64_t u , uint32_t padding , bool sign ) {
2017-04-03 13:07:53 +02:00
char number [ 20 ] = { 0 } ; // construct the number in reverse order (20 chars are required to store UINT64_MAX)
uint8_t digits = 0 ; // to count the number of digits
size_t length = 0 ; // number of characters printed
do {
number [ digits + + ] = ' 0 ' + ( u % 10 ) ; // store digit
u / = 10 ; // go to next digit
} while ( u > 0 ) ;
if ( sign ) { // print sign
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' + ' ) ) ; // we only have positive numbers
2017-04-03 13:07:53 +02:00
}
2017-12-13 12:30:16 +01:00
for ( uint32_t zeros = digits ; zeros < padding ; zeros + + ) { // print padding 0's
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' 0 ' ) ) ; // print 0
2017-04-03 13:07:53 +02:00
}
for ( uint8_t digit = 0 ; digit < digits ; digit + + ) { // go through all digits
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , number [ digits - digit - 1 ] ) ) ; // print digit (in reverse order)
2017-04-03 13:07:53 +02:00
}
return length ; // return number of characters printed
}
2017-12-14 10:23:31 +01:00
/** print signed integer
* @ param [ out ] str string to print signed integer on ( use NULL to print on user output )
2017-04-03 13:07:53 +02:00
* @ param [ in , out ] size size of string
2017-12-14 10:23:31 +01:00
* @ param [ in ] d signed integer to be printed
2017-04-03 13:07:53 +02:00
* @ param [ in ] padding number of 0 ' s to pad
* @ param [ in ] sign if sign should be printed
* @ return number of characters printed
* */
2017-12-13 12:30:16 +01:00
static size_t print_signed ( char * * str , size_t * size , int64_t d , uint32_t padding , bool sign ) {
2017-04-03 13:07:53 +02:00
size_t length = 0 ; // number of characters printed
if ( d < 0 ) {
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' - ' ) ) ; // print sign
print_printed ( & length , print_unsigned ( str , size , ( uint64_t ) - d , padding , false ) ) ; // print number (casting because there is one more negative value then positive value)
2017-04-03 13:07:53 +02:00
} else {
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_unsigned ( str , size , d , padding , sign ) ) ; // print number
2017-04-03 13:07:53 +02:00
}
return length ; // return number of characters printed
}
2017-12-14 10:23:31 +01:00
/** print floating number
* @ param [ out ] str string to print floating number on ( use NULL to print on user output )
* @ param [ in , out ] size size of string
* @ param [ in ] f floating number to be printed
* @ param [ in ] padding number of 0 ' s to pad
* @ param [ in ] sign if sign should be printed
* @ return number of characters printed
* */
static size_t print_float ( char * * str , size_t * size , double f , uint32_t padding , uint32_t fractional , bool sign ) {
size_t length = 0 ; // number of characters printed
if ( isnan ( f ) ) { // not a number
print_printed ( & length , print_string ( str , size , " NaN " ) ) ; // print NaN
} else if ( isinf ( f ) ) { // infinite
if ( - 1 = = isinf ( f ) ) {
print_printed ( & length , print_char ( str , size , ' - ' ) ) ; // print sign
} else if ( sign ) {
print_printed ( & length , print_char ( str , size , ' + ' ) ) ; // print sign
}
print_printed ( & length , print_string ( str , size , " inf " ) ) ; // print inf
} else if ( isnormal ( f ) ) { // it should be not 0
if ( f < 0 ) {
print_printed ( & length , print_char ( str , size , ' - ' ) ) ; // print sign
} else if ( sign ) {
print_printed ( & length , print_char ( str , size , ' + ' ) ) ; // print sign
}
double f_abs = fabs ( f ) ; // only work using the absolute value now that the sign is printed
// get the exponent
int8_t exponent = 0 ; // exponent min/max for double is 37
if ( f_abs < 1.0 ) {
while ( f_abs < pow ( 10.0 , exponent - 1 ) ) { // find negative exponent, base 10
exponent - = 1 ; // decrement in deci
}
if ( padding ) { // respect padding wish
exponent - = padding ;
}
} else {
2018-01-24 16:34:24 +01:00
while ( f_abs > = pow ( 10.0 , exponent ) ) { // find the positive exponent, base 10
2017-12-14 10:23:31 +01:00
exponent + = 3 ; // increment in kilo
}
if ( padding ) { // respect padding wish
exponent - = padding ;
} else {
exponent - = 3 ;
}
}
// print integer part
f_abs / = pow ( 10.0 , exponent ) ; // convert to scientific format
print_printed ( & length , print_unsigned ( str , size , f_abs , padding , false ) ) ; // print integer part as scientific number
// print fractional part
if ( fractional ) {
print_printed ( & length , print_char ( str , size , ' . ' ) ) ; // print decimal point
f_abs - = ( uint64_t ) f_abs ; // remove integer part
for ( uint32_t frac = 0 ; frac < fractional ; frac + + ) { // print fractional parts
f_abs * = 10.0 ;
print_printed ( & length , print_unsigned ( str , size , f_abs , 0 , false ) ) ;
f_abs - = ( uint64_t ) f_abs ;
}
}
// print exponent
if ( exponent ) {
print_printed ( & length , print_char ( str , size , ' E ' ) ) ; // print exponent mark
print_printed ( & length , print_signed ( str , size , exponent , 0 , false ) ) ;
}
} else { // f=0
// print sign
if ( f < 0 ) {
print_printed ( & length , print_char ( str , size , ' - ' ) ) ; // print sign
} else if ( sign ) {
print_printed ( & length , print_char ( str , size , ' + ' ) ) ; // print sign
}
print_printed ( & length , print_unsigned ( str , size , 0 , padding , false ) ) ; // print integer part
if ( fractional ) {
print_printed ( & length , print_char ( str , size , ' . ' ) ) ; // print decimal point
print_printed ( & length , print_unsigned ( str , size , 0 , fractional , false ) ) ; // print fractional part
}
}
return length ; // return number of characters printed
}
2017-04-03 13:07:53 +02:00
/** print nibble (half-byte)
* @ param [ out ] str string to print nibble on ( use NULL to print on user output )
* @ param [ in , out ] size size of string
* @ param [ in ] nibble nibble to be printed
* @ param [ in ] upcase use upcase digits ( A - F )
* @ return number of characters printed
* */
static size_t print_nibble ( char * * str , size_t * size , uint8_t nibble , bool upcase ) {
size_t length = 0 ; // number of characters printed
nibble & = 0x0f ; // ensure we only have a nibble
if ( nibble < 10 ) {
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' 0 ' + nibble ) ) ;
2017-04-03 13:07:53 +02:00
} else if ( upcase ) {
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' A ' + nibble - 10 ) ) ;
2017-04-03 13:07:53 +02:00
} else {
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' a ' + nibble - 10 ) ) ;
2017-04-03 13:07:53 +02:00
}
return length ; // return number of characters printed
}
/** print hex value
* @ param [ out ] str string to print hex on ( use NULL to print on user output )
* @ param [ in , out ] size size of string
* @ param [ in ] hex hex value to be printed
* @ param [ in ] padding number of 0 ' s to pad
* @ param [ in ] prefix if 0 x prefix should be printed
* @ param [ in ] upcase use upcase digits ( A - F )
* @ return number of characters printed
* */
2017-12-13 14:01:05 +01:00
static size_t print_hex ( char * * str , size_t * size , uint64_t hex , uint32_t padding , bool prefix , bool upcase ) {
2017-04-03 13:07:53 +02:00
size_t length = 0 ; // number of characters printed
if ( prefix ) { // print 0x prefix
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' 0 ' ) ) ;
print_printed ( & length , print_char ( str , size , ' x ' ) ) ;
2017-04-03 13:07:53 +02:00
}
uint8_t digits = 0 ; // number of digits to print
// figure out number of digits to print
2017-12-13 14:01:05 +01:00
if ( hex > 0xffffffffffffffUL ) {
digits = 16 ;
} else if ( hex > 0xffffffffffffUL ) {
digits = 14 ;
} else if ( hex > 0xffffffffffUL ) {
digits = 12 ;
} else if ( hex > 0xffffffffUL ) {
digits = 10 ;
} else if ( hex > 0xffffffUL ) {
2017-04-03 13:07:53 +02:00
digits = 8 ;
2017-12-13 14:01:05 +01:00
} else if ( hex > 0xffffUL ) {
2017-04-03 13:07:53 +02:00
digits = 6 ;
2017-12-13 14:01:05 +01:00
} else if ( hex > 0xffUL ) {
2017-04-03 13:07:53 +02:00
digits = 4 ;
} else {
digits = 2 ;
}
2017-12-13 12:30:16 +01:00
for ( uint32_t zeros = digits ; zeros < padding ; zeros + + ) { // print padding 0's
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' 0 ' ) ) ; // print 0
2017-04-03 13:07:53 +02:00
}
for ( uint8_t digit = 0 ; digit < digits ; digit + + ) { // go through all digits
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_nibble ( str , size , hex > > ( ( digits - digit - 1 ) * 4 ) , upcase ) ) ; // print nibble (in reverse order)
2017-04-03 13:07:53 +02:00
}
return length ; // return number of characters printed
}
/** print bits
* @ param [ out ] str string to print bits on ( use NULL to print on user output )
* @ param [ in , out ] size size of string
* @ param [ in ] u bits to be printed
* @ param [ in ] padding number of 0 ' s to pad
* @ param [ in ] prefix if 0 b prefix should be printed
* @ return number of characters printed
* */
2017-12-13 14:16:28 +01:00
static size_t print_bits ( char * * str , size_t * size , uint64_t u , uint32_t padding , bool prefix ) {
char bits [ 64 ] = { 0 } ; // construct the bit string in reverse order
2017-04-03 13:07:53 +02:00
uint8_t digits = 0 ; // to count the number of digits
size_t length = 0 ; // number of characters printed
do {
bits [ digits + + ] = ' 0 ' + ( u & 0x1 ) ; // store bit
u > > = 1 ; // go to next bit
} while ( u > 0 ) ;
if ( digits > sizeof ( bits ) ) { // prevent buffer underflow
return 0 ;
}
if ( prefix ) { // print prefix
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' 0 ' ) ) ;
print_printed ( & length , print_char ( str , size , ' b ' ) ) ;
2017-04-03 13:07:53 +02:00
}
2017-12-13 12:30:16 +01:00
for ( uint32_t zeros = digits ; zeros < padding ; zeros + + ) { // print padding 0's
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , ' 0 ' ) ) ; // print 0
2017-04-03 13:07:53 +02:00
}
for ( uint8_t digit = 0 ; digit < digits ; digit + + ) { // go through all bits
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , bits [ digits - digit - 1 ] ) ) ; // print bit (in reverse order)
2017-04-03 13:07:53 +02:00
}
return length ; // return number of characters printed
}
/** print format string on string or user output
* @ param [ out ] str string to print format string on , or user output if str is set to NULL ( str will always be terminated with a null character ' \0 ' )
* @ param [ in , out ] size size of string ( writes at most size characters on str , including the termination null character ' \0 ' )
* @ param [ in ] format format string to be printed
* @ param [ in ] va arguments referenced by format string to be printed
* @ return number of characters printed ( a return value of size or more means that the output was truncated )
* */
static size_t vsnprintf ( char * * str , size_t * size , const char * format , va_list va )
{
2017-12-13 13:48:29 +01:00
size_t length = 0 ; // total number of characters printed
2017-12-13 12:30:16 +01:00
uint32_t padding = 0 ; // number of padding 0's
2017-12-14 10:23:31 +01:00
uint32_t fractional = 0 ; // number or fractional digits for floating point numbers
2017-04-03 13:07:53 +02:00
bool sign = false ; // if sign needs to be printed
while ( * format ) { // go through format string
padding = 0 ; // reset padding
sign = false ; // reset sign
if ( ' % ' ! = * format ) { // check for format specifier prefix
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_char ( str , size , * format + + ) ) ; // print character (no interpretation needed)
2017-04-03 13:07:53 +02:00
} else {
format + + ; // go to format specifier
if ( 0 = = * format ) { // end of string detected
2017-12-13 13:48:29 +01:00
print_error | = PRINT_ERROR_MALFORMED ; // set error
2017-04-03 13:07:53 +02:00
goto end ;
}
// check if sign need to be printed
if ( ' + ' = = * format ) { // sign required
sign = true ; // remember sign is required
format + + ; // go to padding number
if ( 0 = = * format ) { // end of string detected
2017-12-13 13:48:29 +01:00
print_error | = PRINT_ERROR_MALFORMED ; // set error
2017-04-03 13:07:53 +02:00
goto end ;
}
}
// check padding
if ( ' 0 ' = = * format ) { // padding required
format + + ; // go to padding number
2017-12-13 12:30:16 +01:00
while ( * format > = ' 0 ' & & * format < = ' 9 ' ) {
if ( padding > UINT32_MAX / 10 ) { // check for overflow
2017-12-13 13:48:29 +01:00
print_error | = PRINT_ERROR_UNSUPPORTED ; // set error
2017-12-13 12:30:16 +01:00
goto end ;
}
padding * = 10 ; // go to next magnitude
if ( padding > UINT32_MAX - ( * format - ' 0 ' ) ) { // check for overflow
2017-12-13 13:48:29 +01:00
print_error | = PRINT_ERROR_UNSUPPORTED ; // set error
2017-04-03 13:07:53 +02:00
goto end ;
}
2017-12-13 13:48:29 +01:00
padding + = * format - ' 0 ' ; // save digit
2017-12-13 12:30:16 +01:00
format + + ; // go to next character
}
if ( 0 = = * format ) { // end of string detected
2017-12-13 13:48:29 +01:00
print_error | = PRINT_ERROR_MALFORMED ; // set error
2017-12-13 12:30:16 +01:00
goto end ;
2017-04-03 13:07:53 +02:00
}
}
2017-12-14 10:23:31 +01:00
// check fractional
if ( ' . ' = = * format ) { // fractional required
format + + ; // go to fractional number
while ( * format > = ' 0 ' & & * format < = ' 9 ' ) {
if ( fractional > UINT32_MAX / 10 ) { // check for overflow
print_error | = PRINT_ERROR_UNSUPPORTED ; // set error
goto end ;
}
fractional * = 10 ; // go to next magnitude
if ( fractional > UINT32_MAX - ( * format - ' 0 ' ) ) { // check for overflow
print_error | = PRINT_ERROR_UNSUPPORTED ; // set error
goto end ;
}
fractional + = * format - ' 0 ' ; // save digit
format + + ; // go to next character
}
if ( 0 = = * format ) { // end of string detected
print_error | = PRINT_ERROR_MALFORMED ; // set error
goto end ;
}
} else {
fractional = 2 ; // default fractional precision
}
2017-04-03 13:07:53 +02:00
// check format specifier
switch ( * format ) {
2017-12-14 10:23:31 +01:00
case ' c ' : // for char, unsigned char
print_printed ( & length , print_char ( str , size , ( char ) ( va_arg ( va , int ) ) ) ) ; // needs casting because the returned value is promoted
break ;
case ' s ' : // for strings
print_printed ( & length , print_string ( str , size , va_arg ( va , char * ) ) ) ;
break ;
2017-04-03 13:07:53 +02:00
case ' u ' : // for uint8_t, uint16_t, uint32_t, unsigned int, unsigned long
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_unsigned ( str , size , va_arg ( va , uint32_t ) , padding , sign ) ) ;
2017-04-03 13:07:53 +02:00
break ;
case ' U ' : // for uint64_t, unsigned long long
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_unsigned ( str , size , va_arg ( va , uint64_t ) , padding , sign ) ) ;
2017-04-03 13:07:53 +02:00
break ;
case ' d ' : // for int8_t, int16_t, int32_t, int, long
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_signed ( str , size , va_arg ( va , int32_t ) , padding , sign ) ) ;
2017-04-03 13:07:53 +02:00
break ;
case ' D ' : // for int64_t, long long
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_signed ( str , size , va_arg ( va , int64_t ) , padding , sign ) ) ;
2017-04-03 13:07:53 +02:00
break ;
2017-12-14 10:23:31 +01:00
case ' f ' :
print_printed ( & length , print_float ( str , size , va_arg ( va , double ) , padding , fractional , sign ) ) ;
2017-04-03 13:07:53 +02:00
break ;
2017-12-13 14:01:05 +01:00
case ' x ' : // for uint8_t, uint16_t, uint32_t downcase hexadecimal
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_hex ( str , size , va_arg ( va , uint32_t ) , padding , sign , false ) ) ;
2017-04-03 13:07:53 +02:00
break ;
2017-12-13 14:01:05 +01:00
case ' X ' : // for uint64_t downcase hexadecimal
print_printed ( & length , print_hex ( str , size , va_arg ( va , uint64_t ) , padding , sign , false ) ) ;
break ;
case ' h ' : // for uint8_t, uint16_t, uint32_t upcase hexadecimal
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_hex ( str , size , va_arg ( va , uint32_t ) , padding , sign , true ) ) ;
2017-04-03 13:07:53 +02:00
break ;
2017-12-13 14:01:05 +01:00
case ' H ' : // for uint64_t upcase hexadecimal
print_printed ( & length , print_hex ( str , size , va_arg ( va , uint64_t ) , padding , sign , true ) ) ;
break ;
2017-12-13 14:16:28 +01:00
case ' b ' : // for uint8_t, uint16_t, uint32_t bits
2017-12-13 13:48:29 +01:00
print_printed ( & length , print_bits ( str , size , va_arg ( va , uint32_t ) , padding , sign ) ) ;
2017-04-03 13:07:53 +02:00
break ;
2017-12-13 14:16:28 +01:00
case ' B ' : // for uint64_t bits
print_printed ( & length , print_bits ( str , size , va_arg ( va , uint64_t ) , padding , sign ) ) ;
break ;
2017-04-03 13:07:53 +02:00
default :
2017-12-13 13:48:29 +01:00
print_error | = PRINT_ERROR_UNSUPPORTED ; // set error
print_printed ( & length , print_char ( str , size , * format ) ) ; // print character (unknown format specifier)
2017-04-03 13:07:53 +02:00
}
format + + ; // go to next character
}
}
end :
if ( NULL ! = str & & NULL ! = * str & & NULL ! = size ) { // when working on a string
* * str = ' \0 ' ; // enforce null termination
2017-12-13 13:48:29 +01:00
if ( * size > 0 ) {
* size - = 1 ; // remember we used memory
} else {
print_error | = PRINT_ERROR_TRUNCATED ; // indicate we truncated the string
}
2017-04-03 13:07:53 +02:00
}
2017-12-13 13:48:29 +01:00
return length ; // return number of characters it should have written (not including the '\0' null termination character)
2017-04-03 13:07:53 +02:00
}
size_t printf ( const char * format , . . . )
{
2017-12-13 13:48:29 +01:00
print_error = PRINT_ERROR_NONE ; // clear error
2017-04-03 13:07:53 +02:00
va_list arglist ;
va_start ( arglist , format ) ;
2017-12-13 13:48:29 +01:00
size_t length = vsnprintf ( NULL , NULL , format , arglist ) ;
2017-04-03 13:07:53 +02:00
va_end ( arglist ) ;
return length ;
}
size_t snprintf ( char * str , size_t size , const char * format , . . . )
{
2017-12-13 13:48:29 +01:00
print_error = PRINT_ERROR_NONE ; // clear error
2017-04-03 13:07:53 +02:00
va_list arglist ;
va_start ( arglist , format ) ;
2017-12-13 13:48:29 +01:00
size_t length = vsnprintf ( & str , & size , format , arglist ) ;
2017-04-03 13:07:53 +02:00
va_end ( arglist ) ;
return length ;
}