Skip to content

Commit 060f11e

Browse files
committed
Simplify/fix integer zero padding + hash flag
Handle 0x / 0b when width is equal to string size (issue mpaland#50): printf("%#4x", 0x1234); -> "0x1234" Do not print # prefix if it does not fit into PRINTF_NTOA_BUFFER_SIZE %#<prec>o is implemented as in libc: - printf("%#0o", 0); does output octal prefix ("0") - printf("%#3o", 1); printf "001" - padding zero is used as octal prefix (issue mpaland#53) Left padding and precision is handled correctly (issue mpaland#49): - printf("%-10.6d", 1024); -> "001024 "
1 parent 87d27ef commit 060f11e

File tree

1 file changed

+41
-27
lines changed

1 file changed

+41
-27
lines changed

printf.c

+41-27
Original file line numberDiff line numberDiff line change
@@ -231,40 +231,46 @@ static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen
231231
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
232232
{
233233
// pad leading zeros
234-
if (!(flags & FLAGS_LEFT)) {
235-
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
236-
width--;
237-
}
238-
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
239-
buf[len++] = '0';
240-
}
241-
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
242-
buf[len++] = '0';
234+
int zeropad = 0;
235+
if (flags & FLAGS_PRECISION) {
236+
// no other source of zero-padding if prec is specified
237+
zeropad = (int)(prec - len);
243238
}
239+
else if (flags & FLAGS_ZEROPAD) {
240+
zeropad = (int)(width - len);
241+
if (negative || flags & (FLAGS_PLUS | FLAGS_SPACE)) {
242+
// keep one position for sign
243+
zeropad--;
244244
}
245-
246-
// handle hash
247245
if (flags & FLAGS_HASH) {
248-
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
249-
len--;
250-
if (len && (base == 16U)) {
251-
len--;
246+
// keep space for 0x / 0b
247+
// octal is handled separately
248+
if (base == 16U || base == 2U) {
249+
zeropad -= 2;
252250
}
253251
}
254-
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
255-
buf[len++] = 'x';
256252
}
257-
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
258-
buf[len++] = 'X';
253+
254+
while ((zeropad-- > 0) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
255+
buf[len++] = '0';
259256
}
260-
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
257+
258+
// handle hash
259+
if (flags & FLAGS_HASH) {
260+
if (base == 2 && len < PRINTF_NTOA_BUFFER_SIZE - 1) {
261261
buf[len++] = 'b';
262+
buf[len++] = '0';
262263
}
263-
if (len < PRINTF_NTOA_BUFFER_SIZE) {
264+
// pesky octal case. Add 0 prefix only if following digit is not zero (both from value and zero-padding)
265+
if (base == 8 && len < PRINTF_NTOA_BUFFER_SIZE && (!len || buf[len - 1] != '0')) {
264266
buf[len++] = '0';
265267
}
268+
if (base == 16 && len < PRINTF_NTOA_BUFFER_SIZE - 1) {
269+
buf[len++] = (flags & FLAGS_UPPERCASE) ? 'X' : 'x';
270+
buf[len++] = '0';
266271
}
267-
272+
}
273+
// handle '+', '-', ' '
268274
if (len < PRINTF_NTOA_BUFFER_SIZE) {
269275
if (negative) {
270276
buf[len++] = '-';
@@ -287,12 +293,13 @@ static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxl
287293
char buf[PRINTF_NTOA_BUFFER_SIZE];
288294
size_t len = 0U;
289295

290-
// no hash for 0 values
291-
if (!value) {
296+
// no hash for 0 values, except octal 0 */
297+
if (!value && (base != 8)) {
292298
flags &= ~FLAGS_HASH;
293299
}
294300

295-
// write if precision != 0 and value is != 0
301+
// if precision is specified and zero, don't print zero value
302+
// if precision > 0, zero padding code will supply at least one zero
296303
if (!(flags & FLAGS_PRECISION) || value) {
297304
do {
298305
const char digit = (char)(value % base);
@@ -313,11 +320,12 @@ static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t
313320
size_t len = 0U;
314321

315322
// no hash for 0 values
316-
if (!value) {
323+
if (!value && (base != 8)) {
317324
flags &= ~FLAGS_HASH;
318325
}
319326

320-
// write if precision != 0 and value is != 0
327+
// if precision is specified and zero, don't print zero value
328+
// if precision > 0, zero padding code will supply at least one zero
321329
if (!(flags & FLAGS_PRECISION) || value) {
322330
do {
323331
const char digit = (char)(value % base);
@@ -761,6 +769,9 @@ static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const
761769
#if defined(PRINTF_SUPPORT_FLOAT)
762770
case 'f' :
763771
case 'F' :
772+
if (flags & FLAGS_LEFT) {
773+
flags &= ~FLAGS_ZEROPAD;
774+
}
764775
if (*format == 'F') flags |= FLAGS_UPPERCASE;
765776
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
766777
format++;
@@ -770,6 +781,9 @@ static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const
770781
case 'E':
771782
case 'g':
772783
case 'G':
784+
if (flags & FLAGS_LEFT) {
785+
flags &= ~FLAGS_ZEROPAD;
786+
}
773787
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
774788
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
775789
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);

0 commit comments

Comments
 (0)