File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / lib / printf.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Aug 22 12:33:54 2017 UTC (6 years, 10 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_3p0, v1_6_3, HEAD
bird 1.6.3

    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: #define do_div(n,base) ({ \
   38: int __res; \
   39: __res = ((unsigned long) n) % (unsigned) base; \
   40: n = ((unsigned long) n) / (unsigned) base; \
   41: __res; })
   42: 
   43: static char * number(char * str, long num, int base, int size, int precision,
   44: 	int type, int remains)
   45: {
   46: 	char c,sign,tmp[66];
   47: 	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
   48: 	int i;
   49: 
   50: 	if (size >= 0 && (remains -= size) < 0)
   51: 		return NULL;
   52: 	if (type & LARGE)
   53: 		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   54: 	if (type & LEFT)
   55: 		type &= ~ZEROPAD;
   56: 	if (base < 2 || base > 36)
   57: 		return 0;
   58: 	c = (type & ZEROPAD) ? '0' : ' ';
   59: 	sign = 0;
   60: 	if (type & SIGN) {
   61: 		if (num < 0) {
   62: 			sign = '-';
   63: 			num = -num;
   64: 			size--;
   65: 		} else if (type & PLUS) {
   66: 			sign = '+';
   67: 			size--;
   68: 		} else if (type & SPACE) {
   69: 			sign = ' ';
   70: 			size--;
   71: 		}
   72: 	}
   73: 	if (type & SPECIAL) {
   74: 		if (base == 16)
   75: 			size -= 2;
   76: 		else if (base == 8)
   77: 			size--;
   78: 	}
   79: 	i = 0;
   80: 	if (num == 0)
   81: 		tmp[i++]='0';
   82: 	else while (num != 0)
   83: 		tmp[i++] = digits[do_div(num,base)];
   84: 	if (i > precision)
   85: 		precision = i;
   86: 	size -= precision;
   87: 	if (size < 0 && -size > remains)
   88: 		return NULL;
   89: 	if (!(type&(ZEROPAD+LEFT)))
   90: 		while(size-->0)
   91: 			*str++ = ' ';
   92: 	if (sign)
   93: 		*str++ = sign;
   94: 	if (type & SPECIAL) {
   95: 		if (base==8)
   96: 			*str++ = '0';
   97: 		else if (base==16) {
   98: 			*str++ = '0';
   99: 			*str++ = digits[33];
  100: 		}
  101: 	}
  102: 	if (!(type & LEFT))
  103: 		while (size-- > 0)
  104: 			*str++ = c;
  105: 	while (i < precision--)
  106: 		*str++ = '0';
  107: 	while (i-- > 0)
  108: 		*str++ = tmp[i];
  109: 	while (size-- > 0)
  110: 		*str++ = ' ';
  111: 	return str;
  112: }
  113: 
  114: /**
  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
  120:  *
  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:  * |%lR| for 64bit Router / Network ID (u64 value printed as eight :-separated octets)
  128:  * and |%m| resp. |%M| for error messages (uses strerror() to translate @errno code to
  129:  * message text). On the other hand, it doesn't support floating
  130:  * point numbers.
  131:  *
  132:  * Result: number of characters of the output string or -1 if
  133:  * the buffer space was insufficient.
  134:  */
  135: int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
  136: {
  137: 	int len;
  138: 	unsigned long num;
  139: 	int i, base;
  140: 	u32 x;
  141: 	u64 X;
  142: 	char *str, *start;
  143: 	const char *s;
  144: 	char ipbuf[MAX(STD_ADDRESS_P_LENGTH,ROUTER_ID_64_LENGTH)+1];
  145: 	struct iface *iface;
  146: 
  147: 	int flags;		/* flags to number() */
  148: 
  149: 	int field_width;	/* width of output field */
  150: 	int precision;		/* min. # of digits for integers; max
  151: 				   number of chars for from string */
  152: 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
  153: 
  154: 	for (start=str=buf ; *fmt ; ++fmt, size-=(str-start), start=str) {
  155: 		if (*fmt != '%') {
  156: 			if (!size)
  157: 				return -1;
  158: 			*str++ = *fmt;
  159: 			continue;
  160: 		}
  161: 			
  162: 		/* process flags */
  163: 		flags = 0;
  164: 		repeat:
  165: 			++fmt;		/* this also skips first '%' */
  166: 			switch (*fmt) {
  167: 				case '-': flags |= LEFT; goto repeat;
  168: 				case '+': flags |= PLUS; goto repeat;
  169: 				case ' ': flags |= SPACE; goto repeat;
  170: 				case '#': flags |= SPECIAL; goto repeat;
  171: 				case '0': flags |= ZEROPAD; goto repeat;
  172: 			}
  173: 		
  174: 		/* get field width */
  175: 		field_width = -1;
  176: 		if (is_digit(*fmt))
  177: 			field_width = skip_atoi(&fmt);
  178: 		else if (*fmt == '*') {
  179: 			++fmt;
  180: 			/* it's the next argument */
  181: 			field_width = va_arg(args, int);
  182: 			if (field_width < 0) {
  183: 				field_width = -field_width;
  184: 				flags |= LEFT;
  185: 			}
  186: 		}
  187: 
  188: 		/* get the precision */
  189: 		precision = -1;
  190: 		if (*fmt == '.') {
  191: 			++fmt;	
  192: 			if (is_digit(*fmt))
  193: 				precision = skip_atoi(&fmt);
  194: 			else if (*fmt == '*') {
  195: 				++fmt;
  196: 				/* it's the next argument */
  197: 				precision = va_arg(args, int);
  198: 			}
  199: 			if (precision < 0)
  200: 				precision = 0;
  201: 		}
  202: 
  203: 		/* get the conversion qualifier */
  204: 		qualifier = -1;
  205: 		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
  206: 			qualifier = *fmt;
  207: 			++fmt;
  208: 		}
  209: 
  210: 		/* default base */
  211: 		base = 10;
  212: 
  213: 		if (field_width > size)
  214: 			return -1;
  215: 		switch (*fmt) {
  216: 		case 'c':
  217: 			if (!(flags & LEFT))
  218: 				while (--field_width > 0)
  219: 					*str++ = ' ';
  220: 			*str++ = (byte) va_arg(args, int);
  221: 			while (--field_width > 0)
  222: 				*str++ = ' ';
  223: 			continue;
  224: 
  225: 		case 'm':
  226: 			if (flags & SPECIAL) {
  227: 				if (!errno)
  228: 					continue;
  229: 				if (size < 2)
  230: 					return -1;
  231: 				*str++ = ':';
  232: 				*str++ = ' ';
  233: 				start += 2;
  234: 				size -= 2;
  235: 			}
  236: 			s = strerror(errno);
  237: 			goto str;
  238: 		case 'M':
  239: 			s = strerror(va_arg(args, int));
  240: 			goto str;
  241: 		case 's':
  242: 			s = va_arg(args, char *);
  243: 			if (!s)
  244: 				s = "<NULL>";
  245: 
  246: 		str:
  247: 			len = strlen(s);
  248: 			if (precision >= 0 && len > precision)
  249: 				len = precision;
  250: 			if (len > size)
  251: 				return -1;
  252: 
  253: 			if (!(flags & LEFT))
  254: 				while (len < field_width--)
  255: 					*str++ = ' ';
  256: 			for (i = 0; i < len; ++i)
  257: 				*str++ = *s++;
  258: 			while (len < field_width--)
  259: 				*str++ = ' ';
  260: 			continue;
  261: 
  262: 		case 'p':
  263: 			if (field_width == -1) {
  264: 				field_width = 2*sizeof(void *);
  265: 				flags |= ZEROPAD;
  266: 			}
  267: 			str = number(str,
  268: 				(unsigned long) va_arg(args, void *), 16,
  269: 				field_width, precision, flags, size);
  270: 			if (!str)
  271: 				return -1;
  272: 			continue;
  273: 
  274: 
  275: 		case 'n':
  276: 			if (qualifier == 'l') {
  277: 				long * ip = va_arg(args, long *);
  278: 				*ip = (str - buf);
  279: 			} else {
  280: 				int * ip = va_arg(args, int *);
  281: 				*ip = (str - buf);
  282: 			}
  283: 			continue;
  284: 
  285: 		/* IP address */
  286: 		case 'I':
  287: 			if (flags & SPECIAL)
  288: 				ipa_ntox(va_arg(args, ip_addr), ipbuf);
  289: 			else {
  290: 				ipa_ntop(va_arg(args, ip_addr), ipbuf);
  291: 				if (field_width == 1)
  292: 					field_width = STD_ADDRESS_P_LENGTH;
  293: 			}
  294: 			s = ipbuf;
  295: 			goto str;
  296: 
  297: 		/* Interface scope after link-local IP address */
  298: 		case 'J':
  299: 			iface = va_arg(args, struct iface *);
  300: 			if (!iface)
  301: 				continue;
  302: 			if (!size)
  303: 				return -1;
  304: 
  305: 			*str++ = '%';
  306: 			start++;
  307: 			size--;
  308: 
  309: 			s = iface->name;
  310: 			goto str;
  311: 
  312: 		/* Router/Network ID - essentially IPv4 address in u32 value */
  313: 		case 'R':
  314: 			if(qualifier == 'l') {
  315: 				X = va_arg(args, u64);
  316: 				bsprintf(ipbuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
  317: 					((X >> 56) & 0xff),
  318: 					((X >> 48) & 0xff),
  319: 					((X >> 40) & 0xff),
  320: 					((X >> 32) & 0xff),
  321: 					((X >> 24) & 0xff),
  322: 					((X >> 16) & 0xff),
  323: 					((X >> 8) & 0xff),
  324: 					(X & 0xff));
  325: 			}
  326: 			else
  327: 			{
  328: 				x = va_arg(args, u32);
  329: 				bsprintf(ipbuf, "%d.%d.%d.%d",
  330: 					((x >> 24) & 0xff),
  331: 					((x >> 16) & 0xff),
  332: 					((x >> 8) & 0xff),
  333: 					(x & 0xff));
  334: 			}
  335: 			s = ipbuf;
  336: 			goto str;
  337: 
  338: 		/* integer number formats - set up the flags and "break" */
  339: 		case 'o':
  340: 			base = 8;
  341: 			break;
  342: 
  343: 		case 'X':
  344: 			flags |= LARGE;
  345: 		case 'x':
  346: 			base = 16;
  347: 			break;
  348: 
  349: 		case 'd':
  350: 		case 'i':
  351: 			flags |= SIGN;
  352: 		case 'u':
  353: 			break;
  354: 
  355: 		default:
  356: 			if (size < 2)
  357: 				return -1;
  358: 			if (*fmt != '%')
  359: 				*str++ = '%';
  360: 			if (*fmt)
  361: 				*str++ = *fmt;
  362: 			else
  363: 				--fmt;
  364: 			continue;
  365: 		}
  366: 		if (qualifier == 'l')
  367: 			num = va_arg(args, unsigned long);
  368: 		else if (qualifier == 'h') {
  369: 			num = (unsigned short) va_arg(args, int);
  370: 			if (flags & SIGN)
  371: 				num = (short) num;
  372: 		} else if (flags & SIGN)
  373: 			num = va_arg(args, int);
  374: 		else
  375: 			num = va_arg(args, uint);
  376: 		str = number(str, num, base, field_width, precision, flags, size);
  377: 		if (!str)
  378: 			return -1;
  379: 	}
  380: 	if (!size)
  381: 		return -1;
  382: 	*str = '\0';
  383: 	return str-buf;
  384: }
  385: 
  386: /**
  387:  * bvsprintf - BIRD's vsprintf()
  388:  * @buf: buffer
  389:  * @fmt: format string
  390:  * @args: a list of arguments to be formatted
  391:  *
  392:  * This function is equivalent to bvsnprintf() with an infinite
  393:  * buffer size. Please use carefully only when you are absolutely
  394:  * sure the buffer won't overflow.
  395:  */
  396: int bvsprintf(char *buf, const char *fmt, va_list args)
  397: {
  398:   return bvsnprintf(buf, 1000000000, fmt, args);
  399: }
  400: 
  401: /**
  402:  * bsprintf - BIRD's sprintf()
  403:  * @buf: buffer
  404:  * @fmt: format string
  405:  *
  406:  * This function is equivalent to bvsnprintf() with an infinite
  407:  * buffer size and variable arguments instead of a &va_list.
  408:  * Please use carefully only when you are absolutely
  409:  * sure the buffer won't overflow.
  410:  */
  411: int bsprintf(char * buf, const char *fmt, ...)
  412: {
  413:   va_list args;
  414:   int i;
  415: 
  416:   va_start(args, fmt);
  417:   i=bvsnprintf(buf, 1000000000, fmt, args);
  418:   va_end(args);
  419:   return i;
  420: }
  421: 
  422: /**
  423:  * bsnprintf - BIRD's snprintf()
  424:  * @buf: buffer
  425:  * @size: buffer size
  426:  * @fmt: format string
  427:  *
  428:  * This function is equivalent to bsnprintf() with variable arguments instead of a &va_list.
  429:  */
  430: int bsnprintf(char * buf, int size, const char *fmt, ...)
  431: {
  432:   va_list args;
  433:   int i;
  434: 
  435:   va_start(args, fmt);
  436:   i=bvsnprintf(buf, size, fmt, args);
  437:   va_end(args);
  438:   return i;
  439: }
  440: 
  441: int
  442: buffer_vprint(buffer *buf, const char *fmt, va_list args)
  443: {
  444:   int i = bvsnprintf((char *) buf->pos, buf->end - buf->pos, fmt, args);
  445:   buf->pos = (i >= 0) ? (buf->pos + i) : buf->end;
  446:   return i;
  447: }
  448: 
  449: int
  450: buffer_print(buffer *buf, const char *fmt, ...)
  451: {
  452:   va_list args;
  453:   int i;
  454: 
  455:   va_start(args, fmt);
  456:   i=bvsnprintf((char *) buf->pos, buf->end - buf->pos, fmt, args);
  457:   va_end(args);
  458: 
  459:   buf->pos = (i >= 0) ? (buf->pos + i) : buf->end;
  460:   return i;
  461: }
  462: 
  463: void
  464: buffer_puts(buffer *buf, const char *str)
  465: {
  466:   byte *bp = buf->pos;
  467:   byte *be = buf->end;
  468: 
  469:   while (bp < be && *str)
  470:     *bp++ = *str++;
  471: 
  472:   if (bp < be)
  473:     *bp = 0;
  474: 
  475:   buf->pos = bp;
  476: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>