diff options
-rw-r--r-- | lib.c | 41 | ||||
-rw-r--r-- | tests/custom/03_stdlib/27_sprintf | 21 | ||||
-rw-r--r-- | tests/custom/03_stdlib/28_printf | 17 |
3 files changed, 72 insertions, 7 deletions
@@ -1198,7 +1198,7 @@ uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf) uint32_t conv, flags, width, precision; uc_value_t *fmt = uc_fn_arg(0), *arg; const char *fstr, *last, *p, *cfmt; - size_t argidx = 1, sfmtlen; + size_t argidx = 1, argpos, sfmtlen; uint64_t u; int64_t n; double d; @@ -1218,6 +1218,26 @@ uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf) width = 0; precision = 0; + argpos = argidx; + + if (*p >= '1' && *p <= '9') { + while (isdigit(*p)) + width = width * 10 + (*p++ - '0'); + + /* if a dollar sign follows, this is an argument index */ + if (*p == '$') { + argpos = width; + width = 0; + p++; + } + + /* otherwise skip to parsing precision, flags can't possibly follow */ + else { + flags |= FMT_F_WIDTH; + goto parse_precision; + } + } + while (*p != '\0' && strchr("#0- +", *p)) { switch (*p++) { case '#': flags |= FMT_F_ALT; break; @@ -1235,6 +1255,7 @@ uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf) flags |= FMT_F_WIDTH; } +parse_precision: if (*p == '.') { p++; @@ -1374,7 +1395,8 @@ uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf) break; case FMT_C_INT: - arg = uc_fn_arg(argidx++); + argidx++; + arg = uc_fn_arg(argpos); n = ucv_to_integer(arg); if (errno == ERANGE) @@ -1384,7 +1406,8 @@ uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf) break; case FMT_C_UINT: - arg = uc_fn_arg(argidx++); + argidx++; + arg = uc_fn_arg(argpos); u = ucv_to_unsigned(arg); if (errno == ERANGE) @@ -1394,17 +1417,20 @@ uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf) break; case FMT_C_DBL: - d = ucv_to_double(uc_fn_arg(argidx++)); + argidx++; + d = ucv_to_double(uc_fn_arg(argpos)); ucv_stringbuf_printf(buf, sfmt, d); break; case FMT_C_CHR: - n = ucv_to_integer(uc_fn_arg(argidx++)); + argidx++; + n = ucv_to_integer(uc_fn_arg(argpos)); ucv_stringbuf_printf(buf, sfmt, (int)n); break; case FMT_C_STR: - arg = uc_fn_arg(argidx++); + argidx++; + arg = uc_fn_arg(argpos); switch (ucv_type(arg)) { case UC_STRING: @@ -1424,8 +1450,9 @@ uc_printf_common(uc_vm_t *vm, size_t nargs, uc_stringbuf_t *buf) break; case FMT_C_JSON: + argidx++; s = ucv_to_jsonstring_formatted(vm, - uc_fn_arg(argidx++), + uc_fn_arg(argpos), precision > 0 ? (precision > 1 ? ' ' : '\t') : '\0', precision > 0 ? (precision > 1 ? precision - 1 : 1) : 0); diff --git a/tests/custom/03_stdlib/27_sprintf b/tests/custom/03_stdlib/27_sprintf index 3edcd48..e1a3c5d 100644 --- a/tests/custom/03_stdlib/27_sprintf +++ b/tests/custom/03_stdlib/27_sprintf @@ -548,3 +548,24 @@ Supplying a non-string format value will yield an empty string result. -- Expect stdout -- "" -- End -- + + +Prefixing a format directive with `n$` will select the corresponding argument +with 1 referring to the first argument. Missing or out-of range arguments will +be treated as `null`. + +-- Testcase -- +{% + printf("%.J\n", [ + sprintf("%2$s", "foo", "bar", "baz"), + sprintf("%10$s", "foo", "bar", "baz") + ]); +%} +-- End -- + +-- Expect stdout -- +[ + "bar", + "(null)" +] +-- End -- diff --git a/tests/custom/03_stdlib/28_printf b/tests/custom/03_stdlib/28_printf index a2a6d27..b4556b3 100644 --- a/tests/custom/03_stdlib/28_printf +++ b/tests/custom/03_stdlib/28_printf @@ -524,3 +524,20 @@ Supplying a non-string format value will yield an empty string result. -- Expect stdout -- -- End -- + + +Prefixing a format directive with `n$` will select the corresponding argument +with 1 referring to the first argument. Missing or out-of range arguments will +be treated as `null`. + +-- Testcase -- +{% + printf("%2$s\n", "foo", "bar", "baz"); + printf("%10$s\n", "foo", "bar", "baz"); +%} +-- End -- + +-- Expect stdout -- +bar +(null) +-- End -- |