LibC: fix bugs with printf
This commit is contained in:
		
							parent
							
								
									591d03de95
								
							
						
					
					
						commit
						8ec675cca6
					
				|  | @ -26,17 +26,14 @@ struct format_options_t | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template<BAN::integral T> | template<BAN::integral T> | ||||||
| static void integer_to_string(char* buffer, T value, int base, bool upper, const format_options_t options) | static void integer_to_string(char* buffer, T value, int base, bool upper, format_options_t options) | ||||||
| { | { | ||||||
| 	int width = 1; | 	int digits = 1; | ||||||
| 	bool zero_padded = options.zero_padded; |  | ||||||
| 	if (options.percision != -1) | 	if (options.percision != -1) | ||||||
| 	{ | 	{ | ||||||
| 		width = options.percision; | 		digits = options.percision; | ||||||
| 		zero_padded = false; | 		options.zero_padded = false; | ||||||
| 	} | 	} | ||||||
| 	else if (options.width != -1) |  | ||||||
| 		width = options.width; |  | ||||||
| 
 | 
 | ||||||
| 	auto digit_char = [](int digit, bool upper) | 	auto digit_char = [](int digit, bool upper) | ||||||
| 	{ | 	{ | ||||||
|  | @ -45,51 +42,57 @@ static void integer_to_string(char* buffer, T value, int base, bool upper, const | ||||||
| 		return (upper ? 'A' : 'a') + (digit - 10); | 		return (upper ? 'A' : 'a') + (digit - 10); | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	bool sign = false; |  | ||||||
| 	int offset = 0; | 	int offset = 0; | ||||||
| 	if (value < 0) | 
 | ||||||
|  | 	int prefix_length = 0; | ||||||
|  | 	char prefix[2] {}; | ||||||
|  | 	if constexpr(BAN::is_signed_v<T>) | ||||||
| 	{ | 	{ | ||||||
| 		sign = true; | 		prefix_length = 1; | ||||||
| 		buffer[offset++] = digit_char(-(value % base), upper); | 		if (value < 0) | ||||||
| 		value = -(value / base); | 		{ | ||||||
|  | 			prefix[0] = '-'; | ||||||
|  | 			buffer[offset++] = digit_char(-(value % base), upper); | ||||||
|  | 			value = -(value / base); | ||||||
|  | 		} | ||||||
|  | 		else if (options.show_plus_sign) | ||||||
|  | 			prefix[0] = '+'; | ||||||
|  | 		else if (options.show_plus_sign_as_space) | ||||||
|  | 			prefix[0] = ' '; | ||||||
|  | 		else | ||||||
|  | 			prefix_length = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 	else | ||||||
| 	if (value == 0 && width > 0) | 	{ | ||||||
| 		buffer[offset++] = '0'; | 		if (options.alternate_form && base == 8) | ||||||
| 
 | 		{ | ||||||
| 	while (value) | 			prefix_length = 1; | ||||||
|  | 			prefix[0] = '0'; | ||||||
|  | 		} | ||||||
|  | 		else if (options.alternate_form && base == 16) | ||||||
|  | 		{ | ||||||
|  | 			prefix_length = 2; | ||||||
|  | 			prefix[0] = '0'; | ||||||
|  | 			prefix[1] = 'x'; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	while (value || offset < digits) | ||||||
| 	{ | 	{ | ||||||
| 		buffer[offset++] = digit_char(value % base, upper); | 		buffer[offset++] = digit_char(value % base, upper); | ||||||
| 		value /= base; | 		value /= base; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	int prefix_length = 0; | 	if (options.zero_padded) | ||||||
| 
 |  | ||||||
| 	if (sign || options.show_plus_sign || options.show_plus_sign_as_space) |  | ||||||
| 		prefix_length++; |  | ||||||
| 	if (base == 8 && options.alternate_form) |  | ||||||
| 		prefix_length++; |  | ||||||
| 	if (base == 16 && options.alternate_form) |  | ||||||
| 		prefix_length += 2; |  | ||||||
| 
 |  | ||||||
| 	while (offset < width - prefix_length) |  | ||||||
| 		buffer[offset++] = (zero_padded ? '0' : ' '); |  | ||||||
| 
 |  | ||||||
| 	if (sign) |  | ||||||
| 		buffer[offset++] = '-'; |  | ||||||
| 	else if (options.show_plus_sign) |  | ||||||
| 		buffer[offset++] = '+'; |  | ||||||
| 	else if (options.show_plus_sign_as_space) |  | ||||||
| 		buffer[offset++] = ' '; |  | ||||||
| 
 |  | ||||||
| 	if (base == 8 && options.alternate_form) |  | ||||||
| 		buffer[offset++] = '0'; |  | ||||||
| 	if (base == 16 && options.alternate_form) |  | ||||||
| 	{ | 	{ | ||||||
| 		buffer[offset++] = 'x'; | 		int zeroes = options.width - prefix_length; | ||||||
| 		buffer[offset++] = '0'; | 		for (int i = offset; i < zeroes; i++) | ||||||
|  | 			buffer[offset++] = '0'; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (prefix[1]) buffer[offset++] = prefix[1]; | ||||||
|  | 	if (prefix[0]) buffer[offset++] = prefix[0]; | ||||||
|  | 
 | ||||||
| 	for (int i = 0; i < offset / 2; i++) | 	for (int i = 0; i < offset / 2; i++) | ||||||
| 	{ | 	{ | ||||||
| 		char temp = buffer[i]; | 		char temp = buffer[i]; | ||||||
|  | @ -273,6 +276,13 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun | ||||||
| 						format++; | 						format++; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | 				else if (*format == '-') | ||||||
|  | 				{ | ||||||
|  | 					percision = -1; | ||||||
|  | 					format++; | ||||||
|  | 					while (isdigit(*format)) | ||||||
|  | 						format++; | ||||||
|  | 				} | ||||||
| 				else if (*format == '*') | 				else if (*format == '*') | ||||||
| 				{ | 				{ | ||||||
| 					percision = va_arg(arguments, int); | 					percision = va_arg(arguments, int); | ||||||
|  |  | ||||||
|  | @ -476,7 +476,6 @@ int vprintf(const char* format, va_list arguments) | ||||||
| // TODO
 | // TODO
 | ||||||
| int vscanf(const char*, va_list); | int vscanf(const char*, va_list); | ||||||
| 
 | 
 | ||||||
| // TODO
 |  | ||||||
| int vsnprintf(char* buffer, size_t max_size, const char* format, va_list arguments) | int vsnprintf(char* buffer, size_t max_size, const char* format, va_list arguments) | ||||||
| { | { | ||||||
| 	if (buffer == nullptr) | 	if (buffer == nullptr) | ||||||
|  | @ -489,34 +488,44 @@ int vsnprintf(char* buffer, size_t max_size, const char* format, va_list argumen | ||||||
| 	}; | 	}; | ||||||
| 	print_info info { buffer, max_size }; | 	print_info info { buffer, max_size }; | ||||||
| 
 | 
 | ||||||
| 	return printf_impl(format, arguments, | 	int ret = printf_impl(format, arguments, | ||||||
| 		[](int c, void* _info) | 		[](int c, void* _info) | ||||||
| 		{ | 		{ | ||||||
| 			print_info* info = (print_info*)_info; | 			print_info* info = (print_info*)_info; | ||||||
| 			if (info->remaining) | 			if (info->remaining == 1) | ||||||
| 			{ | 			{ | ||||||
| 				*info->buffer = (info->remaining == 1 ? '\0' : c); | 				*info->buffer = '\0'; | ||||||
|  | 				info->remaining = 0; | ||||||
|  | 			} | ||||||
|  | 			else if (info->remaining) | ||||||
|  | 			{ | ||||||
|  | 				*info->buffer = c; | ||||||
| 				info->buffer++; | 				info->buffer++; | ||||||
| 				info->remaining--; | 				info->remaining--; | ||||||
| 			} | 			} | ||||||
| 			return 0; | 			return 0; | ||||||
| 		}, &info | 		}, &info | ||||||
| 	); | 	); | ||||||
|  | 
 | ||||||
|  | 	*info.buffer = '\0'; | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO
 |  | ||||||
| int vsprintf(char* buffer, const char* format, va_list arguments) | int vsprintf(char* buffer, const char* format, va_list arguments) | ||||||
| { | { | ||||||
| 	if (buffer == nullptr) | 	if (buffer == nullptr) | ||||||
| 		return printf_impl(format, arguments, [](int, void*) { return 0; }, nullptr); | 		return printf_impl(format, arguments, [](int, void*) { return 0; }, nullptr); | ||||||
| 	 | 	 | ||||||
| 	return printf_impl(format, arguments, | 	int ret = printf_impl(format, arguments, | ||||||
| 		[](int c, void* _buffer) | 		[](int c, void* _buffer) | ||||||
| 		{ | 		{ | ||||||
| 			*(*(char**)_buffer)++ = c; | 			*(*(char**)_buffer)++ = c; | ||||||
| 			return 0; | 			return 0; | ||||||
| 		}, &buffer | 		}, &buffer | ||||||
| 	); | 	); | ||||||
|  | 
 | ||||||
|  | 	*buffer = '\0'; | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO
 | // TODO
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue