summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c2
-rw-r--r--lib.c36
-rw-r--r--lib.h2
-rw-r--r--tests/015/split.tl39
-rw-r--r--txr.137
5 files changed, 103 insertions, 13 deletions
diff --git a/eval.c b/eval.c
index b8a611d2..5eb22fd0 100644
--- a/eval.c
+++ b/eval.c
@@ -7217,7 +7217,7 @@ void eval_init(void)
reg_fun(intern(lit("sub-str"), user_package), func_n3o(sub_str, 1));
reg_fun(intern(lit("replace-str"), user_package), func_n4o(replace_str, 2));
reg_fun(intern(lit("cat-str"), user_package), func_n2o(cat_str, 1));
- reg_fun(intern(lit("split-str"), user_package), func_n3o(split_str_keep, 2));
+ reg_fun(intern(lit("split-str"), user_package), func_n4o(split_str_keep, 2));
reg_fun(intern(lit("spl"), user_package), func_n3o(spl, 2));
reg_fun(intern(lit("split-str-set"), user_package), func_n2(split_str_set));
reg_fun(intern(lit("sspl"), user_package), func_n2(sspl));
diff --git a/lib.c b/lib.c
index 95c1bd6b..050e8889 100644
--- a/lib.c
+++ b/lib.c
@@ -5735,10 +5735,18 @@ val fmt_join(struct args *args)
return join_with(nil, args);
}
-val split_str_keep(val str, val sep, val keep_sep)
+val split_str_keep(val str, val sep, val keep_sep_opt, val count_opt)
{
val self = lit("split-str");
- keep_sep = default_null_arg(keep_sep);
+ val keep_sep = default_null_arg(keep_sep_opt);
+ val count = default_null_arg(count_opt);
+ cnum cnt = c_num(if3(count, count, negone), self);
+
+ if (count && cnt < 0)
+ uw_throwf(error_s, lit("~a: count must be nonnegative"), self, nao);
+
+ if (count == zero)
+ return cons(str, nil);
if (regexp(sep)) {
list_collect_decl (out, iter);
@@ -5758,6 +5766,10 @@ val split_str_keep(val str, val sep, val keep_sep)
pos = plus(pos, len);
if (keep_sep)
iter = list_collect(iter, sub_str(str, new_pos, pos));
+ if (cnt > 0 && --cnt == 0) {
+ iter = list_collect(iter, sub_str(str, pos, t));
+ break;
+ }
continue;
}
break;
@@ -5789,8 +5801,14 @@ val split_str_keep(val str, val sep, val keep_sep)
val piece = mkustring(one);
init_str(piece, cstr, self);
iter = list_collect(iter, piece);
- if (keep_sep && *(cstr+1))
- iter = list_collect(iter, null_string);
+ if (*(cstr + 1)) {
+ if (keep_sep)
+ iter = list_collect(iter, null_string);
+ if (cnt > 0 && --cnt == 0) {
+ iter = list_collect(iter, string(cstr + 1));
+ break;
+ }
+ }
}
gc_hint(str);
@@ -5817,6 +5835,10 @@ val split_str_keep(val str, val sep, val keep_sep)
cstr += len_sep;
if (keep_sep)
iter = list_collect(iter, sep);
+ if (cnt > 0 && --cnt == 0) {
+ iter = list_collect(iter, string(cstr));
+ break;
+ }
continue;
}
break;
@@ -5833,13 +5855,13 @@ val split_str_keep(val str, val sep, val keep_sep)
val spl(val sep, val arg1, val arg2)
{
return if3(missingp(arg2),
- split_str_keep(arg1, sep, arg2),
- split_str_keep(arg2, sep, arg1));
+ split_str_keep(arg1, sep, arg2, nil),
+ split_str_keep(arg2, sep, arg1, nil));
}
val split_str(val str, val sep)
{
- return split_str_keep(str, sep, nil);
+ return split_str_keep(str, sep, nil, nil);
}
val split_str_set(val str, val set)
diff --git a/lib.h b/lib.h
index b5b59b38..5363f47b 100644
--- a/lib.h
+++ b/lib.h
@@ -925,7 +925,7 @@ val scat3(val s1, val sep, val s2);
val join_with(val sep, struct args *args);
val fmt_join(struct args *args);
val split_str(val str, val sep);
-val split_str_keep(val str, val sep, val keep_sep);
+val split_str_keep(val str, val sep, val keep_sep_opt, val count_opt);
val spl(val sep, val arg1, val arg2);
val split_str_set(val str, val set);
val sspl(val set, val str);
diff --git a/tests/015/split.tl b/tests/015/split.tl
index e54092c5..8cdf7f04 100644
--- a/tests/015/split.tl
+++ b/tests/015/split.tl
@@ -217,3 +217,42 @@
(join-with "a" "b") "b"
(join-with "--" "b" "c" "d") "b--c--d"
(join-with #\- "b" "c" "d") "b-c-d")
+
+(mtest
+ (split-str "abc" "" : 0) ("abc")
+ (split-str "abc" "" : 1) ("a" "bc")
+ (split-str "abc" "" : 2) ("a" "b" "c")
+ (split-str "abc" "" : 3) ("a" "b" "c")
+ (split-str "abc" "" : -1) :error)
+
+(mtest
+ (split-str "abc" "" t 0) ("abc")
+ (split-str "abc" "" t 1) ("a" "" "bc")
+ (split-str "abc" "" t 2) ("a" "" "b" "" "c")
+ (split-str "abc" "" t 3) ("a" "" "b" "" "c"))
+
+(mtest
+ (split-str "a,b,c" "," : 0) ("a,b,c")
+ (split-str "a,b,c" "," : 1) ("a" "b,c")
+ (split-str "a,b,c" "," : 2) ("a" "b" "c")
+ (split-str "a,b,c" "," : 3) ("a" "b" "c"))
+
+(mtest
+ (split-str "a,b,c" "," t 0) ("a,b,c")
+ (split-str "a,b,c" "," t 1) ("a" "," "b,c")
+ (split-str "a,b,c" "," t 2) ("a" "," "b" "," "c")
+ (split-str "a,b,c" "," t 3) ("a" "," "b" "," "c"))
+
+(mtest
+ (split-str "a12b34c567d" #/[0-9]+/ : 0) ("a12b34c567d")
+ (split-str "a12b34c567d" #/[0-9]+/ : 1) ("a" "b34c567d")
+ (split-str "a12b34c567d" #/[0-9]+/ : 2) ("a" "b" "c567d")
+ (split-str "a12b34c567d" #/[0-9]+/ : 3) ("a" "b" "c" "d")
+ (split-str "a12b34c567d" #/[0-9]+/ : 4) ("a" "b" "c" "d"))
+
+(mtest
+ (split-str "a12b34c567d" #/[0-9]+/ t 0) ("a12b34c567d")
+ (split-str "a12b34c567d" #/[0-9]+/ t 1) ("a" "12" "b34c567d")
+ (split-str "a12b34c567d" #/[0-9]+/ t 2) ("a" "12" "b" "34" "c567d")
+ (split-str "a12b34c567d" #/[0-9]+/ t 3) ("a" "12" "b" "34" "c" "567" "d")
+ (split-str "a12b34c567d" #/[0-9]+/ t 4) ("a" "12" "b" "34" "c" "567" "d"))
diff --git a/txr.1 b/txr.1
index bfa10958..02b0548c 100644
--- a/txr.1
+++ b/txr.1
@@ -25341,7 +25341,7 @@ string, in order.
.coNP Function @ split-str
.synb
-.mets (split-str < string < sep <> [ keep-between ])
+.mets (split-str < string < sep >> [ keep-between <> [ count ]])
.syne
.desc
The
@@ -25356,6 +25356,14 @@ or a regular expression. It determines the separator character
sequences within
.metn string .
+The following describes the behavior of
+.code split-str
+in the case when the integer parameter
+.meta count
+is omitted. The semantics of
+.meta count
+are then given.
+
All non-overlapping matches for
.meta sep
within
@@ -25449,6 +25457,25 @@ last character, whereas
does not recognize empty separators at these outer limits
of the string.
+If the
+.meta count
+parameter is present, it must be a non-negative integer. This value
+specifies the maximum number of pieces of the input
+.meta string
+which are extracted by the splitting process. The returned list
+consists of these pieces, followed by the remainder of the string, if
+the remainder is nonempty. If
+.meta keep-sep
+is true, then separators appear between the pieces, and if the remainder
+piece is present, the separator between the last piece and the remainder
+is included.
+If
+.meta count
+is zero, then
+.code split-str
+returns a list of one element, which is
+.metn string .
+
.coNP Function @ spl
.synb
.mets (spl < sep <> [ keep-between ] << string )
@@ -70512,7 +70539,7 @@ into the target directory whose path is given by
The target directory must exist.
-For source each path in
+For each source path in
.metn from-list ,
the
.code copy-files
@@ -70612,9 +70639,11 @@ Propagate the permissions of all objects under
onto their
.meta to-path
counterparts. In the absence of this option, the copied objects
-receive permissions with are calculated by applying the
+receive the same permissions as a newly created files.
+On POSIX systems this means: readable and writable to the owner,
+group and others, by default, subject to the
.code umask
-of the calling process to the maximally liberal.
+that is in effect.
.IP :times
Propagate the modification and access time stamps of all objects under
.meta from-path