char *out;
const char *outstr;
unsigned int sign_prefix;
+ int got_width;
written = 0;
while (1) {
}
/* Width and precision */
- for (;; ch = *fmt++) {
+ for (got_width = 0;; ch = *fmt++) {
if (ch == '*') {
- precision = va_arg(args, unsigned int);
+ precision = va_arg(args, int);
ch = *fmt++;
} else {
for (precision = 0; ch >= '0' && ch <= '9'; ch = *fmt++)
precision = precision * 10 + (ch - '0');
}
- if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '.'))
+ if (got_width)
break;
width = precision;
if (ch != '.') {
/* Default precision for strings */
- precision = INT_MAX;
+ precision = -1;
break;
}
- flags |= _NOLIBC_PF_FLAG('.');
+ got_width = 1;
+ }
+ /* A negative width (e.g. from "%*s") requests left justify. */
+ if (width < 0) {
+ width = -width;
+ flags |= _NOLIBC_PF_FLAG('-');
}
/* Length modifier.
if (!outstr) {
outstr = "(null)";
/* Match glibc, nothing output if precision too small */
- len = precision >= 6 ? 6 : 0;
+ len = precision < 0 || precision >= 6 ? 6 : 0;
goto do_output;
}
goto do_strlen_output;
}
/* Add zero padding */
- if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '0', '.')) {
- if (!_NOLIBC_PF_FLAGS_CONTAIN(flags, '.')) {
- if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '-'))
- /* Left justify overrides zero pad */
- goto prepend_sign;
- /* eg "%05d", Zero pad to field width less sign.
- * Note that precision can end up negative so all
- * the variables have to be 'signed int'.
- */
- precision = width;
- if (sign_prefix) {
+ if (precision < 0) {
+ /* No explicit precision (or negative from "%.*s"). */
+ if (!_NOLIBC_PF_FLAGS_CONTAIN(flags, '0'))
+ goto no_zero_padding;
+ if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '-'))
+ /* Left justify overrides zero pad */
+ goto no_zero_padding;
+ /* eg "%05d", Zero pad to field width less sign.
+ * Note that precision can end up negative so all
+ * the variables have to be 'signed int'.
+ */
+ precision = width;
+ if (sign_prefix) {
+ precision--;
+ if (sign_prefix >= 256)
precision--;
- if (sign_prefix >= 256)
- precision--;
- }
- }
- if (precision > 31)
- /* Don't run off the start of outbuf[], arbitrary limit
- * longer than the longest number field. */
- precision = 31;
- for (; len < precision; len++) {
- /* Stop gcc generating horrid code and memset(). */
- _NOLIBC_OPTIMIZER_HIDE_VAR(len);
- *--out = '0';
}
}
+ if (precision > 31)
+ /* Don't run off the start of outbuf[], arbitrary limit
+ * longer than the longest number field. */
+ precision = 31;
+ for (; len < precision; len++) {
+ /* Stop gcc generating horrid code and memset(). */
+ _NOLIBC_OPTIMIZER_HIDE_VAR(len);
+ *--out = '0';
+ }
+no_zero_padding:
/* %#o has set sign_prefix to '0', but we don't want so add an extra
* leading zero here.
do_strlen_output:
/* Open coded strnlen() (slightly smaller). */
- for (len = 0; len < precision; len++)
+ for (len = 0; precision < 0 || len < precision; len++)
if (!outstr[len])
break;
CASE_TEST(char); EXPECT_VFPRINTF(1, "|c|d| e|", "|%c|%.0c|%4c|", 'c', 'd', 'e'); break;
CASE_TEST(octal); EXPECT_VFPRINTF(1, "|17| 0033||", "|%o|%6.4o|%.0o|", 017, 033, 0); break;
CASE_TEST(octal_max); EXPECT_VFPRINTF(1, "1777777777777777777777", "%llo", ~0ULL); break;
- CASE_TEST(octal_alt); EXPECT_VFPRINTF(1, "|0|01|02|034|0|", "|%#o|%#o|%#02o|%#02o|%#.0o|", 0, 1, 2, 034, 0); break;
+ CASE_TEST(octal_alt); EXPECT_VFPRINTF(1, "|0|01|02|034|0|0|", "|%#o|%#o|%#02o|%#02o|%#.0o|%0-#o|", 0, 1, 2, 034, 0, 0); break;
CASE_TEST(hex_nolibc); EXPECT_VFPRINTF(is_nolibc, "|f|d|", "|%x|%X|", 0xf, 0xd); break;
CASE_TEST(hex_libc); EXPECT_VFPRINTF(!is_nolibc, "|f|D|", "|%x|%X|", 0xf, 0xd); break;
CASE_TEST(hex_alt); EXPECT_VFPRINTF(1, "|0x1| 0x2| 0|", "|%#x|%#5x|%#5x|", 1, 2, 0); break;
CASE_TEST(truncation); EXPECT_VFPRINTF(1, "012345678901234567890123456789", "%s", "012345678901234567890123456789"); break;
CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break;
CASE_TEST(string_trunc); EXPECT_VFPRINTF(1, " 12345", "%10.5s", "1234567890"); break;
+ CASE_TEST(string_var); EXPECT_VFPRINTF(1, "| ab|ef | ij|kl |", "|%*.*s|%*.*s|%*.*s|%*.*s|", 3, 2, "abcd", -3, 2, "efgh", 3, -1, "ij", -3, -1, "kl"); break;
CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break;
CASE_TEST(number_left); EXPECT_VFPRINTF(1, "|-5 |", "|%-8d|", -5); break;
CASE_TEST(string_align); EXPECT_VFPRINTF(1, "|foo |", "|%-8s|", "foo"); break;
CASE_TEST(num_p_tr_libc);EXPECT_VFPRINTF(!is_nolibc, "00000000000000000000000000000000005", "%035d", 5); break;
CASE_TEST(number_prec); EXPECT_VFPRINTF(1, " 00005", "%10.5d", 5); break;
CASE_TEST(num_prec_neg); EXPECT_VFPRINTF(1, " -00005", "%10.5d", -5); break;
- CASE_TEST(num_prec_var); EXPECT_VFPRINTF(1, " -00005", "%*.*d", 10, 5, -5); break;
+ CASE_TEST(number_var); EXPECT_VFPRINTF(1, "| -00005|5 |", "|%*.*d|%*.*d|", 10, 5, -5, -2, -10, 5); break;
CASE_TEST(num_0_prec_0); EXPECT_VFPRINTF(1, "|| |+||||", "|%.0d|% .0d|%+.0d|%.0u|%.0x|%#.0x|", 0, 0, 0, 0, 0, 0); break;
CASE_TEST(errno); errno = 22; EXPECT_VFPRINTF(is_nolibc, "errno=22", "%m"); break;
CASE_TEST(errno-neg); errno = -22; EXPECT_VFPRINTF(is_nolibc, "errno=-22 ", "%-12m"); break;