[SLOF] [PATCH slof] libc: Port vsnprintf back from skiboot

Alexey Kardashevskiy aik at ozlabs.ru
Tue Dec 1 18:14:36 AEDT 2015


Since initial port from slof to skiboot, vsnprintf() has improved in
skiboot so let's port the improved version back.

Suggested-by: Thomas Huth <thuth at redhat.com>
Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>
---

btw the initial commit of it is a bit different from the current slof version.


---
 lib/libc/stdio/vsnprintf.c | 178 ++++++++++++++++++++++++++++++---------------
 1 file changed, 118 insertions(+), 60 deletions(-)

diff --git a/lib/libc/stdio/vsnprintf.c b/lib/libc/stdio/vsnprintf.c
index e78fb3d..96a48b9 100644
--- a/lib/libc/stdio/vsnprintf.c
+++ b/lib/libc/stdio/vsnprintf.c
@@ -10,72 +10,112 @@
  *     IBM Corporation - initial implementation
  *****************************************************************************/
 
+#include <stdbool.h>
 #include "stdio.h"
 #include "stdlib.h"
 #include "string.h"
+#include "ctype.h"
 
 const static unsigned long long convert[] = {
 	0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF,
 	0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL
 };
 
-
-
 static int
-print_itoa(char **buffer,unsigned long value, unsigned short int base)
+print_str_fill(char **buffer, size_t bufsize, char *sizec,
+					const char *str, char c)
 {
-	const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
-	static char sign = 0;
+	int i, sizei, len;
+	char *bstart = *buffer;
 
-	if(base <= 2 || base > 16)
-		return 0;
-
-	if(value < 0) {
-		sign = 1;
-		value *= -1;
-	}
-
-	if(value < base) {
-		if(sign) {
-			**buffer = '-';
+	sizei = strtoul(sizec, NULL, 10);
+	len = strlen(str);
+	if (sizei > len) {
+		for (i = 0;
+			(i < (sizei - len)) && ((*buffer - bstart) < bufsize);
+									i++) {
+			**buffer = c;
 			*buffer += 1;
-			sign = 0;
 		}
-		**buffer = zeichen[value];
-		*buffer += 1;
-	} else {
-		print_itoa(buffer, value / base, base);
-		**buffer = zeichen[(value % base)];
-		*buffer += 1;
 	}
+	return 1;
+}
 
+static int
+print_str(char **buffer, size_t bufsize, const char *str)
+{
+	char *bstart = *buffer;
+	int i;
+
+	for (i = 0; (i < strlen(str)) && ((*buffer - bstart) < bufsize); i++) {
+		**buffer = str[i];
+		*buffer += 1;
+	}
 	return 1;
 }
 
 
+
 static unsigned int
 print_intlen(unsigned long value, unsigned short int base)
 {
 	int i = 0;
 
-	while(value > 0) {
+	while (value > 0) {
 		value /= base;
 		i++;
 	}
-	if(i == 0) i = 1;
+	if (i == 0)
+		i = 1;
 	return i;
 }
 
+static int
+print_itoa(char **buffer, size_t bufsize, unsigned long value,
+					unsigned short base, bool upper)
+{
+	const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+	char c;
+	int i, len;
+
+	if(base <= 2 || base > 16)
+		return 0;
+
+	len = i = print_intlen(value, base);
+
+	/* Don't print to buffer if bufsize is not enough. */
+	if (len > bufsize)
+		return 0;
+
+	do {
+		c = zeichen[value % base];
+		if (upper)
+			c = toupper(c);
+
+		(*buffer)[--i] = c;
+		value /= base;
+	} while(value);
+
+	*buffer += len;
+
+	return 1;
+}
+
+
 
 static int
-print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int base, char c, int optlen)
+print_fill(char **buffer, size_t bufsize, char *sizec, unsigned long size,
+				unsigned short int base, char c, int optlen)
 {
 	int i, sizei, len;
+	char *bstart = *buffer;
 
 	sizei = strtoul(sizec, NULL, 10);
  	len = print_intlen(size, base) + optlen;
-	if(sizei > len) {
-		for(i = 0; i < (sizei - len); i++) {
+	if (sizei > len) {
+		for (i = 0;
+			(i < (sizei - len)) && ((*buffer - bstart) < bufsize);
+									i++) {
 			**buffer = c;
 			*buffer += 1;
 		}
@@ -86,17 +126,18 @@ print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int ba
 
 
 static int
-print_format(char **buffer, const char *format, void *var)
+print_format(char **buffer, size_t bufsize, const char *format, void *var)
 {
-	unsigned long start;
-	unsigned int i = 0, sizei = 0, len = 0, length_mod = sizeof(int);
+	char *start;
+	unsigned int i = 0, length_mod = sizeof(int);
 	unsigned long value = 0;
 	unsigned long signBit;
 	char *form, sizec[32];
 	char sign = ' ';
+	bool upper = false;
 
 	form  = (char *) format;
-	start = (unsigned long) *buffer;
+	start = *buffer;
 
 	form++;
 	if(*form == '0' || *form == '.') {
@@ -104,7 +145,7 @@ print_format(char **buffer, const char *format, void *var)
 		form++;
 	}
 
-	while(*form != '\0') {
+	while ((*form != '\0') && ((*buffer - start) < bufsize)) {
 		switch(*form) {
 			case 'u':
 			case 'd':
@@ -112,57 +153,59 @@ print_format(char **buffer, const char *format, void *var)
 				sizec[i] = '\0';
 				value = (unsigned long) var;
 				signBit = 0x1ULL << (length_mod * 8 - 1);
-				if (signBit & value) {
+				if ((*form != 'u') && (signBit & value)) {
 					**buffer = '-';
 					*buffer += 1;
 					value = (-(unsigned long)value) & convert[length_mod];
 				}
-				print_fill(buffer, sizec, value, 10, sign, 0);
-				print_itoa(buffer, value, 10);
+				print_fill(buffer, bufsize - (*buffer - start),
+						sizec, value, 10, sign, 0);
+				print_itoa(buffer, bufsize - (*buffer - start),
+							value, 10, upper);
 				break;
 			case 'X':
+				upper = true;
 			case 'x':
 				sizec[i] = '\0';
 				value = (unsigned long) var & convert[length_mod];
-				print_fill(buffer, sizec, value, 16, sign, 0);
-				print_itoa(buffer, value, 16);
+				print_fill(buffer, bufsize - (*buffer - start),
+						sizec, value, 16, sign, 0);
+				print_itoa(buffer, bufsize - (*buffer - start),
+							value, 16, upper);
 				break;
 			case 'O':
 			case 'o':
 				sizec[i] = '\0';
 				value = (long int) var & convert[length_mod];
-				print_fill(buffer, sizec, value, 8, sign, 0);
-				print_itoa(buffer, value, 8);
+				print_fill(buffer, bufsize - (*buffer - start),
+						sizec, value, 8, sign, 0);
+				print_itoa(buffer, bufsize - (*buffer - start),
+							value, 8, upper);
 				break;
 			case 'p':
 				sizec[i] = '\0';
-				print_fill(buffer, sizec, (unsigned long) var, 16, ' ', 2);
-				**buffer = '0';
-				*buffer += 1;	
-				**buffer = 'x';
-				*buffer += 1;
-				print_itoa(buffer,(unsigned long) var, 16);
+				print_fill(buffer, bufsize - (*buffer - start),
+					sizec, (unsigned long) var, 16, ' ', 2);
+				print_str(buffer, bufsize - (*buffer - start),
+									"0x");
+				print_itoa(buffer, bufsize - (*buffer - start),
+						(unsigned long) var, 16, upper);
 				break;
 			case 'c':
 				sizec[i] = '\0';
-				print_fill(buffer, sizec, 1, 10, ' ', 0);
+				print_fill(buffer, bufsize - (*buffer - start),
+							sizec, 1, 10, ' ', 0);
 				**buffer = (unsigned long) var;
 				*buffer += 1;
 				break;
 			case 's':
 				sizec[i] = '\0';
-				sizei = strtoul(sizec, NULL, 10);
-				len = strlen((char *) var);
-				if(sizei > len) {
-					for(i = 0; i < (sizei - len); i++) {
-						**buffer = ' ';
-						*buffer += 1;
-					}
-				}
-				for(i = 0; i < strlen((char *) var); i++) {
-					**buffer = ((char *) var)[i];
-					*buffer += 1;
-				}
+				print_str_fill(buffer,
+					bufsize - (*buffer - start), sizec,
+							(char *) var, ' ');
+
+				print_str(buffer, bufsize - (*buffer - start),
+								(char *) var);
 				break;
 			case 'l':
 				form++;
@@ -182,6 +225,9 @@ print_format(char **buffer, const char *format, void *var)
 					length_mod = sizeof(short int);
 				}
 				break;
+			case 'z':
+				length_mod = sizeof(size_t);
+				break;
 			default:
 				if(*form >= '0' && *form <= '9')
 					sizec[i++] = *form;
@@ -206,6 +252,16 @@ vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
 	bstart = buffer;
 	ptr = (char *) format;
 
+	/*
+	 * Return from here if size passed is zero, otherwise we would
+	 * overrun buffer while setting NULL character at the end.
+	 */
+	if (!buffer || !bufsize)
+		return 0;
+
+	/* Leave one space for NULL character */
+	bufsize--;
+
 	while(*ptr != '\0' && (buffer - bstart) < bufsize)
 	{
 		if(*ptr == '%') {
@@ -224,7 +280,9 @@ vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
 			if(*ptr == '%') {
 				*buffer++ = '%';
 			} else {
-				print_format(&buffer, formstr, va_arg(arg, void *));
+				print_format(&buffer,
+					bufsize - (buffer - bstart),
+					formstr, va_arg(arg, void *));
 			}
 			ptr++;
 		} else {
-- 
2.5.0.rc3



More information about the SLOF mailing list