summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmanuele Torre <torreemanuele6@gmail.com>2023-12-09 20:46:38 +0100
committerNico Williams <nico@cryptonector.com>2024-01-16 16:57:37 -0600
commit1f1e619f4e1478598aca56115948eb14d484b9fe (patch)
tree06820f0c606b99a01f6784810c80954d3600cc0f
parent71e7bcdfc154ddbd27b80c840f35b52cb9d66215 (diff)
builtins: make ltrimstr and rtrimstr error for non-string inputs
Previously, ltrimstr/rtrimstr would just let the input pass through for non-string inputs or arguments. That was happening because, they were leaking the errors returned by startswith/endswith treating them as if they were jv_false(). The leak was resolved by #2977 for 1.7.1 This patch rewrites ltrimstr and rtrimstr in jq, and makes them not ignore startswith and endswith errors anymore.
-rw-r--r--src/builtin.c33
-rw-r--r--src/builtin.jq2
-rw-r--r--tests/jq.test16
3 files changed, 18 insertions, 33 deletions
diff --git a/src/builtin.c b/src/builtin.c
index 0e59bf40..db28d05b 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -294,37 +294,6 @@ static jv f_endswith(jq_state *jq, jv a, jv b) {
return ret;
}
-static jv f_ltrimstr(jq_state *jq, jv input, jv left) {
- jv startswith = f_startswith(jq, jv_copy(input), jv_copy(left));
- if (jv_get_kind(startswith) != JV_KIND_TRUE) {
- jv_free(startswith);
- jv_free(left);
- return input;
- }
- /*
- * FIXME It'd be better to share the suffix with the original input --
- * that we could do, we just can't share prefixes.
- */
- int prefixlen = jv_string_length_bytes(left);
- jv res = jv_string_sized(jv_string_value(input) + prefixlen,
- jv_string_length_bytes(jv_copy(input)) - prefixlen);
- jv_free(input);
- return res;
-}
-
-static jv f_rtrimstr(jq_state *jq, jv input, jv right) {
- jv endswith = f_endswith(jq, jv_copy(input), jv_copy(right));
- if (jv_get_kind(endswith) == JV_KIND_TRUE) {
- jv res = jv_string_sized(jv_string_value(input),
- jv_string_length_bytes(jv_copy(input)) - jv_string_length_bytes(right));
- jv_free(input);
- return res;
- }
- jv_free(endswith);
- jv_free(right);
- return input;
-}
-
jv binop_minus(jv a, jv b) {
if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
jv r = jv_number(jv_number_value(a) - jv_number_value(b));
@@ -1736,8 +1705,6 @@ BINOPS
{f_keys_unsorted, "keys_unsorted", 1},
{f_startswith, "startswith", 2},
{f_endswith, "endswith", 2},
- {f_ltrimstr, "ltrimstr", 2},
- {f_rtrimstr, "rtrimstr", 2},
{f_string_split, "split", 2},
{f_string_explode, "explode", 1},
{f_string_implode, "implode", 1},
diff --git a/src/builtin.jq b/src/builtin.jq
index 2b8263c7..802595ba 100644
--- a/src/builtin.jq
+++ b/src/builtin.jq
@@ -74,6 +74,8 @@ def fromdateiso8601: strptime("%Y-%m-%dT%H:%M:%SZ")|mktime;
def todateiso8601: strftime("%Y-%m-%dT%H:%M:%SZ");
def fromdate: fromdateiso8601;
def todate: todateiso8601;
+def ltrimstr($left): if startswith($left) then .[$left | length:] end;
+def rtrimstr($right): if endswith($right) then .[:$right | -length] end;
def match(re; mode): _match_impl(re; mode; false)|.[];
def match($val): ($val|type) as $vt | if $vt == "string" then match($val; null)
elif $vt == "array" and ($val | length) > 1 then match($val[0]; $val[1])
diff --git a/tests/jq.test b/tests/jq.test
index 7036df2c..b94f29d2 100644
--- a/tests/jq.test
+++ b/tests/jq.test
@@ -2115,3 +2115,19 @@ try ltrimstr("x") catch "x", try rtrimstr("x") catch "x" | "ok"
{"hey":[]}
"ok"
"ok"
+
+# ltrimstr/1 and rtrimstr/1 return an error for non-strings. #2969
+
+.[] as [$x, $y] | try ["ok", ($x | ltrimstr($y))] catch ["ko", .]
+[["hi",1],[1,"hi"],["hi","hi"],[1,1]]
+["ko","startswith() requires string inputs"]
+["ko","startswith() requires string inputs"]
+["ok",""]
+["ko","startswith() requires string inputs"]
+
+.[] as [$x, $y] | try ["ok", ($x | rtrimstr($y))] catch ["ko", .]
+[["hi",1],[1,"hi"],["hi","hi"],[1,1]]
+["ko","endswith() requires string inputs"]
+["ko","endswith() requires string inputs"]
+["ok",""]
+["ko","endswith() requires string inputs"]