summaryrefslogtreecommitdiffstats
path: root/firmware/libc
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2017-09-08 19:28:02 -0400
committerMichael Sevakis <jethead71@rockbox.org>2017-11-21 05:00:27 -0500
commit5c9688961ef9166cec5225db50d5f73691d8292d (patch)
tree467cc61cceef1fda804f9c715e9994670eb7683f /firmware/libc
parent52af55eee8566e23b190b7444e73df0106b1663d (diff)
downloadrockbox-5c9688961ef9166cec5225db50d5f73691d8292d.tar.gz
rockbox-5c9688961ef9166cec5225db50d5f73691d8292d.tar.bz2
rockbox-5c9688961ef9166cec5225db50d5f73691d8292d.zip
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.c110
1 files changed, 65 insertions, 45 deletions
diff --git a/firmware/libc/sprintf.c b/firmware/libc/sprintf.c
index 18e2ce6fd2..a56f454c34 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;
}