summaryrefslogtreecommitdiff
path: root/lib/printf.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/printf.c')
-rw-r--r--lib/printf.c92
1 files changed, 62 insertions, 30 deletions
diff --git a/lib/printf.c b/lib/printf.c
index 4fd75c9b..8e3cbbcf 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -118,16 +118,16 @@ static char * number(char * str, long num, int base, int size, int precision,
* @fmt: format string
* @args: a list of arguments to be formatted
*
- * This functions acts like ordinary sprintf() except that it checks
- * available space to avoid buffer overflows and it allows some more
- * format specifiers: |%I| for formatting of IP addresses (any non-zero
- * width is automatically replaced by standard IP address width which
- * depends on whether we use IPv4 or IPv6; |%#I| gives hexadecimal format),
- * |%R| for Router / Network ID (u32 value printed as IPv4 address)
- * |%lR| for 64bit Router / Network ID (u64 value printed as eight :-separated octets)
- * and |%m| resp. |%M| for error messages (uses strerror() to translate @errno code to
- * message text). On the other hand, it doesn't support floating
- * point numbers.
+ * This functions acts like ordinary sprintf() except that it checks available
+ * space to avoid buffer overflows and it allows some more format specifiers:
+ * |%I| for formatting of IP addresses (width of 1 is automatically replaced by
+ * standard IP address width which depends on whether we use IPv4 or IPv6; |%I4|
+ * or |%I6| can be used for explicit ip4_addr / ip6_addr arguments, |%N| for
+ * generic network addresses (net_addr *), |%R| for Router / Network ID (u32
+ * value printed as IPv4 address), |%lR| for 64bit Router / Network ID (u64
+ * value printed as eight :-separated octets) and |%m| resp. |%M| for error
+ * messages (uses strerror() to translate @errno code to message text). On the
+ * other hand, it doesn't support floating point numbers.
*
* Result: number of characters of the output string or -1 if
* the buffer space was insufficient.
@@ -141,7 +141,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
u64 X;
char *str, *start;
const char *s;
- char ipbuf[MAX(STD_ADDRESS_P_LENGTH,ROUTER_ID_64_LENGTH)+1];
+ char ipbuf[NET_MAX_TEXT_LENGTH+1];
struct iface *iface;
int flags; /* flags to number() */
@@ -158,7 +158,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
*str++ = *fmt;
continue;
}
-
+
/* process flags */
flags = 0;
repeat:
@@ -170,7 +170,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
-
+
/* get field width */
field_width = -1;
if (is_digit(*fmt))
@@ -188,7 +188,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
/* get the precision */
precision = -1;
if (*fmt == '.') {
- ++fmt;
+ ++fmt;
if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
@@ -238,6 +238,14 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
case 'M':
s = strerror(va_arg(args, int));
goto str;
+ case 'N': {
+ net_addr *n = va_arg(args, net_addr *);
+ if (field_width == 1)
+ field_width = net_max_text_length[n->type];
+ net_format(n, ipbuf, sizeof(ipbuf));
+ s = ipbuf;
+ goto str;
+ }
case 's':
s = va_arg(args, char *);
if (!s)
@@ -284,14 +292,35 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
/* IP address */
case 'I':
- if (flags & SPECIAL)
- ipa_ntox(va_arg(args, ip_addr), ipbuf);
- else {
- ipa_ntop(va_arg(args, ip_addr), ipbuf);
- if (field_width == 1)
- field_width = STD_ADDRESS_P_LENGTH;
+ if (fmt[1] == '4') {
+ /* Explicit IPv4 address */
+ ip4_addr a = va_arg(args, ip4_addr);
+ ip4_ntop(a, ipbuf);
+ i = IP4_MAX_TEXT_LENGTH;
+ fmt++;
+ } else if (fmt[1] == '6') {
+ /* Explicit IPv6 address */
+ ip6_addr a = va_arg(args, ip6_addr);
+ ip6_ntop(a, ipbuf);
+ i = IP6_MAX_TEXT_LENGTH;
+ fmt++;
+ } else {
+ /* Just IP address */
+ ip_addr a = va_arg(args, ip_addr);
+
+ if (ipa_is_ip4(a)) {
+ ip4_ntop(ipa_to_ip4(a), ipbuf);
+ i = IP4_MAX_TEXT_LENGTH;
+ } else {
+ ip6_ntop(ipa_to_ip6(a), ipbuf);
+ i = IP6_MAX_TEXT_LENGTH;
+ }
}
+
s = ipbuf;
+ if (field_width == 1)
+ field_width = i;
+
goto str;
/* Interface scope after link-local IP address */
@@ -311,7 +340,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
/* Router/Network ID - essentially IPv4 address in u32 value */
case 'R':
- if(qualifier == 'l') {
+ if (qualifier == 'l') {
X = va_arg(args, u64);
bsprintf(ipbuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
((X >> 56) & 0xff),
@@ -326,11 +355,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
else
{
x = va_arg(args, u32);
- bsprintf(ipbuf, "%d.%d.%d.%d",
- ((x >> 24) & 0xff),
- ((x >> 16) & 0xff),
- ((x >> 8) & 0xff),
- (x & 0xff));
+ ip4_ntop(ip4_from_u32(x), ipbuf);
}
s = ipbuf;
goto str;
@@ -442,6 +467,10 @@ int
buffer_vprint(buffer *buf, const char *fmt, va_list args)
{
int i = bvsnprintf((char *) buf->pos, buf->end - buf->pos, fmt, args);
+
+ if ((i < 0) && (buf->pos < buf->end))
+ *buf->pos = 0;
+
buf->pos = (i >= 0) ? (buf->pos + i) : buf->end;
return i;
}
@@ -453,9 +482,12 @@ buffer_print(buffer *buf, const char *fmt, ...)
int i;
va_start(args, fmt);
- i=bvsnprintf((char *) buf->pos, buf->end - buf->pos, fmt, args);
+ i = bvsnprintf((char *) buf->pos, buf->end - buf->pos, fmt, args);
va_end(args);
+ if ((i < 0) && (buf->pos < buf->end))
+ *buf->pos = 0;
+
buf->pos = (i >= 0) ? (buf->pos + i) : buf->end;
return i;
}
@@ -464,13 +496,13 @@ void
buffer_puts(buffer *buf, const char *str)
{
byte *bp = buf->pos;
- byte *be = buf->end;
+ byte *be = buf->end - 1;
while (bp < be && *str)
*bp++ = *str++;
- if (bp < be)
+ if (bp <= be)
*bp = 0;
- buf->pos = bp;
+ buf->pos = (bp < be) ? bp : buf->end;
}