From 5c9688961ef9166cec5225db50d5f73691d8292d Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Fri, 8 Sep 2017 19:28:02 -0400 Subject: Implement a much more capable vuprintf() New support as well as some buggy support fixed. Still no floating point support if ever that would be desired. Support (*): * Flags: '-', '+', ' ', '#', '0' * Width and precision: 'n', '.n', '*' and '.*' * Length modifiers: 'hh', 'h', 'j', 'l', 'll', 't', 'z' * Radix: 'c', 'd', 'i', 'n', 'o', 'p/P', 's', 'u', 'x/X' (*) Provision exists to switch lesser-used stuff on or off or when certain functionality isn't desired (bootloader?). The compulsory radixes are everything but 'o', 'n', 'p/P' and 'x/X' with length modifiers being optional. The default setup is 'l', 'z', 'c', 'd', 'p/P', 's', 'u', 'x/X'. * Move fdprintf() to its own file. It was in a strange place. * Make callers compatible and fix a couple snprintf() bugs while at it. Could smush it down in size but I'm gonna get over the binsize neurosis and just the let optimizer do its thing. Change-Id: Ibdc613a9b6775802c188b29b9dd46c568c94f7c3 --- firmware/libc/sprintf.c | 110 ++++++++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 45 deletions(-) (limited to 'firmware/libc') diff --git a/firmware/libc/sprintf.c b/firmware/libc/sprintf.c index 18e2ce6..a56f454 100644 --- a/firmware/libc/sprintf.c +++ b/firmware/libc/sprintf.c @@ -18,74 +18,94 @@ * KIND, either express or implied. * ****************************************************************************/ - -/* - * Minimal printf and snprintf formatting functions - * - * These support %c %s %d and %x - * Field width and zero-padding flag only - */ - #include -#include -#include #include -#include "format.h" +#include +#include "vuprintf.h" /* ALSA library requires a more advanced snprintf, so let's not override it in simulator for Linux. Note that Cygwin requires our snprintf or it produces garbled output after a while. */ struct for_snprintf { - unsigned char *ptr; /* where to store it */ - size_t bytes; /* amount already stored */ - size_t max; /* max amount to store */ + char *ptr; /* where to store it */ + int rem; /* unwritten buffer remaining */ }; -static int sprfunc(void *ptr, unsigned char letter) +static int sprfunc(void *ptr, int letter) { struct for_snprintf *pr = (struct for_snprintf *)ptr; - if(pr->bytes < pr->max) { - *pr->ptr = letter; - pr->ptr++; - pr->bytes++; - return true; + + if (pr->rem > 0) { + if (--pr->rem == 0) { + return 0; + } + + *pr->ptr++ = letter; + return 1; } - return false; /* filled buffer */ -} + else { + if (pr->rem == -INT_MAX) { + pr->rem = 1; + return -1; + } + --pr->rem; + return 1; + } +} -int snprintf(char *buf, size_t size, const char *fmt, ...) +int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) { - va_list ap; - struct for_snprintf pr; + if (size <= INT_MAX) { + int bytes; + struct for_snprintf pr; + + pr.ptr = buf; + pr.rem = size; - pr.ptr = (unsigned char *)buf; - pr.bytes = 0; - pr.max = size; + bytes = vuprintf(sprfunc, &pr, fmt, ap); - va_start(ap, fmt); - format(sprfunc, &pr, fmt, ap); - va_end(ap); + if (size) { + *pr.ptr = '\0'; + } + else if (pr.rem > 0) { + goto overflow; + } - /* make sure it ends with a trailing zero */ - pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0'; - - return pr.bytes; + return bytes; + } + +overflow: + errno = EOVERFLOW; + return -1; } -int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) +int snprintf(char *buf, size_t size, const char *fmt, ...) { - struct for_snprintf pr; + if (size <= INT_MAX) { + int bytes; + struct for_snprintf pr; + va_list ap; + + pr.ptr = buf; + pr.rem = size; - pr.ptr = (unsigned char *)buf; - pr.bytes = 0; - pr.max = size; + va_start(ap, fmt); + bytes = vuprintf(sprfunc, &pr, fmt, ap); + va_end(ap); - format(sprfunc, &pr, fmt, ap); + if (size) { + *pr.ptr = '\0'; + } + else if (pr.rem > 0) { + goto overflow; + } + + return bytes; + } - /* make sure it ends with a trailing zero */ - pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0'; - - return pr.bytes; +overflow: + errno = EOVERFLOW; + return -1; } -- cgit v1.1