Annotation of embedaddon/bird2/lib/printf.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD Library -- Formatted Output
! 3: *
! 4: * (c) 1991, 1992 Lars Wirzenius & Linus Torvalds
! 5: *
! 6: * Hacked up for BIRD by Martin Mares <mj@ucw.cz>
! 7: * Buffer size limitation implemented by Martin Mares.
! 8: */
! 9:
! 10: #include "nest/bird.h"
! 11: #include "string.h"
! 12:
! 13: #include <errno.h>
! 14:
! 15: #include "nest/iface.h"
! 16:
! 17: /* we use this so that we can do without the ctype library */
! 18: #define is_digit(c) ((c) >= '0' && (c) <= '9')
! 19:
! 20: static int skip_atoi(const char **s)
! 21: {
! 22: int i=0;
! 23:
! 24: while (is_digit(**s))
! 25: i = i*10 + *((*s)++) - '0';
! 26: return i;
! 27: }
! 28:
! 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' */
! 36:
! 37: static char * number(char * str, u64 num, uint base, int size, int precision,
! 38: int type, int remains)
! 39: {
! 40: char c,sign,tmp[66];
! 41: const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
! 42: int i;
! 43:
! 44: if (size >= 0 && (remains -= size) < 0)
! 45: return NULL;
! 46: if (type & LARGE)
! 47: digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
! 48: if (type & LEFT)
! 49: type &= ~ZEROPAD;
! 50: if (base < 2 || base > 36)
! 51: return 0;
! 52: c = (type & ZEROPAD) ? '0' : ' ';
! 53: sign = 0;
! 54: if (type & SIGN) {
! 55: if (num > (u64) INT64_MAX) {
! 56: sign = '-';
! 57: num = -num;
! 58: size--;
! 59: } else if (type & PLUS) {
! 60: sign = '+';
! 61: size--;
! 62: } else if (type & SPACE) {
! 63: sign = ' ';
! 64: size--;
! 65: }
! 66: }
! 67: if (type & SPECIAL) {
! 68: if (base == 16)
! 69: size -= 2;
! 70: else if (base == 8)
! 71: size--;
! 72: }
! 73: i = 0;
! 74: if (num == 0)
! 75: tmp[i++]='0';
! 76: else while (num != 0) {
! 77: uint res = num % base;
! 78: num = num / base;
! 79: tmp[i++] = digits[res];
! 80: }
! 81: if (i > precision)
! 82: precision = i;
! 83: size -= precision;
! 84: if (size < 0 && -size > remains)
! 85: return NULL;
! 86: if (!(type&(ZEROPAD+LEFT)))
! 87: while(size-->0)
! 88: *str++ = ' ';
! 89: if (sign)
! 90: *str++ = sign;
! 91: if (type & SPECIAL) {
! 92: if (base==8)
! 93: *str++ = '0';
! 94: else if (base==16) {
! 95: *str++ = '0';
! 96: *str++ = digits[33];
! 97: }
! 98: }
! 99: if (!(type & LEFT))
! 100: while (size-- > 0)
! 101: *str++ = c;
! 102: while (i < precision--)
! 103: *str++ = '0';
! 104: while (i-- > 0)
! 105: *str++ = tmp[i];
! 106: while (size-- > 0)
! 107: *str++ = ' ';
! 108: return str;
! 109: }
! 110:
! 111: /**
! 112: * bvsnprintf - BIRD's vsnprintf()
! 113: * @buf: destination buffer
! 114: * @size: size of the buffer
! 115: * @fmt: format string
! 116: * @args: a list of arguments to be formatted
! 117: *
! 118: * This functions acts like ordinary sprintf() except that it checks available
! 119: * space to avoid buffer overflows and it allows some more format specifiers:
! 120: * |%I| for formatting of IP addresses (width of 1 is automatically replaced by
! 121: * standard IP address width which depends on whether we use IPv4 or IPv6; |%I4|
! 122: * or |%I6| can be used for explicit ip4_addr / ip6_addr arguments, |%N| for
! 123: * generic network addresses (net_addr *), |%R| for Router / Network ID (u32
! 124: * value printed as IPv4 address), |%lR| for 64bit Router / Network ID (u64
! 125: * value printed as eight :-separated octets), |%t| for time values (btime) with
! 126: * specified subsecond precision, and |%m| resp. |%M| for error messages (uses
! 127: * strerror() to translate @errno code to message text). On the other hand, it
! 128: * doesn't support floating point numbers. The bvsnprintf() supports |%h| and
! 129: * |%l| qualifiers, but |%l| is used for s64/u64 instead of long/ulong.
! 130: *
! 131: * Result: number of characters of the output string or -1 if
! 132: * the buffer space was insufficient.
! 133: */
! 134: int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
! 135: {
! 136: int len, i;
! 137: u64 num;
! 138: uint base;
! 139: u32 x;
! 140: u64 X;
! 141: btime t;
! 142: s64 t1, t2;
! 143: char *str, *start;
! 144: const char *s;
! 145: char ipbuf[NET_MAX_TEXT_LENGTH+1];
! 146: struct iface *iface;
! 147:
! 148: int flags; /* flags to number() */
! 149:
! 150: int field_width; /* width of output field */
! 151: int precision; /* min. # of digits for integers; max
! 152: number of chars for from string */
! 153: int qualifier; /* 'h' or 'l' for integer fields */
! 154:
! 155: for (start=str=buf ; *fmt ; ++fmt, size-=(str-start), start=str) {
! 156: if (*fmt != '%') {
! 157: if (!size)
! 158: return -1;
! 159: *str++ = *fmt;
! 160: continue;
! 161: }
! 162:
! 163: /* process flags */
! 164: flags = 0;
! 165: repeat:
! 166: ++fmt; /* this also skips first '%' */
! 167: switch (*fmt) {
! 168: case '-': flags |= LEFT; goto repeat;
! 169: case '+': flags |= PLUS; goto repeat;
! 170: case ' ': flags |= SPACE; goto repeat;
! 171: case '#': flags |= SPECIAL; goto repeat;
! 172: case '0': flags |= ZEROPAD; goto repeat;
! 173: }
! 174:
! 175: /* get field width */
! 176: field_width = -1;
! 177: if (is_digit(*fmt))
! 178: field_width = skip_atoi(&fmt);
! 179: else if (*fmt == '*') {
! 180: ++fmt;
! 181: /* it's the next argument */
! 182: field_width = va_arg(args, int);
! 183: if (field_width < 0) {
! 184: field_width = -field_width;
! 185: flags |= LEFT;
! 186: }
! 187: }
! 188:
! 189: /* get the precision */
! 190: precision = -1;
! 191: if (*fmt == '.') {
! 192: ++fmt;
! 193: if (is_digit(*fmt))
! 194: precision = skip_atoi(&fmt);
! 195: else if (*fmt == '*') {
! 196: ++fmt;
! 197: /* it's the next argument */
! 198: precision = va_arg(args, int);
! 199: }
! 200: if (precision < 0)
! 201: precision = 0;
! 202: }
! 203:
! 204: /* get the conversion qualifier */
! 205: qualifier = -1;
! 206: if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
! 207: qualifier = *fmt;
! 208: ++fmt;
! 209: }
! 210:
! 211: /* default base */
! 212: base = 10;
! 213:
! 214: if (field_width > size)
! 215: return -1;
! 216: switch (*fmt) {
! 217: case 'c':
! 218: if (!(flags & LEFT))
! 219: while (--field_width > 0)
! 220: *str++ = ' ';
! 221: *str++ = (byte) va_arg(args, int);
! 222: while (--field_width > 0)
! 223: *str++ = ' ';
! 224: continue;
! 225:
! 226: case 'm':
! 227: if (flags & SPECIAL) {
! 228: if (!errno)
! 229: continue;
! 230: if (size < 2)
! 231: return -1;
! 232: *str++ = ':';
! 233: *str++ = ' ';
! 234: start += 2;
! 235: size -= 2;
! 236: }
! 237: s = strerror(errno);
! 238: goto str;
! 239: case 'M':
! 240: s = strerror(va_arg(args, int));
! 241: goto str;
! 242: case 'N': {
! 243: net_addr *n = va_arg(args, net_addr *);
! 244: if (field_width == 1)
! 245: field_width = net_max_text_length[n->type];
! 246: net_format(n, ipbuf, sizeof(ipbuf));
! 247: s = ipbuf;
! 248: goto str;
! 249: }
! 250: case 's':
! 251: s = va_arg(args, char *);
! 252: if (!s)
! 253: s = "<NULL>";
! 254:
! 255: str:
! 256: len = strlen(s);
! 257: if (precision >= 0 && len > precision)
! 258: len = precision;
! 259: if (len > size)
! 260: return -1;
! 261:
! 262: if (!(flags & LEFT))
! 263: while (len < field_width--)
! 264: *str++ = ' ';
! 265: for (i = 0; i < len; ++i)
! 266: *str++ = *s++;
! 267: while (len < field_width--)
! 268: *str++ = ' ';
! 269: continue;
! 270:
! 271: case 'V': {
! 272: const char *vfmt = va_arg(args, const char *);
! 273: va_list *vargs = va_arg(args, va_list *);
! 274: int res = bvsnprintf(str, size, vfmt, *vargs);
! 275: if (res < 0)
! 276: return -1;
! 277: str += res;
! 278: size -= res;
! 279: continue;
! 280: }
! 281:
! 282: case 'p':
! 283: if (field_width == -1) {
! 284: field_width = 2*sizeof(void *);
! 285: flags |= ZEROPAD;
! 286: }
! 287: str = number(str, (uintptr_t) va_arg(args, void *), 16,
! 288: field_width, precision, flags, size);
! 289: if (!str)
! 290: return -1;
! 291: continue;
! 292:
! 293: case 'n':
! 294: if (qualifier == 'l') {
! 295: s64 * ip = va_arg(args, s64 *);
! 296: *ip = (str - buf);
! 297: } else {
! 298: int * ip = va_arg(args, int *);
! 299: *ip = (str - buf);
! 300: }
! 301: continue;
! 302:
! 303: /* IP address */
! 304: case 'I':
! 305: if (fmt[1] == '4') {
! 306: /* Explicit IPv4 address */
! 307: ip4_addr a = va_arg(args, ip4_addr);
! 308: ip4_ntop(a, ipbuf);
! 309: i = IP4_MAX_TEXT_LENGTH;
! 310: fmt++;
! 311: } else if (fmt[1] == '6') {
! 312: /* Explicit IPv6 address */
! 313: ip6_addr a = va_arg(args, ip6_addr);
! 314: ip6_ntop(a, ipbuf);
! 315: i = IP6_MAX_TEXT_LENGTH;
! 316: fmt++;
! 317: } else {
! 318: /* Just IP address */
! 319: ip_addr a = va_arg(args, ip_addr);
! 320:
! 321: if (ipa_is_ip4(a)) {
! 322: ip4_ntop(ipa_to_ip4(a), ipbuf);
! 323: i = IP4_MAX_TEXT_LENGTH;
! 324: } else {
! 325: ip6_ntop(ipa_to_ip6(a), ipbuf);
! 326: i = IP6_MAX_TEXT_LENGTH;
! 327: }
! 328: }
! 329:
! 330: s = ipbuf;
! 331: if (field_width == 1)
! 332: field_width = i;
! 333:
! 334: goto str;
! 335:
! 336: /* Interface scope after link-local IP address */
! 337: case 'J':
! 338: iface = va_arg(args, struct iface *);
! 339: if (!iface)
! 340: continue;
! 341: if (!size)
! 342: return -1;
! 343:
! 344: *str++ = '%';
! 345: start++;
! 346: size--;
! 347:
! 348: s = iface->name;
! 349: goto str;
! 350:
! 351: /* Router/Network ID - essentially IPv4 address in u32 value */
! 352: case 'R':
! 353: if (qualifier == 'l') {
! 354: X = va_arg(args, u64);
! 355: bsprintf(ipbuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
! 356: (uint) ((X >> 56) & 0xff),
! 357: (uint) ((X >> 48) & 0xff),
! 358: (uint) ((X >> 40) & 0xff),
! 359: (uint) ((X >> 32) & 0xff),
! 360: (uint) ((X >> 24) & 0xff),
! 361: (uint) ((X >> 16) & 0xff),
! 362: (uint) ((X >> 8) & 0xff),
! 363: (uint) (X & 0xff));
! 364: }
! 365: else
! 366: {
! 367: x = va_arg(args, u32);
! 368: ip4_ntop(ip4_from_u32(x), ipbuf);
! 369: }
! 370: s = ipbuf;
! 371: goto str;
! 372:
! 373: case 't':
! 374: t = va_arg(args, btime);
! 375: t1 = t TO_S;
! 376: t2 = t - t1 S;
! 377:
! 378: if (precision < 0)
! 379: precision = 3;
! 380:
! 381: if (precision > 6)
! 382: precision = 6;
! 383:
! 384: /* Compute field_width for second part */
! 385: if ((precision > 0) && (field_width > 0))
! 386: field_width -= (1 + precision);
! 387:
! 388: if (field_width < 0)
! 389: field_width = 0;
! 390:
! 391: /* Print seconds */
! 392: flags |= SIGN;
! 393: str = number(str, (u64) t1, 10, field_width, 0, flags, size);
! 394: if (!str)
! 395: return -1;
! 396:
! 397: if (precision > 0)
! 398: {
! 399: size -= (str-start);
! 400: start = str;
! 401:
! 402: if ((1 + precision) > size)
! 403: return -1;
! 404:
! 405: /* Convert microseconds to requested precision */
! 406: for (i = precision; i < 6; i++)
! 407: t2 /= 10;
! 408:
! 409: /* Print sub-seconds */
! 410: *str++ = '.';
! 411: str = number(str, (u64) t2, 10, precision, 0, ZEROPAD, size - 1);
! 412: if (!str)
! 413: return -1;
! 414: }
! 415: goto done;
! 416:
! 417: /* integer number formats - set up the flags and "break" */
! 418: case 'o':
! 419: base = 8;
! 420: break;
! 421:
! 422: case 'X':
! 423: flags |= LARGE;
! 424: /* fallthrough */
! 425: case 'x':
! 426: base = 16;
! 427: break;
! 428:
! 429: case 'd':
! 430: case 'i':
! 431: flags |= SIGN;
! 432: case 'u':
! 433: break;
! 434:
! 435: default:
! 436: if (size < 2)
! 437: return -1;
! 438: if (*fmt != '%')
! 439: *str++ = '%';
! 440: if (*fmt)
! 441: *str++ = *fmt;
! 442: else
! 443: --fmt;
! 444: continue;
! 445: }
! 446: if (flags & SIGN) {
! 447: /* Conversions valid per ISO C99 6.3.1.3 (2) */
! 448: if (qualifier == 'l')
! 449: num = (u64) va_arg(args, s64);
! 450: else if (qualifier == 'h')
! 451: num = (u64) (short) va_arg(args, int);
! 452: else
! 453: num = (u64) va_arg(args, int);
! 454: } else {
! 455: if (qualifier == 'l')
! 456: num = va_arg(args, u64);
! 457: else if (qualifier == 'h')
! 458: num = (unsigned short) va_arg(args, int);
! 459: else
! 460: num = va_arg(args, uint);
! 461: }
! 462: str = number(str, num, base, field_width, precision, flags, size);
! 463: if (!str)
! 464: return -1;
! 465: done: ;
! 466: }
! 467: if (!size)
! 468: return -1;
! 469: *str = '\0';
! 470: return str-buf;
! 471: }
! 472:
! 473: /**
! 474: * bvsprintf - BIRD's vsprintf()
! 475: * @buf: buffer
! 476: * @fmt: format string
! 477: * @args: a list of arguments to be formatted
! 478: *
! 479: * This function is equivalent to bvsnprintf() with an infinite
! 480: * buffer size. Please use carefully only when you are absolutely
! 481: * sure the buffer won't overflow.
! 482: */
! 483: int bvsprintf(char *buf, const char *fmt, va_list args)
! 484: {
! 485: return bvsnprintf(buf, 1000000000, fmt, args);
! 486: }
! 487:
! 488: /**
! 489: * bsprintf - BIRD's sprintf()
! 490: * @buf: buffer
! 491: * @fmt: format string
! 492: *
! 493: * This function is equivalent to bvsnprintf() with an infinite
! 494: * buffer size and variable arguments instead of a &va_list.
! 495: * Please use carefully only when you are absolutely
! 496: * sure the buffer won't overflow.
! 497: */
! 498: int bsprintf(char * buf, const char *fmt, ...)
! 499: {
! 500: va_list args;
! 501: int i;
! 502:
! 503: va_start(args, fmt);
! 504: i=bvsnprintf(buf, 1000000000, fmt, args);
! 505: va_end(args);
! 506: return i;
! 507: }
! 508:
! 509: /**
! 510: * bsnprintf - BIRD's snprintf()
! 511: * @buf: buffer
! 512: * @size: buffer size
! 513: * @fmt: format string
! 514: *
! 515: * This function is equivalent to bsnprintf() with variable arguments instead of a &va_list.
! 516: */
! 517: int bsnprintf(char * buf, int size, const char *fmt, ...)
! 518: {
! 519: va_list args;
! 520: int i;
! 521:
! 522: va_start(args, fmt);
! 523: i=bvsnprintf(buf, size, fmt, args);
! 524: va_end(args);
! 525: return i;
! 526: }
! 527:
! 528: int
! 529: buffer_vprint(buffer *buf, const char *fmt, va_list args)
! 530: {
! 531: int i = bvsnprintf((char *) buf->pos, buf->end - buf->pos, fmt, args);
! 532:
! 533: if ((i < 0) && (buf->pos < buf->end))
! 534: *buf->pos = 0;
! 535:
! 536: buf->pos = (i >= 0) ? (buf->pos + i) : buf->end;
! 537: return i;
! 538: }
! 539:
! 540: int
! 541: buffer_print(buffer *buf, const char *fmt, ...)
! 542: {
! 543: va_list args;
! 544: int i;
! 545:
! 546: va_start(args, fmt);
! 547: i = bvsnprintf((char *) buf->pos, buf->end - buf->pos, fmt, args);
! 548: va_end(args);
! 549:
! 550: if ((i < 0) && (buf->pos < buf->end))
! 551: *buf->pos = 0;
! 552:
! 553: buf->pos = (i >= 0) ? (buf->pos + i) : buf->end;
! 554: return i;
! 555: }
! 556:
! 557: void
! 558: buffer_puts(buffer *buf, const char *str)
! 559: {
! 560: byte *bp = buf->pos;
! 561: byte *be = buf->end - 1;
! 562:
! 563: while (bp < be && *str)
! 564: *bp++ = *str++;
! 565:
! 566: if (bp <= be)
! 567: *bp = 0;
! 568:
! 569: buf->pos = (bp < be) ? bp : buf->end;
! 570: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>