]>
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 #include "nest/iface.h"
17 /* we use this so that we can do without the ctype library */
18 #define is_digit(c) ((c) >= '0' && (c) <= '9')
20 static int skip_atoi(const char **s
)
25 i
= i
*10 + *((*s
)++) - '0';
29 #define ZEROPAD 1 /* pad with zero */
30 #define SIGN 2 /* unsigned/signed long */
31 #define PLUS 4 /* show plus */
32 #define SPACE 8 /* space if plus */
33 #define LEFT 16 /* left justified */
34 #define SPECIAL 32 /* 0x */
35 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
37 #define do_div(n,base) ({ \
39 __res = ((unsigned long) n) % (unsigned) base; \
40 n = ((unsigned long) n) / (unsigned) base; \
43 static char * number(char * str
, long num
, int base
, int size
, int precision
,
44 int type
, int remains
)
47 const char *digits
="0123456789abcdefghijklmnopqrstuvwxyz";
50 if (size
>= 0 && (remains
-= size
) < 0)
53 digits
= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
56 if (base
< 2 || base
> 36)
58 c
= (type
& ZEROPAD
) ? '0' : ' ';
65 } else if (type
& PLUS
) {
68 } else if (type
& SPACE
) {
83 tmp
[i
++] = digits
[do_div(num
,base
)];
87 if (size
< 0 && -size
> remains
)
89 if (!(type
&(ZEROPAD
+LEFT
)))
105 while (i
< precision
--)
115 * bvsnprintf - BIRD's vsnprintf()
116 * @buf: destination buffer
117 * @size: size of the buffer
118 * @fmt: format string
119 * @args: a list of arguments to be formatted
121 * This functions acts like ordinary sprintf() except that it checks
122 * available space to avoid buffer overflows and it allows some more
123 * format specifiers: |%I| for formatting of IP addresses (any non-zero
124 * width is automatically replaced by standard IP address width which
125 * depends on whether we use IPv4 or IPv6; |%#I| gives hexadecimal format),
126 * |%R| for Router / Network ID (u32 value printed as IPv4 address)
127 * and |%m| resp. |%M| for error messages (uses strerror() to translate @errno code to
128 * message text). On the other hand, it doesn't support floating
131 * Result: number of characters of the output string or -1 if
132 * the buffer space was insufficient.
134 int bvsnprintf(char *buf
, int size
, const char *fmt
, va_list args
)
142 char ipbuf
[STD_ADDRESS_P_LENGTH
+1];
145 int flags
; /* flags to number() */
147 int field_width
; /* width of output field */
148 int precision
; /* min. # of digits for integers; max
149 number of chars for from string */
150 int qualifier
; /* 'h', 'l', or 'L' for integer fields */
152 for (start
=str
=buf
; *fmt
; ++fmt
, size
-=(str
-start
), start
=str
) {
163 ++fmt
; /* this also skips first '%' */
165 case '-': flags
|= LEFT
; goto repeat
;
166 case '+': flags
|= PLUS
; goto repeat
;
167 case ' ': flags
|= SPACE
; goto repeat
;
168 case '#': flags
|= SPECIAL
; goto repeat
;
169 case '0': flags
|= ZEROPAD
; goto repeat
;
172 /* get field width */
175 field_width
= skip_atoi(&fmt
);
176 else if (*fmt
== '*') {
178 /* it's the next argument */
179 field_width
= va_arg(args
, int);
180 if (field_width
< 0) {
181 field_width
= -field_width
;
186 /* get the precision */
191 precision
= skip_atoi(&fmt
);
192 else if (*fmt
== '*') {
194 /* it's the next argument */
195 precision
= va_arg(args
, int);
201 /* get the conversion qualifier */
203 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L') {
211 if (field_width
> size
)
216 while (--field_width
> 0)
218 *str
++ = (unsigned char) va_arg(args
, int);
219 while (--field_width
> 0)
224 if (flags
& SPECIAL
) {
237 s
= strerror(va_arg(args
, int));
240 s
= va_arg(args
, char *);
246 if (precision
>= 0 && len
> precision
)
252 while (len
< field_width
--)
254 for (i
= 0; i
< len
; ++i
)
256 while (len
< field_width
--)
261 if (field_width
== -1) {
262 field_width
= 2*sizeof(void *);
266 (unsigned long) va_arg(args
, void *), 16,
267 field_width
, precision
, flags
, size
);
274 if (qualifier
== 'l') {
275 long * ip
= va_arg(args
, long *);
278 int * ip
= va_arg(args
, int *);
286 ipa_ntox(va_arg(args
, ip_addr
), ipbuf
);
288 ipa_ntop(va_arg(args
, ip_addr
), ipbuf
);
289 if (field_width
== 1)
290 field_width
= STD_ADDRESS_P_LENGTH
;
295 /* Interface scope after link-local IP address */
297 iface
= va_arg(args
, struct iface
*);
310 /* Router/Network ID - essentially IPv4 address in u32 value */
312 x
= va_arg(args
, u32
);
313 bsprintf(ipbuf
, "%d.%d.%d.%d",
321 /* integer number formats - set up the flags and "break" */
349 if (qualifier
== 'l')
350 num
= va_arg(args
, unsigned long);
351 else if (qualifier
== 'h') {
352 num
= (unsigned short) va_arg(args
, int);
355 } else if (flags
& SIGN
)
356 num
= va_arg(args
, int);
358 num
= va_arg(args
, unsigned int);
359 str
= number(str
, num
, base
, field_width
, precision
, flags
, size
);
370 * bvsprintf - BIRD's vsprintf()
372 * @fmt: format string
373 * @args: a list of arguments to be formatted
375 * This function is equivalent to bvsnprintf() with an infinite
376 * buffer size. Please use carefully only when you are absolutely
377 * sure the buffer won't overflow.
379 int bvsprintf(char *buf
, const char *fmt
, va_list args
)
381 return bvsnprintf(buf
, 1000000000, fmt
, args
);
385 * bsprintf - BIRD's sprintf()
387 * @fmt: format string
389 * This function is equivalent to bvsnprintf() with an infinite
390 * buffer size and variable arguments instead of a &va_list.
391 * Please use carefully only when you are absolutely
392 * sure the buffer won't overflow.
394 int bsprintf(char * buf
, const char *fmt
, ...)
400 i
=bvsnprintf(buf
, 1000000000, fmt
, args
);
406 * bsnprintf - BIRD's snprintf()
409 * @fmt: format string
411 * This function is equivalent to bsnprintf() with variable arguments instead of a &va_list.
413 int bsnprintf(char * buf
, int size
, const char *fmt
, ...)
419 i
=bvsnprintf(buf
, size
, fmt
, args
);
425 buffer_vprint(buffer
*buf
, const char *fmt
, va_list args
)
427 int i
= bvsnprintf((char *) buf
->pos
, buf
->end
- buf
->pos
, fmt
, args
);
428 buf
->pos
= (i
>= 0) ? (buf
->pos
+ i
) : buf
->end
;
433 buffer_print(buffer
*buf
, const char *fmt
, ...)
439 i
=bvsnprintf((char *) buf
->pos
, buf
->end
- buf
->pos
, fmt
, args
);
442 buf
->pos
= (i
>= 0) ? (buf
->pos
+ i
) : buf
->end
;
447 buffer_puts(buffer
*buf
, const char *str
)
452 while (bp
< be
&& *str
)