From aafc3022fc0d3a8cf4a6ea0878897f9667d5da67 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Wed, 20 Sep 2017 20:45:28 -0700 Subject: [PATCH 1/6] Implement length field Provisional for testing only --- mini-printf.c | 31 +++++++++++++++++++++++++------ test1.c | 6 ++++++ test1.gold | 3 +++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/mini-printf.c b/mini-printf.c index 53cfe99..6a8c350 100644 --- a/mini-printf.c +++ b/mini-printf.c @@ -53,7 +53,7 @@ mini_strlen(const char *s) static unsigned int mini_itoa(int value, unsigned int radix, unsigned int uppercase, unsigned int unsig, - char *buffer, unsigned int zero_pad) + char *buffer, unsigned int zero_pad, unsigned int width) { char *pbuffer = buffer; int negative = 0; @@ -81,6 +81,9 @@ mini_itoa(int value, unsigned int radix, unsigned int uppercase, unsigned int un if (negative) *(pbuffer++) = '-'; + for (i = (pbuffer - buffer); i < width; i++) + *(pbuffer++) = ' '; + *(pbuffer) = '\0'; /* ... now we reverse it (could do it recursively but will @@ -143,12 +146,22 @@ mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list v if (ch!='%') _putc(ch, &b); else { - char zero_pad = 0; + unsigned int zero_pad = 0; char *ptr; unsigned int len; + unsigned int width = 0; - ch=*(fmt++); + ch=*(fmt++); // step over the % + /* Format width */ + if (ch>'0' && ch<='9') { + width = ch-'0'; + while (ch=*(fmt++), ch>='0' && ch<='9') { + width = width*10 + ch - '0'; + } + if (ch == '\0') + goto end; + } /* Zero padding requested */ if (ch=='0') { ch=*(fmt++); @@ -165,13 +178,15 @@ mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list v case 'u': case 'd': - len = mini_itoa(va_arg(va, unsigned int), 10, 0, (ch=='u'), bf, zero_pad); + if (width > sizeof bf) width = sizeof bf; /* prevent buffer overflow */ + len = mini_itoa(va_arg(va, unsigned int), 10, 0, (ch=='u'), bf, zero_pad, width); _puts(bf, len, &b); break; case 'x': case 'X': - len = mini_itoa(va_arg(va, unsigned int), 16, (ch=='X'), 1, bf, zero_pad); + if (width > sizeof bf) width = sizeof bf; /* prevent buffer overflow */ + len = mini_itoa(va_arg(va, unsigned int), 16, (ch=='X'), 1, bf, zero_pad, width); _puts(bf, len, &b); break; @@ -181,7 +196,11 @@ mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list v case 's' : ptr = va_arg(va, char*); - _puts(ptr, mini_strlen(ptr), &b); + { + unsigned l = mini_strlen(ptr); + for (unsigned ix=l; ix Date: Wed, 20 Sep 2017 20:47:05 -0700 Subject: [PATCH 2/6] Add easier mechanism to cross-check against libc As in -D_LIBC_REVERT --- test1.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test1.c b/test1.c index 6956e88..934d814 100644 --- a/test1.c +++ b/test1.c @@ -1,24 +1,27 @@ #include +#ifndef _LIBC_REVERT #include "mini-printf.h" +#define snprintf mini_snprintf +#endif int main(void) { char buff[30]; - mini_snprintf(buff, sizeof buff, "testing %d %d %07d", 1, 2, 3); + snprintf(buff, sizeof buff, "testing %d %d %07d", 1, 2, 3); puts(buff); - mini_snprintf(buff, sizeof buff, "faster %s %ccheaper%c", "and", 34, 34); + snprintf(buff, sizeof buff, "faster %s %ccheaper%c", "and", 34, 34); puts(buff); - mini_snprintf(buff, sizeof buff, "%x %% %X", 0xdeadf00d, 0xdeadf00d); + snprintf(buff, sizeof buff, "%x %% %X", 0xdeadf00d, 0xdeadf00d); puts(buff); - mini_snprintf(buff, sizeof buff, "%09d%09d%09d%09d%09d", 1, 2, 3, 4, 5); + snprintf(buff, sizeof buff, "%09d%09d%09d%09d%09d", 1, 2, 3, 4, 5); puts(buff); - mini_snprintf(buff, sizeof buff, "%d %u %d %u", 50, 50, -50, -50); + snprintf(buff, sizeof buff, "%d %u %d %u", 50, 50, -50, -50); puts(buff); - mini_snprintf(buff, sizeof buff, "(%6d) (%12d)", 78, 78); + snprintf(buff, sizeof buff, "(%6d) (%12d)", 78, 78); puts(buff); - mini_snprintf(buff, sizeof buff, "(%s) (%12s) (%s)", "a", "b", "xcccccccccccccccx"); + snprintf(buff, sizeof buff, "(%s) (%12s) (%s)", "a", "b", "xcccccccccccccccx"); puts(buff); - mini_snprintf(buff, sizeof buff, "(%s)", "xcccccccccccccccx"); + snprintf(buff, sizeof buff, "(%s)", "xcccccccccccccccx"); puts(buff); return 0; } From 30dc4d145ea445d159f392ca355e0c99d3095c78 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Wed, 20 Sep 2017 20:48:16 -0700 Subject: [PATCH 3/6] Get rid of some stupid whitespace --- mini-printf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mini-printf.c b/mini-printf.c index 6a8c350..0b96612 100644 --- a/mini-printf.c +++ b/mini-printf.c @@ -55,9 +55,9 @@ static unsigned int mini_itoa(int value, unsigned int radix, unsigned int uppercase, unsigned int unsig, char *buffer, unsigned int zero_pad, unsigned int width) { - char *pbuffer = buffer; - int negative = 0; - unsigned int i, len; + char *pbuffer = buffer; + int negative = 0; + unsigned int i, len; /* No support for unusual radixes. */ if (radix > 16) From 25acd6a68d6a275d28acb7af6465cddf7ccc69c7 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Wed, 17 Jun 2020 18:04:18 -0700 Subject: [PATCH 4/6] NULL terminate empty and malformed inputs Thanks @cybojanek! --- mini-printf.c | 2 ++ test1.c | 12 ++++++++++++ test1.gold | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/mini-printf.c b/mini-printf.c index 0b96612..7ee9bc1 100644 --- a/mini-printf.c +++ b/mini-printf.c @@ -140,6 +140,8 @@ mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list v b.pbuffer = buffer; b.buffer_len = buffer_len; + if (buffer_len > 0) *buffer = 0; + while ((ch=*(fmt++))) { if ((unsigned int)((b.pbuffer - b.buffer) + 1) >= b.buffer_len) break; diff --git a/test1.c b/test1.c index 934d814..9f53dbc 100644 --- a/test1.c +++ b/test1.c @@ -17,6 +17,18 @@ int main(void) puts(buff); snprintf(buff, sizeof buff, "%d %u %d %u", 50, 50, -50, -50); puts(buff); + snprintf(buff, sizeof buff, "%0"); + puts(buff); + snprintf(buff, sizeof buff, "a%0"); + puts(buff); + snprintf(buff, sizeof buff, "%"); + puts(buff); + snprintf(buff, sizeof buff, "b%"); + puts(buff); + snprintf(buff, 0, "%s", "hello"); + puts(buff); + snprintf(buff, sizeof buff, ""); + puts(buff); snprintf(buff, sizeof buff, "(%6d) (%12d)", 78, 78); puts(buff); snprintf(buff, sizeof buff, "(%s) (%12s) (%s)", "a", "b", "xcccccccccccccccx"); diff --git a/test1.gold b/test1.gold index 5ea8924..4d8dafb 100644 --- a/test1.gold +++ b/test1.gold @@ -3,6 +3,12 @@ faster and "cheaper" deadf00d % DEADF00D 00000000100000000200000000300 50 50 -50 4294967246 + +a + +b +b + ( 78) ( 78) (a) ( b) (xcccccccc (xcccccccccccccccx) From 02b6d36edcdc95b4cb18472b59d0758f97ba7234 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Wed, 17 Jun 2020 18:05:48 -0700 Subject: [PATCH 5/6] Fix typos in README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 942872c..1f63328 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Motivation I was recently working on an embedded project with a STM32 MCU. The chip had 32kB of flash memory - that's heaps for a microcontroller! -How surprised I was when the linker suddelnly failed saying that +How surprised I was when the linker suddenly failed saying that the program is too big and won't fit! How come?! It's just some USB, I2C, GPIO, a few timers ... and snprintf() @@ -88,12 +88,13 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the auhor nor the names of its contributors + * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. From 42f66f77fcc0e608ba21683aac959c56211b93b4 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Wed, 17 Jun 2020 18:06:03 -0700 Subject: [PATCH 6/6] Stricter warning flags in build --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 1ac111c..00bc875 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ CFLAGS = --std=c99 -O2 -pedantic -Wall -Wextra -Wshadow +CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wundef +CFLAGS += -Wpointer-arith -Wcast-align -Wcast-qual -Wredundant-decls %_check: %.out %.gold cmp $^