summaryrefslogtreecommitdiffstats
path: root/firmware/libc
diff options
context:
space:
mode:
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;
}