summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@gnu.org>2009-01-17 18:15:58 +0100
committerNeal H. Walfield <neal@gnu.org>2009-01-17 18:16:25 +0100
commit3b19e1767cc604d15f2912bf4fd314c6c5906e79 (patch)
treeab44b63fcff48efb924b4c05382bc1f81d81d829
parentc630ae1e13659bbceed85ad47f519fedb09fc73f (diff)
Extend s_printf to support precision, base and type modifiers.
2009-01-17 Neal H. Walfield <neal@gnu.org> * s_printf.c (FLAG_LONGLONG): Define. (FLAG_PAD_ZERO): Define. (FLAG_BASE): Define. (FLAG_UPPERCASE): Define. (FLAG_LONG): Define. (print_nr): Take additional parameters precision and flags. Use them. Update users. (print_signed_nr): Likewise. (s_cvprintf): Support precision, base and type modifiers. Contributed by Tom Bachmann <e_mc_h2@web.de>.
-rw-r--r--libc-parts/ChangeLog13
-rw-r--r--libc-parts/s_printf.c267
2 files changed, 189 insertions, 91 deletions
diff --git a/libc-parts/ChangeLog b/libc-parts/ChangeLog
index ebd9833..cdbb224 100644
--- a/libc-parts/ChangeLog
+++ b/libc-parts/ChangeLog
@@ -1,3 +1,16 @@
+2009-01-17 Neal H. Walfield <neal@gnu.org>
+
+ * s_printf.c (FLAG_LONGLONG): Define.
+ (FLAG_PAD_ZERO): Define.
+ (FLAG_BASE): Define.
+ (FLAG_UPPERCASE): Define.
+ (FLAG_LONG): Define.
+ (print_nr): Take additional parameters precision and flags. Use
+ them. Update users.
+ (print_signed_nr): Likewise.
+ (s_cvprintf): Support precision, base and type modifiers.
+ Contributed by Tom Bachmann <e_mc_h2@web.de>.
+
2009-01-16 Neal H. Walfield <neal@gnu.org>
* _exit.c (_exit): Use sched_yield, not l4_yield.
diff --git a/libc-parts/s_printf.c b/libc-parts/s_printf.c
index 94caaa2..5568851 100644
--- a/libc-parts/s_printf.c
+++ b/libc-parts/s_printf.c
@@ -134,14 +134,34 @@ s_puts (const char *str)
return ret;
}
+/* Output format flags. */
+#define FLAG_LONGLONG (1 << 0)
+#define FLAG_PAD_ZERO (1 << 1)
+#define FLAG_BASE (1 << 2)
+#define FLAG_UPPERCASE (1 << 3)
+#define FLAG_LONG (1 << 4)
static void
-print_nr (int (*putchar) (int), unsigned long long nr, int base)
+print_nr (int (*putchar) (int),
+ unsigned long long nr, int base, int precision, unsigned int flags)
{
- static char *digits = "0123456789abcdef";
+ static char *digits;
char str[30];
int i = 0;
+ digits = (flags & FLAG_UPPERCASE) ? "0123456789ABCDEF" : "0123456789abcdef";
+
+ if (flags & FLAG_BASE)
+ {
+ if (base == 16)
+ {
+ putchar ('0');
+ putchar ((flags & FLAG_UPPERCASE) ? 'X' : 'x');
+ }
+ else if (base == 8)
+ putchar ('0');
+ }
+
do
{
str[i++] = digits[nr % base];
@@ -149,6 +169,12 @@ print_nr (int (*putchar) (int), unsigned long long nr, int base)
}
while (nr);
+ if (precision >= sizeof (str))
+ precision = sizeof (str);
+
+ while (i < precision)
+ str[i++] = (flags & FLAG_PAD_ZERO) ? '0' : ' ';
+
i--;
while (i >= 0)
putchar (str[i--]);
@@ -156,7 +182,8 @@ print_nr (int (*putchar) (int), unsigned long long nr, int base)
static void
-print_signed_nr (int (*putchar) (int), long long nr, int base)
+print_signed_nr (int (*putchar) (int),
+ long long nr, int base, int precision, unsigned int flags)
{
unsigned long long unr;
@@ -168,128 +195,186 @@ print_signed_nr (int (*putchar) (int), long long nr, int base)
else
unr = nr;
- print_nr (putchar, unr, base);
+ print_nr (putchar, unr, base, precision, flags);
}
-
+
int
s_cvprintf (int (*putchar) (int), const char *fmt, va_list ap)
{
+ int precision = 0;
+ unsigned int flags = 0;
+ bool done;
+
const char *p = fmt;
while (*p != '\0')
{
+ const char *startp;
+
if (*p != '%')
{
putchar (*(p++));
continue;
}
-
p++;
- switch (*p)
- {
- case '%':
- putchar ('%');
- p++;
- break;
-
- case 'l':
- p++;
- if (*p != 'l')
- {
- putchar ('%');
- putchar ('l');
- putchar (*(p++));
- continue;
- }
- p++;
+
+ startp = p;
+ flags = 0;
+ precision = 0;
+ done = false;
+
+ while (*p && !done)
+ {
switch (*p)
{
- case 'o':
- print_nr (putchar, va_arg (ap, unsigned long long), 8);
+ case '%':
+ putchar ('%');
+ p++;
+ done = true;
+ break;
+
+ case '#':
+ flags |= FLAG_BASE;
+ p++;
+ break;
+
+ case '0':
+ flags |= FLAG_PAD_ZERO;
p++;
break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ while (*p >= '0' && *p <= '9')
+ {
+ precision = precision * 10;
+ precision += *(p++) - '0';
+ }
+ break;
+
+ case 'l':
+ p++;
+ if (*p == 'l')
+ {
+ p++;
+ flags |= FLAG_LONGLONG;
+ }
+ else
+ flags |= FLAG_LONG;
+ break;
+
+ case 'o':
+ if (flags & FLAG_LONGLONG)
+ print_nr (putchar,
+ va_arg (ap, unsigned long long), 8,
+ precision, flags);
+ else if (flags & FLAG_LONG)
+ print_nr (putchar,
+ va_arg (ap, unsigned long), 8,
+ precision, flags);
+ else
+ print_nr (putchar,
+ va_arg (ap, unsigned int), 8, precision, flags);
+ p++;
+ done = true;
+ break;
+
case 'd':
case 'i':
- print_signed_nr (putchar, va_arg (ap, long long), 10);
+ if (flags & FLAG_LONGLONG)
+ print_signed_nr (putchar,
+ va_arg (ap, long long), 10,
+ precision, flags);
+ else if (flags & FLAG_LONG)
+ print_signed_nr (putchar,
+ va_arg (ap, long), 10,
+ precision, flags);
+ else
+ print_signed_nr (putchar,
+ va_arg (ap, int), 10, precision, flags);
p++;
+ done = true;
break;
-
- case 'x':
+
case 'X':
- print_nr (putchar, va_arg (ap, unsigned long long), 16);
+ flags |= FLAG_UPPERCASE;
+ /* Fall-through. */
+ case 'x':
+ if (flags & FLAG_LONGLONG)
+ print_nr (putchar,
+ va_arg (ap, unsigned long long), 16,
+ precision, flags);
+ else if (flags & FLAG_LONG)
+ print_nr (putchar,
+ va_arg (ap, unsigned long), 16,
+ precision, flags);
+ else
+ print_nr (putchar,
+ va_arg (ap, unsigned int), 16, precision, flags);
p++;
+ done = true;
break;
-
+
case 'u':
- print_nr (putchar, va_arg (ap, unsigned long long), 10);
+ if (flags & FLAG_LONGLONG)
+ print_nr (putchar,
+ va_arg (ap, unsigned long long), 10,
+ precision, flags);
+ else if (flags & FLAG_LONG)
+ print_nr (putchar,
+ va_arg (ap, unsigned long), 10,
+ precision, flags);
+ else
+ print_nr (putchar,
+ va_arg (ap, unsigned int), 10, precision, flags);
p++;
+ done = true;
break;
-
+
+ case 'c':
+ putchar (va_arg (ap, int));
+ p++;
+ done = true;
+ break;
+
+ case 's':
+ {
+ char *str = va_arg (ap, char *);
+ while (*str)
+ putchar (*(str++));
+ }
+ p++;
+ done = true;
+ break;
+
+ case 'P':
+ flags |= FLAG_UPPERCASE;
+ /* Fall-through. */
+ case 'p':
+ flags |= FLAG_BASE;
+ print_nr (putchar,
+ (uintptr_t) va_arg (ap, void *), 16,
+ precision, flags);
+ p++;
+ done = true;
+ break;
+
default:
putchar ('%');
- putchar ('l');
- putchar ('l');
- putchar (*(p++));
+ p++;
+ while (startp < p)
+ putchar (*(startp++));
+ done = true;
break;
}
- break;
-
- case 'o':
- print_nr (putchar, va_arg (ap, unsigned int), 8);
- p++;
- break;
-
- case 'd':
- case 'i':
- print_signed_nr (putchar, va_arg (ap, int), 10);
- p++;
- break;
-
- case 'x':
- case 'X':
- print_nr (putchar, va_arg (ap, unsigned int), 16);
- p++;
- break;
-
- case 'u':
- print_nr (putchar, va_arg (ap, unsigned int), 10);
- p++;
- break;
-
- case 'c':
- putchar (va_arg (ap, int));
- p++;
- break;
-
- case 's':
- {
- char *str = va_arg (ap, char *);
- if (str)
- while (*str)
- putchar (*(str++));
- else
- {
- putchar ('N');
- putchar ('U');
- putchar ('L');
- putchar ('L');
- }
- }
- p++;
- break;
-
- case 'p':
- print_nr (putchar, (unsigned int) va_arg (ap, void *), 16);
- p++;
- break;
-
- default:
- putchar ('%');
- putchar (*p);
- p++;
- break;
}
}