[PATCH 15/17] printf: support field padding

Andrew Jones
2014-01-21T16:22:47Z

Support format flags for field padding, such as "%08x", allowing
register dumps to be easier on the eyes.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
lib/printf.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 68 insertions(+), 14 deletions(-)

diff --git a/lib/printf.c b/lib/printf.c
index 867eb1926f742..89308fb26b7d2 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -6,6 +6,11 @@ typedef struct pstream {
int added;
} pstream_t;

+typedef struct strprops {
+ char pad;
+ int npad;
+} strprops_t;
+
static void addchar(pstream_t *p, char c)
{
if (p->remain) {
@@ -15,15 +20,35 @@ static void addchar(pstream_t *p, char c)
++p->added;
}

-void print_str(pstream_t *p, const char *s)
+void print_str(pstream_t *p, const char *s, strprops_t props)
{
+ const char *s_orig = s;
+ int npad = props.npad;
+
+ if (npad > 0) {
+ npad -= strlen(s_orig);
+ while (npad > 0) {
+ addchar(p, props.pad);
+ --npad;
+ }
+ }
+
while (*s)
addchar(p, *s++);
+
+ if (npad < 0) {
+ props.pad = ' '; /* ignore '0' flag with '-' flag */
+ npad += strlen(s_orig);
+ while (npad < 0) {
+ addchar(p, props.pad);
+ ++npad;
+ }
+ }
}

static char digits[16] = "0123456789abcdef";

-void print_int(pstream_t *ps, long long n, int base)
+void print_int(pstream_t *ps, long long n, int base, strprops_t props)
{
char buf[sizeof(long) * 3 + 2], *p = buf;
int s = 0, i;
@@ -54,10 +79,11 @@ void print_int(pstream_t *ps, long long n, int base)

*p = 0;

- print_str(ps, buf);
+ print_str(ps, buf, props);
}

-void print_unsigned(pstream_t *ps, unsigned long long n, int base)
+void print_unsigned(pstream_t *ps, unsigned long long n, int base,
+ strprops_t props)
{
char buf[sizeof(long) * 3 + 1], *p = buf;
int i;
@@ -80,7 +106,23 @@ void print_unsigned(pstream_t *ps, unsigned long long n, int base)

*p = 0;

- print_str(ps, buf);
+ print_str(ps, buf, props);
+}
+
+static int fmtnum(const char **fmt)
+{
+ const char *f = *fmt;
+ int len = 0, num;
+
+ if (*f == '-')
+ ++f, ++len;
+
+ while (*f >= '0' && *f <= '9')
+ ++f, ++len;
+
+ num = atol(*fmt);
+ *fmt += len;
+ return num;
}

int vsnprintf(char *buf, int size, const char *fmt, va_list va)
@@ -93,6 +135,9 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
while (*fmt) {
char f = *fmt++;
int nlong = 0;
+ strprops_t props;
+ memset(&props, 0, sizeof(props));
+ props.pad = ' ';

if (f != '%') {
addchar(&s, f);
@@ -110,41 +155,50 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
case '\0':
--fmt;
break;
+ case '0':
+ props.pad = '0';
+ ++fmt;
+ /* fall through */
+ case '1'...'9':
+ case '-':
+ --fmt;
+ props.npad = fmtnum(&fmt);
+ goto morefmt;
case 'l':
++nlong;
goto morefmt;
case 'd':
switch (nlong) {
case 0:
- print_int(&s, va_arg(va, int), 10);
+ print_int(&s, va_arg(va, int), 10, props);
break;
case 1:
- print_int(&s, va_arg(va, long), 10);
+ print_int(&s, va_arg(va, long), 10, props);
break;
default:
- print_int(&s, va_arg(va, long long), 10);
+ print_int(&s, va_arg(va, long long), 10, props);
break;
}
break;
case 'x':
switch (nlong) {
case 0:
- print_unsigned(&s, va_arg(va, unsigned), 16);
+ print_unsigned(&s, va_arg(va, unsigned), 16, props);
break;
case 1:
- print_unsigned(&s, va_arg(va, unsigned long), 16);
+ print_unsigned(&s, va_arg(va, unsigned long), 16, props);
break;
default:
- print_unsigned(&s, va_arg(va, unsigned long long), 16);
+ print_unsigned(&s, va_arg(va, unsigned long long), 16, props);
break;
}
break;
case 'p':
- print_str(&s, "0x");
- print_unsigned(&s, (unsigned long)va_arg(va, void *), 16);
+ print_str(&s, "0x", props);
+ print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
break;
case 's':
- print_str(&s, va_arg(va, const char *));
+ print_str(&s, va_arg(va, const char *), props);
break;
default:
addchar(&s, f);
--
1.8.1.4