diff --git a/src/builtin.c b/src/builtin.c index 06cd213d..0757a86b 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -343,21 +343,10 @@ jv binop_multiply(jv a, jv b) { str = b; num = a; } - jv res; double d = jv_number_value(num); - if (d < 0 || isnan(d)) { - res = jv_null(); - } else { - int n = d; - size_t alen = jv_string_length_bytes(jv_copy(str)); - res = jv_string_empty(alen * n); - for (; n > 0; n--) { - res = jv_string_append_buf(res, jv_string_value(str), alen); - } - } - jv_free(str); jv_free(num); - return res; + return jv_string_repeat(str, + d < 0 || isnan(d) ? -1 : d > INT_MAX ? INT_MAX : (int)d); } else if (ak == JV_KIND_OBJECT && bk == JV_KIND_OBJECT) { return jv_object_merge_recursive(a, b); } else { diff --git a/src/jv.c b/src/jv.c index 3e9920ed..fd6cfcab 100644 --- a/src/jv.c +++ b/src/jv.c @@ -1324,6 +1324,32 @@ jv jv_string_indexes(jv j, jv k) { return a; } +jv jv_string_repeat(jv j, int n) { + assert(JVP_HAS_KIND(j, JV_KIND_STRING)); + if (n < 0) { + jv_free(j); + return jv_null(); + } + int len = jv_string_length_bytes(jv_copy(j)); + int64_t res_len = (int64_t)len * n; + if (res_len >= INT_MAX) { + jv_free(j); + return jv_invalid_with_msg(jv_string("Repeat string result too long")); + } + if (res_len == 0) { + jv_free(j); + return jv_string(""); + } + jv res = jv_string_empty(res_len); + res = jvp_string_append(res, jv_string_value(j), len); + for (int curr = len, grow; curr < res_len; curr += grow) { + grow = MIN(res_len - curr, curr); + res = jvp_string_append(res, jv_string_value(res), grow); + } + jv_free(j); + return res; +} + jv jv_string_split(jv j, jv sep) { assert(JVP_HAS_KIND(j, JV_KIND_STRING)); assert(JVP_HAS_KIND(sep, JV_KIND_STRING)); diff --git a/src/jv.h b/src/jv.h index 5d4197cf..b9710610 100644 --- a/src/jv.h +++ b/src/jv.h @@ -136,6 +136,7 @@ jv jv_string_fmt(const char*, ...) JV_PRINTF_LIKE(1, 2); jv jv_string_append_codepoint(jv a, uint32_t c); jv jv_string_append_buf(jv a, const char* buf, int len); jv jv_string_append_str(jv a, const char* str); +jv jv_string_repeat(jv j, int n); jv jv_string_split(jv j, jv sep); jv jv_string_explode(jv j); jv jv_string_implode(jv j); diff --git a/tests/jq.test b/tests/jq.test index 959895c4..2e3c1e8b 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -1460,6 +1460,18 @@ indices("o") "abc" [null,null] +. * 100000 | [.[:10],.[-10:]] +"abc" +["abcabcabca","cabcabcabc"] + +. * 1000000000 +"" +"" + +try (. * 1000000000) catch . +"abc" +"Repeat string result too long" + [.[] / ","] ["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"] [["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]