diff --git a/lib/print.c b/lib/print.c index 810de7d..4eef9f8 100644 --- a/lib/print.c +++ b/lib/print.c @@ -19,7 +19,8 @@ */ /* standard libraries */ #include // standard integer types -#include // boolean type +#include // standard definitions +#include // boolean types #include // variadic utilities /* own libraries */ @@ -31,35 +32,29 @@ #define CRLF true /**< if CR+LN new line should be enforced */ /** @} */ -uint8_t putc(char c) +static size_t print_char(char** str, size_t* size, char c) { - uint8_t length = 0; // number of characters printed - static char newline = 0; // to remember on which character we sent the newline - if (0==c) { - length = 0; // don't print string termination character - } else if (!CRLF) { - _putc(c); // print character - length++; // remember we printed 1 character - } else if ('\r' == c || '\n' == c) { // send CR+LF newline for most carriage return and line feed combination - if (0==newline || c==newline) { // send newline only if not already send (and only once on \r\n or \n\r) - _putc('\r'); // send CR - _putc('\n'); // send LF - length += 2; // remember we printed 2 characters - newline = c; // remember on which character we sent the newline - } - } else { - _putc(c); // print character - newline = 0; // clear new line - length++; // remember we printed 1 character + 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 + } else if (*size>1) { // // there is enough space in the string to store the character + **str = c; // add provided character to string + *str += 1; // go to next character on string + *size -= 1; // remember we used one character on string + } else if (1==*size) { // string is reaching it's end + **str = '\0'; // add termination character to string (don't go to next character) + *size -= 1; // remember we used one character on string } - return length; // return number of characters printed + return length; } -uint32_t puts(const char* s) +static size_t print_string(char** str, size_t* size, const char* s) { - uint32_t length = 0; // number of characters printed + size_t length = 0; // number of characters printed while (*s) { // stop at end of string - length += putc(*(s++)); // send character + length += print_char(str, size, *(s++)); // print character } return length; } @@ -70,10 +65,10 @@ uint32_t puts(const char* s) * @param[in] sign if sign should be printed * @return number of characters printed **/ -static uint8_t print_unsigned(uint64_t u, uint8_t padding, bool sign) { +static size_t print_unsigned(char** str, size_t* size, uint64_t u, uint8_t padding, bool sign) { 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 - uint8_t length = 0; // number of characters printed + size_t length = 0; // number of characters printed do { number[digits++] = '0'+(u%10); // store digit u /= 10; // go to next digit @@ -82,13 +77,13 @@ static uint8_t print_unsigned(uint64_t u, uint8_t padding, bool sign) { return 0; } if (sign) { // print sign - length += putc('+'); // we only have positive numbers + length += print_char(str, size, '+'); // we only have positive numbers } for (uint8_t zeros = digits; zeros>((digits-digit-1)*4), upcase); // print nibble (in reverse order) + length += print_nibble(str, size, hex>>((digits-digit-1)*4), upcase); // print nibble (in reverse order) } return length; // return number of characters printed } @@ -167,10 +162,10 @@ static uint8_t print_hex(uint32_t hex, uint8_t padding, bool prefix, bool upcase * @param[in] prefix if 0b prefix should be printed * @return number of characters printed **/ -static uint8_t print_bits(uint32_t u, uint8_t padding, bool prefix) { +static size_t print_bits(char** str, size_t* size, uint32_t u, uint8_t padding, bool prefix) { char bits[32] = {0}; // construct the bit string in reverse order uint8_t digits = 0; // to count the number of digits - uint8_t length = 0; // number of characters printed + size_t length = 0; // number of characters printed do { bits[digits++] = '0'+(u&0x1); // store bit u >>= 1; // go to next bit @@ -179,93 +174,110 @@ static uint8_t print_bits(uint32_t u, uint8_t padding, bool prefix) { return 0; } if (prefix) { // print prefix - length += putc('0'); - length += putc('b'); + length += print_char(str, size, '0'); + length += print_char(str, size, 'b'); } for (uint8_t zeros = digits; zeros='0' && *fmt<='9') { - padding = *fmt-'0'; - fmt++; // go to format specifier - if (0==*fmt) { // end of string detected + if (*format>='0' && *format<='9') { + padding = *format-'0'; + format++; // go to format specifier + if (0==*format) { // end of string detected goto end; } } } // check format specifier - switch (*fmt) { + switch (*format) { case 'u': // for uint8_t, uint16_t, uint32_t, unsigned int, unsigned long - length += print_unsigned(va_arg(va,uint32_t), padding, sign); + length += print_unsigned(str, size, va_arg(va,uint32_t), padding, sign); break; case 'U': // for uint64_t, unsigned long long - length += print_unsigned(va_arg(va,uint64_t), padding, sign); + length += print_unsigned(str, size, va_arg(va,uint64_t), padding, sign); break; case 'd': // for int8_t, int16_t, int32_t, int, long - length += print_signed(va_arg(va,int32_t), padding, sign); + length += print_signed(str, size, va_arg(va,int32_t), padding, sign); break; case 'D': // for int64_t, long long - length += print_signed(va_arg(va,int64_t), padding, sign); + length += print_signed(str, size, va_arg(va,int64_t), padding, sign); break; case 'c': // for char, unsigned char - length += putc((char)(va_arg(va,int))); // needs casting because the returned value is promoted + length += print_char(str, size, (char)(va_arg(va,int))); // needs casting because the returned value is promoted break; case 'x': // for downcase hexadecimal - length += print_hex(va_arg(va,uint32_t), padding, sign, false); + length += print_hex(str, size, va_arg(va,uint32_t), padding, sign, false); break; case 'X': // for upcase hexadecimal - length += print_hex(va_arg(va,uint32_t), padding, sign, true); + length += print_hex(str, size, va_arg(va,uint32_t), padding, sign, true); break; case 'b': // for bits - length += print_bits(va_arg(va,uint32_t), padding, sign); + length += print_bits(str, size, va_arg(va,uint32_t), padding, sign); break; case 's': // for strings - length += puts(va_arg(va,char*)); + length += print_string(str, size, va_arg(va,char*)); break; default: - length += putc(*fmt); // print character (unknown format specifier) + length += print_char(str, size, *format); // print character (unknown format specifier) } - fmt++; // go to next character + format++; // go to next character } } end: - va_end(va); + return length; +} + +size_t printf(const char *format, ...) +{ + size_t length = 0; + va_list arglist; + va_start(arglist, format); + length = vsnprintf(NULL, NULL, format, arglist); + va_end(arglist); + return length; +} + +size_t snprintf(char* str, size_t size, const char* format, ...) +{ + size_t length = 0; + va_list arglist; + va_start(arglist, format); + length = vsnprintf(&str, &size, format, arglist); + va_end(arglist); return length; } diff --git a/lib/print.h b/lib/print.h index afd2f7f..f82867d 100644 --- a/lib/print.h +++ b/lib/print.h @@ -23,18 +23,7 @@ * @warning this must be implemented by the user (using the desired output interface) * @param[in] c character to be printed **/ -void _putc(char c); -/** print character - * @note a CR+LF new line can be enforced in the code using @ref print_crlf - * @param[in] c character to be printed - * @return number of characters printed - */ -uint8_t putc(char c); -/** print string - * @param[in] s string to be printed - * @return number of characters printed (excluding null termination) - */ -uint32_t puts(const char* s); +size_t putc(char c); /** print format string * use % as format specifier prefix, followed by + to enforce sign of prefix, 0 and 0-9 for padding, and format specifier * format specifier supported are: c for far, s for string, u for uint32_t, d for int32_t, U for uint64_t, D for int64_t, x for lower case hex up to uint32_t, X for upper case hex up to uint32_t, b for bits up to uint32_t @@ -42,4 +31,6 @@ uint32_t puts(const char* s); * @param[in] ... arguments to to be formated * @return number of characters printed (excluding null termination) */ -uint32_t printf(const char *fmt, ...); +size_t printf(const char* format, ...); +size_t snprintf(char* str, size_t size, const char* format, ...); +