@@ -38,7 +38,7 @@ static U clamp_to_range(T value, U min, U max) {
3838// / @param base The base to parse the number in
3939// / @return The index at the exclusive end of the number
4040template <typename T>
41- static unsigned long print_number (unsigned long start, char buffer[], T num, unsigned int base) {
41+ static unsigned long print_number (unsigned long start, char buffer[], T num, unsigned int base, unsigned int width = 0 , bool leading_zero = false , bool uppercase = false , bool is_negative = false ) {
4242 // the digits cover base 2, base 8 (don't use) base 10, base 12, base 16 and base 64
4343 static constexpr char const *const digits =
4444 " 0123456789abcdef"
@@ -49,72 +49,72 @@ static unsigned long print_number(unsigned long start, char buffer[], T num, uns
4949 unsigned long offset = 0 ;
5050 char backwards_digits[digit_places_limit]; // hold the value temporarily
5151
52- if (base == base2) {
53- if (num < 0b10 ) {
54- buffer[start] = digits[num];
55- return start + 1 ;
56- } else {
52+ if (num == 0 ) {
53+ backwards_digits[offset++] = ' 0' ;
54+ } else {
55+ if (base == base2) {
5756 while (num != 0 ) {
58- backwards_digits[offset] = digits[num & 1 ];
59- offset++;
57+ backwards_digits[offset++] = digits[num & 1 ];
6058 num >>= 1 ;
6159 }
62- }
63- }
64- if (base == base8) {
65- if (num < 8 ) {
66- buffer[start] = digits[num];
67- return start + 1 ;
68- } else {
60+ } else if (base == base8) {
6961 while (num != 0 ) {
70- backwards_digits[offset] = digits[num & 7 ];
71- offset++;
62+ backwards_digits[offset++] = digits[num & 7 ];
7263 num >>= 3 ;
7364 }
74- }
75- }
76- if (base == base10) {
77- if (num < 10 ) {
78- buffer[start] = digits[num];
79- return start + 1 ;
80- } else {
65+ } else if (base == base10) {
8166 while (num != 0 ) {
82- backwards_digits[offset] = digits[num % 10 ];
83- offset++;
67+ backwards_digits[offset++] = digits[num % 10 ];
8468 num /= 10 ;
8569 }
86- }
87- }
88- if (base == base16) {
89- if (num < 0x10 ) {
90- buffer[start] = digits[num];
91- return start + 1 ;
92- } else {
70+ } else if (base == base16) {
9371 while (num != 0 ) {
94- backwards_digits[offset] = digits[num & 0xF ];
95- offset++;
72+ char d = digits[num & 0xF ];
73+ if (uppercase && d >= ' a' && d <= ' z' ) {
74+ d = d - ' a' + ' A' ;
75+ }
76+ backwards_digits[offset++] = d;
9677 num >>= 4 ;
9778 }
98- }
99- }
100- if (base == base64) {
101- if (num < 0x40 ) {
102- buffer[start] = digits[num];
103- return start + 1 ;
104- } else {
79+ } else if (base == base64) {
10580 while (num != 0 ) {
106- backwards_digits[offset] = digits[num & 0x3F ];
107- offset++;
81+ backwards_digits[offset++] = digits[num & 0x3F ];
10882 num >>= 6 ;
10983 }
11084 }
11185 }
112- if (offset > 0 ) {
113- for (unsigned int i = 0 ; i < offset; i++) {
114- buffer[start + i] = backwards_digits[offset - i - 1 ];
86+
87+ // Determine how many characters we will print before padding
88+ unsigned int total_chars = static_cast <unsigned int >(offset) + (is_negative ? 1U : 0U );
89+ unsigned long current = start;
90+
91+ // Space padding (leading_zero = false) goes before the sign
92+ if (!leading_zero && width > total_chars) {
93+ unsigned int padding = width - total_chars;
94+ for (unsigned int i = 0 ; i < padding; i++) {
95+ buffer[current++] = ' ' ;
96+ }
97+ }
98+
99+ // Print the sign if negative
100+ if (is_negative) {
101+ buffer[current++] = ' -' ;
102+ }
103+
104+ // Zero padding (leading_zero = true) goes after the sign
105+ if (leading_zero && width > total_chars) {
106+ unsigned int padding = width - total_chars;
107+ for (unsigned int i = 0 ; i < padding; i++) {
108+ buffer[current++] = ' 0' ;
115109 }
116110 }
117- return start + offset;
111+
112+ // Print the digits in correct order (reverse of backwards_digits)
113+ for (unsigned int i = 0 ; i < offset; i++) {
114+ buffer[current++] = backwards_digits[offset - i - 1 ];
115+ }
116+
117+ return current;
118118}
119119
120120// / @brief Parses the number and prints it in the specified base in the buffer
@@ -125,12 +125,13 @@ static unsigned long print_number(unsigned long start, char buffer[], T num, uns
125125// / @param base The base to parse the number in
126126// / @return The index at the exclusive end of the number
127127template <typename T>
128- static unsigned long print_signed_number (unsigned long start, char buffer[], T num, unsigned int base) {
128+ static unsigned long print_signed_number (unsigned long start, char buffer[], T num, unsigned int base, unsigned int width = 0 , bool leading_zero = false ) {
129129 if (num < 0 ) {
130- buffer[start] = ' -' ;
131- return print_number (start + 1 , buffer, -num, base);
130+ // Safe absolute value conversion using uint64_t to avoid signed integer overflow on INT_MIN
131+ uint64_t abs_val = static_cast <uint64_t >(-static_cast <int64_t >(num));
132+ return print_number (start, buffer, abs_val, base, width, leading_zero, false , true );
132133 } else {
133- return print_number (start, buffer, num, base);
134+ return print_number (start, buffer, static_cast < uint64_t >( num) , base, width, leading_zero, false , false );
134135 }
135136}
136137
@@ -145,6 +146,25 @@ unsigned long vsnprint(char buffer[], size_t buffer_size, const char *format, va
145146 if (*format == ' %' ) {
146147 format++;
147148
149+ // Handle leading zero modifier
150+ bool leading_zero = false ;
151+ if (*format == ' 0' ) {
152+ leading_zero = true ;
153+ format++;
154+ }
155+
156+ // Handle width modifier
157+ unsigned int width = 0 ;
158+ if (is_digit (*format)) {
159+ while (is_digit (*format)) {
160+ width = width * 10U + static_cast <unsigned int >(*format - ' 0' );
161+ format++;
162+ }
163+ if (width > digit_places_limit) {
164+ width = digit_places_limit;
165+ }
166+ }
167+
148168 // Handle %l modifiers
149169 bool longlong_modifier = false ;
150170 bool long_modifier = false ;
@@ -177,27 +197,6 @@ unsigned long vsnprint(char buffer[], size_t buffer_size, const char *format, va
177197 format++;
178198 }
179199
180- // Handle leading zero modifier
181- // bool leading_zero = false;
182- // if (*format == '0') {
183- // leading_zero = true;
184- // format++;
185- // }
186- // bool specific_digits = false;
187- // if (is_digit(*format)) {
188- // specific_digits = true;
189- // unsigned int digits = 0;
190- // while (is_digit(*format)) {
191- // digits = digits * 10 + (*format - '0');
192- // format++;
193- // }
194- // if (digits > digit_places_limit) {
195- // digits = digit_places_limit;
196- // }
197- // }
198- // (void)leading_zero; // @TODO unused
199- // (void)specific_digits; // @TODO unused
200-
201200 switch (*format) {
202201 case ' s' : {
203202 const char *str = va_arg (args, const char *);
@@ -212,78 +211,99 @@ unsigned long vsnprint(char buffer[], size_t buffer_size, const char *format, va
212211 if (longlong_modifier) {
213212 int64_t num = va_arg (args, int64_t );
214213 num = clamp_to_range (num, std::numeric_limits<int64_t >::min (), std::numeric_limits<int64_t >::max ());
215- index = print_signed_number (index, buffer, num, base10);
214+ index = print_signed_number (index, buffer, num, base10, width, leading_zero );
216215 } else if (long_modifier) {
217216 int32_t num = va_arg (args, int32_t );
218217 num = clamp_to_range (num, std::numeric_limits<int32_t >::min (), std::numeric_limits<int32_t >::max ());
219- index = print_signed_number (index, buffer, num, base10);
218+ index = print_signed_number (index, buffer, num, base10, width, leading_zero );
220219 } else if (half_modifier) {
221220 int value = static_cast <int16_t >(va_arg (args, int ));
222221 int16_t num = clamp_to_range (value, std::numeric_limits<int16_t >::min (), std::numeric_limits<int16_t >::max ());
223- index = print_signed_number (index, buffer, num, base10);
222+ index = print_signed_number (index, buffer, num, base10, width, leading_zero );
224223 } else if (halfhalf_modifier) {
225224 int value = va_arg (args, int );
226225 int8_t num = clamp_to_range (value, std::numeric_limits<int8_t >::min (), std::numeric_limits<int8_t >::max ());
227- index = print_signed_number (index, buffer, num, base10);
228- // } else if (size_modifier) {
229- // ssize_t value = va_arg(args, ssize_t);
230- // num = clamp_to_range(value, std::numeric_limits<ssize_t>::min(), std::numeric_limits<ssize_t>::max());
231- // index = print_signed_number(index, buffer, num, base10);
226+ index = print_signed_number (index, buffer, num, base10, width, leading_zero);
232227 } else {
233228 auto num = va_arg (args, int );
234- index = print_signed_number (index, buffer, num, base10);
229+ index = print_signed_number (index, buffer, num, base10, width, leading_zero );
235230 }
236231 break ;
237232 }
238233 case ' u' : {
239234 if (longlong_modifier) {
240235 uint64_t num = va_arg (args, uint64_t );
241236 num = clamp_to_range (num, std::numeric_limits<uint64_t >::min (), std::numeric_limits<uint64_t >::max ());
242- index = print_number (index, buffer, num, base10);
237+ index = print_number (index, buffer, num, base10, width, leading_zero );
243238 } else if (long_modifier) {
244239 uint32_t num = va_arg (args, uint32_t );
245240 num = clamp_to_range (num, std::numeric_limits<uint32_t >::min (), std::numeric_limits<uint32_t >::max ());
246- index = print_number (index, buffer, num, base10);
241+ index = print_number (index, buffer, num, base10, width, leading_zero );
247242 } else if (half_modifier) {
248243 unsigned int value = va_arg (args, unsigned int );
249244 uint16_t num = clamp_to_range (value, std::numeric_limits<uint16_t >::min (), std::numeric_limits<uint16_t >::max ());
250- index = print_number (index, buffer, num, base10);
245+ index = print_number (index, buffer, num, base10, width, leading_zero );
251246 } else if (halfhalf_modifier) {
252247 unsigned int value = va_arg (args, unsigned int );
253248 uint8_t num = clamp_to_range (value, std::numeric_limits<uint8_t >::min (), std::numeric_limits<uint8_t >::max ());
254- index = print_number (index, buffer, num, base10);
249+ index = print_number (index, buffer, num, base10, width, leading_zero );
255250 } else if (size_modifier) {
256251 size_t num = va_arg (args, size_t );
257- index = print_number (index, buffer, num, base10);
252+ index = print_number (index, buffer, num, base10, width, leading_zero );
258253 } else {
259254 unsigned int num = va_arg (args, unsigned int );
260- index = print_number (index, buffer, num, base10);
255+ index = print_number (index, buffer, num, base10, width, leading_zero );
261256 }
262257 break ;
263258 }
264259 case ' x' : {
265260 buffer[index++] = ' 0' ;
266261 buffer[index++] = ' x' ;
262+ unsigned int sub_width = (width > 2 ) ? (width - 2 ) : 0 ;
267263 if (longlong_modifier) {
268264 uint64_t num = va_arg (args, uint64_t );
269- index = print_number (index, buffer, num, base16);
265+ index = print_number (index, buffer, num, base16, sub_width, leading_zero, false );
270266 } else if (long_modifier) {
271- uint32_t num = va_arg (args, uint32_t ); // 32 bits
272- index = print_number (index, buffer, num, base16);
267+ uint32_t num = va_arg (args, uint32_t );
268+ index = print_number (index, buffer, num, base16, sub_width, leading_zero, false );
273269 } else if (half_modifier) {
274270 unsigned int value = va_arg (args, unsigned int );
275271 uint16_t num = clamp_to_range (value, std::numeric_limits<uint16_t >::min (), std::numeric_limits<uint16_t >::max ());
276- index = print_number (index, buffer, num, base16);
272+ index = print_number (index, buffer, num, base16, sub_width, leading_zero, false );
277273 } else if (halfhalf_modifier) {
278274 unsigned int value = va_arg (args, unsigned int );
279275 uint8_t num = clamp_to_range (value, std::numeric_limits<uint8_t >::min (), std::numeric_limits<uint8_t >::max ());
280- index = print_number (index, buffer, num, base16);
276+ index = print_number (index, buffer, num, base16, sub_width, leading_zero, false );
281277 } else if (size_modifier) {
282278 size_t num = va_arg (args, size_t );
283- index = print_number (index, buffer, num, base16);
279+ index = print_number (index, buffer, num, base16, sub_width, leading_zero, false );
284280 } else {
285281 uint32_t num = va_arg (args, unsigned int );
286- index = print_number (index, buffer, num, base16);
282+ index = print_number (index, buffer, num, base16, sub_width, leading_zero, false );
283+ }
284+ break ;
285+ }
286+ case ' X' : {
287+ if (longlong_modifier) {
288+ uint64_t num = va_arg (args, uint64_t );
289+ index = print_number (index, buffer, num, base16, width, leading_zero, true );
290+ } else if (long_modifier) {
291+ uint32_t num = va_arg (args, uint32_t );
292+ index = print_number (index, buffer, num, base16, width, leading_zero, true );
293+ } else if (half_modifier) {
294+ unsigned int value = va_arg (args, unsigned int );
295+ uint16_t num = clamp_to_range (value, std::numeric_limits<uint16_t >::min (), std::numeric_limits<uint16_t >::max ());
296+ index = print_number (index, buffer, num, base16, width, leading_zero, true );
297+ } else if (halfhalf_modifier) {
298+ unsigned int value = va_arg (args, unsigned int );
299+ uint8_t num = clamp_to_range (value, std::numeric_limits<uint8_t >::min (), std::numeric_limits<uint8_t >::max ());
300+ index = print_number (index, buffer, num, base16, width, leading_zero, true );
301+ } else if (size_modifier) {
302+ size_t num = va_arg (args, size_t );
303+ index = print_number (index, buffer, num, base16, width, leading_zero, true );
304+ } else {
305+ uint32_t num = va_arg (args, unsigned int );
306+ index = print_number (index, buffer, num, base16, width, leading_zero, true );
287307 }
288308 break ;
289309 }
@@ -321,7 +341,8 @@ unsigned long vsnprint(char buffer[], size_t buffer_size, const char *format, va
321341 }
322342 buffer[index++] = ' 0' ;
323343 buffer[index++] = ' b' ;
324- index = print_number (index, buffer, num, base2);
344+ unsigned int sub_width = (width > 2 ) ? (width - 2 ) : 0 ;
345+ index = print_number (index, buffer, num, base2, sub_width, leading_zero, false );
325346 break ;
326347 }
327348 default :
@@ -336,8 +357,6 @@ unsigned long vsnprint(char buffer[], size_t buffer_size, const char *format, va
336357 format++;
337358 }
338359
339- // FIXME determine if we've run over.
340-
341360 // null terminate the string
342361 if (index >= buffer_size) {
343362 index = buffer_size - 1 ;
0 commit comments