]>
git.ipfire.org Git - thirdparty/bird.git/blob - lib/printf.c
2 * BIRD Library -- Formatted Output
4 * (c) 1991, 1992 Lars Wirzenius & Linus Torvalds
6 * Hacked up for BIRD by Martin Mares <mj@ucw.cz>
7 * Buffer size limitation implemented by Martin Mares.
10 #include "nest/bird.h"
15 /* we use this so that we can do without the ctype library */
16 #define is_digit(c) ((c) >= '0' && (c) <= '9')
18 static int skip_atoi(const char **s
)
23 i
= i
*10 + *((*s
)++) - '0';
27 #define ZEROPAD 1 /* pad with zero */
28 #define SIGN 2 /* unsigned/signed long */
29 #define PLUS 4 /* show plus */
30 #define SPACE 8 /* space if plus */
31 #define LEFT 16 /* left justified */
32 #define SPECIAL 32 /* 0x */
33 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
35 #define do_div(n,base) ({ \
37 __res = ((unsigned long) n) % (unsigned) base; \
38 n = ((unsigned long) n) / (unsigned) base; \
41 static char * number(char * str
, long num
, int base
, int size
, int precision
,
42 int type
, int remains
)
45 const char *digits
="0123456789abcdefghijklmnopqrstuvwxyz";
48 if (size
>= 0 && (remains
-= size
) < 0)
51 digits
= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
54 if (base
< 2 || base
> 36)
56 c
= (type
& ZEROPAD
) ? '0' : ' ';
63 } else if (type
& PLUS
) {
66 } else if (type
& SPACE
) {
81 tmp
[i
++] = digits
[do_div(num
,base
)];
85 if (size
< 0 && -size
> remains
)
87 if (!(type
&(ZEROPAD
+LEFT
)))
103 while (i
< precision
--)
113 * bvsnprintf - BIRD's vsnprintf()
114 * @buf: destination buffer
115 * @size: size of the buffer
116 * @fmt: format string
117 * @args: a list of arguments to be formatted
119 * This functions acts like ordinary sprintf() except that it checks
120 * available space to avoid buffer overflows and it allows some more
121 * format specifiers: |%I| for formatting of IP addresses (any non-zero
122 * width is automatically replaced by standard IP address width which
123 * depends on whether we use IPv4 or IPv6; |%#I| gives hexadecimal format),
124 * |%R| for Router / Network ID (u32 value printed as IPv4 address)
125 * and |%m| resp. |%M| for error messages (uses strerror() to translate @errno code to
126 * message text). On the other hand, it doesn't support floating
129 * Result: number of characters of the output string or -1 if
130 * the buffer space was insufficient.
132 int bvsnprintf(char *buf
, int size
, const char *fmt
, va_list args
)
140 char ipbuf
[STD_ADDRESS_P_LENGTH
+1];
142 int flags
; /* flags to number() */
144 int field_width
; /* width of output field */
145 int precision
; /* min. # of digits for integers; max
146 number of chars for from string */
147 int qualifier
; /* 'h', 'l', or 'L' for integer fields */
149 for (start
=str
=buf
; *fmt
; ++fmt
, size
-=(str
-start
), start
=str
) {
160 ++fmt
; /* this also skips first '%' */
162 case '-': flags
|= LEFT
; goto repeat
;
163 case '+': flags
|= PLUS
; goto repeat
;
164 case ' ': flags
|= SPACE
; goto repeat
;
165 case '#': flags
|= SPECIAL
; goto repeat
;
166 case '0': flags
|= ZEROPAD
; goto repeat
;
169 /* get field width */
172 field_width
= skip_atoi(&fmt
);
173 else if (*fmt
== '*') {
175 /* it's the next argument */
176 field_width
= va_arg(args
, int);
177 if (field_width
< 0) {
178 field_width
= -field_width
;
183 /* get the precision */
188 precision
= skip_atoi(&fmt
);
189 else if (*fmt
== '*') {
191 /* it's the next argument */
192 precision
= va_arg(args
, int);
198 /* get the conversion qualifier */
200 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L') {
208 if (field_width
> size
)
213 while (--field_width
> 0)
215 *str
++ = (unsigned char) va_arg(args
, int);
216 while (--field_width
> 0)
224 s
= strerror(va_arg(args
, int));
227 s
= va_arg(args
, char *);
233 if (precision
>= 0 && len
> precision
)
239 while (len
< field_width
--)
241 for (i
= 0; i
< len
; ++i
)
243 while (len
< field_width
--)
248 if (field_width
== -1) {
249 field_width
= 2*sizeof(void *);
253 (unsigned long) va_arg(args
, void *), 16,
254 field_width
, precision
, flags
, size
);
261 if (qualifier
== 'l') {
262 long * ip
= va_arg(args
, long *);
265 int * ip
= va_arg(args
, int *);
273 ip_ntox(va_arg(args
, ip_addr
), ipbuf
);
275 ip_ntop(va_arg(args
, ip_addr
), ipbuf
);
277 field_width
= STD_ADDRESS_P_LENGTH
;
282 /* Router/Network ID - essentially IPv4 address in u32 value */
284 x
= va_arg(args
, u32
);
285 bsprintf(ipbuf
, "%d.%d.%d.%d",
293 /* integer number formats - set up the flags and "break" */
321 if (qualifier
== 'l')
322 num
= va_arg(args
, unsigned long);
323 else if (qualifier
== 'h') {
324 num
= (unsigned short) va_arg(args
, int);
327 } else if (flags
& SIGN
)
328 num
= va_arg(args
, int);
330 num
= va_arg(args
, unsigned int);
331 str
= number(str
, num
, base
, field_width
, precision
, flags
, size
);
342 * bvsprintf - BIRD's vsprintf()
344 * @fmt: format string
345 * @args: a list of arguments to be formatted
347 * This function is equivalent to bvsnprintf() with an infinite
348 * buffer size. Please use carefully only when you are absolutely
349 * sure the buffer won't overflow.
351 int bvsprintf(char *buf
, const char *fmt
, va_list args
)
353 return bvsnprintf(buf
, 1000000000, fmt
, args
);
357 * bsprintf - BIRD's sprintf()
359 * @fmt: format string
361 * This function is equivalent to bvsnprintf() with an infinite
362 * buffer size and variable arguments instead of a &va_list.
363 * Please use carefully only when you are absolutely
364 * sure the buffer won't overflow.
366 int bsprintf(char * buf
, const char *fmt
, ...)
372 i
=bvsnprintf(buf
, 1000000000, fmt
, args
);
378 * bsnprintf - BIRD's snprintf()
381 * @fmt: format string
383 * This function is equivalent to bsnprintf() with variable arguments instead of a &va_list.
385 int bsnprintf(char * buf
, int size
, const char *fmt
, ...)
391 i
=bvsnprintf(buf
, size
, fmt
, args
);