diff options
| author | Michael Sevakis <jethead71@rockbox.org> | 2017-09-08 19:28:02 -0400 |
|---|---|---|
| committer | Michael Sevakis <jethead71@rockbox.org> | 2017-11-21 05:00:27 -0500 |
| commit | 5c9688961ef9166cec5225db50d5f73691d8292d (patch) | |
| tree | 467cc61cceef1fda804f9c715e9994670eb7683f /firmware/libc | |
| parent | 52af55eee8566e23b190b7444e73df0106b1663d (diff) | |
| download | rockbox-5c9688961ef9166cec5225db50d5f73691d8292d.zip rockbox-5c9688961ef9166cec5225db50d5f73691d8292d.tar.gz rockbox-5c9688961ef9166cec5225db50d5f73691d8292d.tar.bz2 rockbox-5c9688961ef9166cec5225db50d5f73691d8292d.tar.xz | |
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
Diffstat (limited to 'firmware/libc')
| -rw-r--r-- | firmware/libc/sprintf.c | 110 |
1 files changed, 65 insertions, 45 deletions
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 <stdio.h> -#include <stdarg.h> -#include <stdbool.h> #include <limits.h> -#include "format.h" +#include <errno.h> +#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; } |