LibC: Implement length modifiers to printf
This commit is contained in:
		
							parent
							
								
									c84b66d078
								
							
						
					
					
						commit
						1cd12b5f16
					
				|  | @ -15,6 +15,19 @@ | ||||||
| 		written++;								\ | 		written++;								\ | ||||||
| 	} while (false) | 	} while (false) | ||||||
| 
 | 
 | ||||||
|  | enum class length_t | ||||||
|  | { | ||||||
|  | 	none, | ||||||
|  | 	hh, | ||||||
|  | 	h, | ||||||
|  | 	l, | ||||||
|  | 	ll, | ||||||
|  | 	j, | ||||||
|  | 	z, | ||||||
|  | 	t, | ||||||
|  | 	L, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct format_options_t | struct format_options_t | ||||||
| { | { | ||||||
| 	bool alternate_form { false }; | 	bool alternate_form { false }; | ||||||
|  | @ -24,6 +37,7 @@ struct format_options_t | ||||||
| 	bool show_plus_sign { false }; | 	bool show_plus_sign { false }; | ||||||
| 	int width { -1 }; | 	int width { -1 }; | ||||||
| 	int percision { -1 }; | 	int percision { -1 }; | ||||||
|  | 	length_t length { length_t::none }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template<BAN::integral T> | template<BAN::integral T> | ||||||
|  | @ -308,45 +322,157 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun | ||||||
| 				options.percision = percision; | 				options.percision = percision; | ||||||
| 			} | 			} | ||||||
| 		 | 		 | ||||||
| 			// TODO: Lenght modifier
 | 			// PARSE LENGTH
 | ||||||
|  | 			if (*format == 'h') | ||||||
|  | 			{ | ||||||
|  | 				if (*(format + 1) == 'h') | ||||||
|  | 				{ | ||||||
|  | 					format++; | ||||||
|  | 					options.length = length_t::hh; | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 					options.length = length_t::h; | ||||||
|  | 			} | ||||||
|  | 			else if (*format == 'l') | ||||||
|  | 			{ | ||||||
|  | 				if (*(format + 1) == 'l') | ||||||
|  | 				{ | ||||||
|  | 					format++; | ||||||
|  | 					options.length = length_t::ll; | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 					options.length = length_t::l; | ||||||
|  | 			} | ||||||
|  | 			else if (*format == 'j') | ||||||
|  | 				options.length = length_t::j; | ||||||
|  | 			else if (*format == 'z') | ||||||
|  | 				options.length = length_t::z; | ||||||
|  | 			else if (*format == 't') | ||||||
|  | 				options.length = length_t::t; | ||||||
|  | 			else if (*format == 'L') | ||||||
|  | 				options.length = length_t::L; | ||||||
|  | 			else | ||||||
|  | 				format--; | ||||||
|  | 			format++; | ||||||
| 
 | 
 | ||||||
| 			char conversion[128]; | 			char conversion[128]; | ||||||
| 			const char* string = nullptr; | 			const char* string = nullptr; | ||||||
| 
 | 
 | ||||||
| 			int length = -1; | 			int length = -1; | ||||||
| 
 | 
 | ||||||
|  | #define PARSE_INT_CASE(length, type) \ | ||||||
|  | 	case length_t::length: integer_to_string<type>(conversion, va_arg(arguments, type), BASE_, UPPER_, options); break | ||||||
|  | 
 | ||||||
|  | #define PARSE_INT_CASE_CAST(length, cast, type) \ | ||||||
|  | 	case length_t::length: integer_to_string<cast>(conversion, va_arg(arguments, type), BASE_, UPPER_, options); break | ||||||
|  | 
 | ||||||
|  | #define PARSE_INT_DEFAULT(type) \ | ||||||
|  | 	default: integer_to_string<type>(conversion, va_arg(arguments, type), BASE_, UPPER_, options); break | ||||||
|  | 
 | ||||||
| 			switch (*format) | 			switch (*format) | ||||||
| 			{ | 			{ | ||||||
| 			case 'd': | 			case 'd': | ||||||
| 			case 'i': | 			case 'i': | ||||||
| 			{ | 			{ | ||||||
| 				int value = va_arg(arguments, int); | 				switch (options.length) | ||||||
| 				integer_to_string<int>(conversion, value, 10, false, options); | 				{ | ||||||
|  | #define BASE_ 10 | ||||||
|  | #define UPPER_ false | ||||||
|  | 					PARSE_INT_CASE_CAST(hh, signed char, int); | ||||||
|  | 					PARSE_INT_CASE_CAST(h, short, int); | ||||||
|  | 					PARSE_INT_CASE(l, long); | ||||||
|  | 					PARSE_INT_CASE(ll, long long); | ||||||
|  | 					PARSE_INT_CASE(j, intmax_t); | ||||||
|  | 					PARSE_INT_CASE(z, ssize_t); | ||||||
|  | 					PARSE_INT_CASE(t, ptrdiff_t); | ||||||
|  | 					PARSE_INT_DEFAULT(int); | ||||||
|  | #undef BASE_ | ||||||
|  | #undef UPPER_ | ||||||
|  | 				} | ||||||
| 				string = conversion; | 				string = conversion; | ||||||
| 				format++; | 				format++; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			case 'o': | 			case 'o': | ||||||
| 			{ | 			{ | ||||||
| 				unsigned int value = va_arg(arguments, unsigned int); | 				switch (options.length) | ||||||
| 				integer_to_string<unsigned int>(conversion, value, 8, false, options); | 				{ | ||||||
|  | #define BASE_ 8 | ||||||
|  | #define UPPER_ false | ||||||
|  | 					PARSE_INT_CASE_CAST(hh, unsigned char, unsigned int); | ||||||
|  | 					PARSE_INT_CASE_CAST(h, unsigned short, unsigned int); | ||||||
|  | 					PARSE_INT_CASE(l, unsigned long); | ||||||
|  | 					PARSE_INT_CASE(ll, unsigned long long); | ||||||
|  | 					PARSE_INT_CASE(j, uintmax_t); | ||||||
|  | 					PARSE_INT_CASE(z, size_t); | ||||||
|  | 					PARSE_INT_CASE(t, uintptr_t); | ||||||
|  | 					PARSE_INT_DEFAULT(unsigned int); | ||||||
|  | #undef BASE_ | ||||||
|  | #undef UPPER_ | ||||||
|  | 				} | ||||||
| 				string = conversion; | 				string = conversion; | ||||||
| 				format++; | 				format++; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			case 'u': | 			case 'u': | ||||||
| 			{ | 			{ | ||||||
| 				unsigned int value = va_arg(arguments, unsigned int); | 				switch (options.length) | ||||||
| 				integer_to_string<unsigned int>(conversion, value, 10, false, options); | 				{ | ||||||
|  | #define BASE_ 10 | ||||||
|  | #define UPPER_ false | ||||||
|  | 					PARSE_INT_CASE_CAST(hh, unsigned char, unsigned int); | ||||||
|  | 					PARSE_INT_CASE_CAST(h, unsigned short, unsigned int); | ||||||
|  | 					PARSE_INT_CASE(l, unsigned long); | ||||||
|  | 					PARSE_INT_CASE(ll, unsigned long long); | ||||||
|  | 					PARSE_INT_CASE(j, uintmax_t); | ||||||
|  | 					PARSE_INT_CASE(z, size_t); | ||||||
|  | 					PARSE_INT_CASE(t, uintptr_t); | ||||||
|  | 					PARSE_INT_DEFAULT(unsigned int); | ||||||
|  | #undef BASE_ | ||||||
|  | #undef UPPER_ | ||||||
|  | 				} | ||||||
| 				string = conversion; | 				string = conversion; | ||||||
| 				format++; | 				format++; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			case 'x': | 			case 'x': | ||||||
|  | 			{ | ||||||
|  | 				switch (options.length) | ||||||
|  | 				{ | ||||||
|  | #define BASE_ 16 | ||||||
|  | #define UPPER_ false | ||||||
|  | 					PARSE_INT_CASE_CAST(hh, unsigned char, unsigned int); | ||||||
|  | 					PARSE_INT_CASE_CAST(h, unsigned short, unsigned int); | ||||||
|  | 					PARSE_INT_CASE(l, unsigned long); | ||||||
|  | 					PARSE_INT_CASE(ll, unsigned long long); | ||||||
|  | 					PARSE_INT_CASE(j, uintmax_t); | ||||||
|  | 					PARSE_INT_CASE(z, size_t); | ||||||
|  | 					PARSE_INT_CASE(t, uintptr_t); | ||||||
|  | 					PARSE_INT_DEFAULT(unsigned int); | ||||||
|  | #undef BASE_ | ||||||
|  | #undef UPPER_ | ||||||
|  | 				} | ||||||
|  | 				string = conversion; | ||||||
|  | 				format++; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
| 			case 'X': | 			case 'X': | ||||||
| 			{ | 			{ | ||||||
| 				unsigned int value = va_arg(arguments, unsigned int); | 				switch (options.length) | ||||||
| 				integer_to_string<unsigned int>(conversion, value, 16, *format == 'X', options); | 				{ | ||||||
|  | #define BASE_ 16 | ||||||
|  | #define UPPER_ true | ||||||
|  | 					PARSE_INT_CASE_CAST(hh, unsigned char, unsigned int); | ||||||
|  | 					PARSE_INT_CASE_CAST(h, unsigned short, unsigned int); | ||||||
|  | 					PARSE_INT_CASE(l, unsigned long); | ||||||
|  | 					PARSE_INT_CASE(ll, unsigned long long); | ||||||
|  | 					PARSE_INT_CASE(j, uintmax_t); | ||||||
|  | 					PARSE_INT_CASE(z, size_t); | ||||||
|  | 					PARSE_INT_CASE(t, uintptr_t); | ||||||
|  | 					PARSE_INT_DEFAULT(unsigned int); | ||||||
|  | #undef BASE_ | ||||||
|  | #undef UPPER_ | ||||||
|  | 				} | ||||||
| 				string = conversion; | 				string = conversion; | ||||||
| 				format++; | 				format++; | ||||||
| 				break; | 				break; | ||||||
|  | @ -355,8 +481,11 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun | ||||||
| 			case 'e': | 			case 'e': | ||||||
| 			case 'E': | 			case 'E': | ||||||
| 			{ | 			{ | ||||||
| 				double value = va_arg(arguments, double); | 				switch (options.length) | ||||||
| 				floating_point_to_exponent_string<double>(conversion, value, *format == 'E', options); | 				{ | ||||||
|  | 					case length_t::L:	floating_point_to_exponent_string<long double>	(conversion, va_arg(arguments, long double),	*format == 'E', options); break; | ||||||
|  | 					default:			floating_point_to_exponent_string<double>		(conversion, va_arg(arguments, double),			*format == 'E', options); break; | ||||||
|  | 				} | ||||||
| 				string = conversion; | 				string = conversion; | ||||||
| 				format++; | 				format++; | ||||||
| 				break; | 				break; | ||||||
|  | @ -364,13 +493,15 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun | ||||||
| 			case 'f': | 			case 'f': | ||||||
| 			case 'F': | 			case 'F': | ||||||
| 			{ | 			{ | ||||||
| 				double value = va_arg(arguments, double); | 				switch (options.length) | ||||||
| 				floating_point_to_string<double>(conversion, value, *format == 'F', options); | 				{ | ||||||
|  | 					case length_t::L:	floating_point_to_string<long double>	(conversion, va_arg(arguments, long double),	*format == 'F', options); break; | ||||||
|  | 					default:			floating_point_to_string<double>		(conversion, va_arg(arguments, double),			*format == 'F', options); break; | ||||||
|  | 				} | ||||||
| 				string = conversion; | 				string = conversion; | ||||||
| 				format++; | 				format++; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| #endif |  | ||||||
| 			case 'g': | 			case 'g': | ||||||
| 			case 'G': | 			case 'G': | ||||||
| 				// TODO
 | 				// TODO
 | ||||||
|  | @ -379,6 +510,7 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun | ||||||
| 			case 'A': | 			case 'A': | ||||||
| 				// TODO
 | 				// TODO
 | ||||||
| 				break; | 				break; | ||||||
|  | #endif | ||||||
| 			case 'c': | 			case 'c': | ||||||
| 			{ | 			{ | ||||||
| 				conversion[0] = va_arg(arguments, int); | 				conversion[0] = va_arg(arguments, int); | ||||||
|  | @ -416,8 +548,17 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun | ||||||
| 			} | 			} | ||||||
| 			case 'n': | 			case 'n': | ||||||
| 			{ | 			{ | ||||||
| 				int* target = va_arg(arguments, int*); | 				switch (options.length) | ||||||
| 				*target = written; | 				{ | ||||||
|  | 					case length_t::hh:	*va_arg(arguments, signed char*)	= written; break; | ||||||
|  | 					case length_t::h:	*va_arg(arguments, short*)			= written; break; | ||||||
|  | 					case length_t::l:	*va_arg(arguments, long*)			= written; break; | ||||||
|  | 					case length_t::ll:	*va_arg(arguments, long long*)		= written; break; | ||||||
|  | 					case length_t::j:	*va_arg(arguments, intmax_t*)		= written; break; | ||||||
|  | 					case length_t::z:	*va_arg(arguments, ssize_t*)		= written; break; | ||||||
|  | 					case length_t::t:	*va_arg(arguments, ptrdiff_t*)		= written; break; | ||||||
|  | 					default:			*va_arg(arguments, int*)			= written; break; | ||||||
|  | 				} | ||||||
| 				format++; | 				format++; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue