summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib.c130
-rw-r--r--tests/015/split.tl13
-rw-r--r--txr.164
3 files changed, 111 insertions, 96 deletions
diff --git a/lib.c b/lib.c
index 4b992374..1db15a3b 100644
--- a/lib.c
+++ b/lib.c
@@ -5632,12 +5632,14 @@ struct cat_str {
val sep;
cnum len_sep;
size_t total;
+ int seen_one;
wchar_t *str, *ptr;
};
static void cat_str_init(struct cat_str *cs, val sep, wchar_t *onech, val self)
{
cs->sep = sep;
+ cs->seen_one = 0;
cs->total = 1;
cs->str = cs->ptr = 0;
@@ -5652,7 +5654,7 @@ static void cat_str_init(struct cat_str *cs, val sep, wchar_t *onech, val self)
}
}
-static void cat_str_measure(struct cat_str *cs, val item, int more_p, val self)
+static void cat_str_measure(struct cat_str *cs, val item, val self)
{
if (!item)
return;
@@ -5660,8 +5662,12 @@ static void cat_str_measure(struct cat_str *cs, val item, int more_p, val self)
if (stringp(item)) {
size_t ntotal = cs->total + c_num(length_str(item), self);
- if (cs->len_sep && more_p)
- ntotal += cs->len_sep;
+ if (cs->len_sep) {
+ if (cs->seen_one)
+ ntotal += cs->len_sep;
+ else
+ cs->seen_one = 1;
+ }
if (ntotal < cs->total)
goto oflow;
@@ -5673,8 +5679,12 @@ static void cat_str_measure(struct cat_str *cs, val item, int more_p, val self)
if (chrp(item)) {
size_t ntotal = cs->total + 1;
- if (cs->len_sep && more_p)
- ntotal += cs->len_sep;
+ if (cs->len_sep) {
+ if (cs->seen_one)
+ ntotal += cs->len_sep;
+ else
+ cs->seen_one = 1;
+ }
if (ntotal < cs->total)
goto oflow;
@@ -5683,32 +5693,54 @@ static void cat_str_measure(struct cat_str *cs, val item, int more_p, val self)
return;
}
- uw_throwf(error_s, lit("~a: ~s is not a character or string"), self,
- item, nao);
+ if (seqp(item)) {
+ seq_iter_t item_iter;
+ seq_iter_init(self, &item_iter, item);
+
+ while (seq_get(&item_iter, &item))
+ cat_str_measure(cs, item, self);
+
+ return;
+ }
+
+ uw_throwf(error_s, lit("~a: ~s neither character, string nor sequence"),
+ self, item, nao);
oflow:
uw_throwf(error_s, lit("~a: string length overflow"), self, nao);
}
static void cat_str_alloc(struct cat_str *cs)
{
+ cs->seen_one = 0;
cs->ptr = cs->str = chk_wmalloc(cs->total);
}
-static void cat_str_append(struct cat_str *cs, val item, int more_p, val self)
+static void cat_str_append(struct cat_str *cs, val item, val self)
{
if (!item)
return;
- if (stringp(item)) {
- cnum len = c_num(length_str(item), self);
- wmemcpy(cs->ptr, c_str(item, self), len);
- cs->ptr += len;
+ if (stringp(item) || chrp(item)) {
+ if (cs->len_sep) {
+ if (cs->seen_one) {
+ wmemcpy(cs->ptr, c_str(cs->sep, self), cs->len_sep);
+ cs->ptr += cs->len_sep;
+ } else {
+ cs->seen_one = 1;
+ }
+ }
+ if (chrp(item)) {
+ *cs->ptr++ = c_chr(item);
+ } else {
+ cnum len = c_num(length_str(item), self);
+ wmemcpy(cs->ptr, c_str(item, self), len);
+ cs->ptr += len;
+ }
} else {
- *cs->ptr++ = c_chr(item);
- }
+ seq_iter_t item_iter;
+ seq_iter_init(self, &item_iter, item);
- if (cs->len_sep && more_p) {
- wmemcpy(cs->ptr, c_str(cs->sep, self), cs->len_sep);
- cs->ptr += cs->len_sep;
+ while (seq_get(&item_iter, &item))
+ cat_str_append(cs, item, self);
}
}
@@ -5721,56 +5753,33 @@ static val cat_str_get(struct cat_str *cs)
val cat_str(val items, val sep)
{
val self = lit("cat-str");
- seq_iter_t item_iter;
- val item, peek = nil;
- int more = 0;
struct cat_str cs;
wchar_t onech[] = wini(" ");
-
cat_str_init(&cs, sep, onech, self);
-
- seq_iter_init(self, &item_iter, items);
- more = seq_get(&item_iter, &item);
- while (more)
- {
- cat_str_measure(&cs, item, more = seq_get(&item_iter, &peek), self);
- item = peek;
- }
-
+ cat_str_measure(&cs, items, self);
cat_str_alloc(&cs);
-
- seq_iter_init(self, &item_iter, items);
- more = seq_get(&item_iter, &item);
- while (more)
- {
- cat_str_append(&cs, item, more = seq_get(&item_iter, &peek), self);
- item = peek;
- }
+ cat_str_append(&cs, items, self);
return cat_str_get(&cs);
}
static val vscat(val sep, va_list vl1, va_list vl2, val self)
{
- val item, next;
+ val item;
struct cat_str cs;
wchar_t onech[] = wini(" ");
cat_str_init(&cs, sep, onech, self);
- for (item = va_arg(vl1, val); item != nao; item = next)
- {
- next = va_arg(vl1, val);
- cat_str_measure(&cs, item, next != nao, self);
- }
+ while ((item = va_arg(vl1, val)) != nao)
+ cat_str_measure(&cs, item, self);
cat_str_alloc(&cs);
- for (item = va_arg(vl2, val); item != nao; item = next)
+ while ((item = va_arg(vl2, val)) != nao)
{
- next = va_arg(vl2, val);
- cat_str_append(&cs, item, next != nao, self);
+ cat_str_append(&cs, item, self);
}
return cat_str_get(&cs);
@@ -5796,13 +5805,13 @@ val scat2(val s1, val s2)
cat_str_init(&cs, nil, NULL, self);
- cat_str_measure(&cs, s1, 1, self);
- cat_str_measure(&cs, s2, 0, self);
+ cat_str_measure(&cs, s1, self);
+ cat_str_measure(&cs, s2, self);
cat_str_alloc(&cs);
- cat_str_append(&cs, s1, 1, self);
- cat_str_append(&cs, s2, 0, self);
+ cat_str_append(&cs, s1, self);
+ cat_str_append(&cs, s2, self);
return cat_str_get(&cs);
}
@@ -5815,13 +5824,13 @@ val scat3(val s1, val sep, val s2)
cat_str_init(&cs, sep, onech, self);
- cat_str_measure(&cs, s1, 1, self);
- cat_str_measure(&cs, s2, 0, self);
+ cat_str_measure(&cs, s1, self);
+ cat_str_measure(&cs, s2, self);
cat_str_alloc(&cs);
- cat_str_append(&cs, s1, 1, self);
- cat_str_append(&cs, s2, 0, self);
+ cat_str_append(&cs, s1, self);
+ cat_str_append(&cs, s2, self);
return cat_str_get(&cs);
}
@@ -5831,26 +5840,23 @@ val join_with(val sep, struct args *args)
val self = lit("join-with");
cnum index;
val iter;
- int more;
struct cat_str cs;
wchar_t onech[] = wini(" ");
cat_str_init(&cs, sep, onech, self);
- for (index = 0, iter = args->list, more = args_more_nozap(args, index, iter);
- more;)
+ for (index = 0, iter = args->list; args_more_nozap(args, index, iter);)
{
val item = args_get_nozap(args, &index, &iter);
- cat_str_measure(&cs, item, more = args_more_nozap(args, index, iter), self);
+ cat_str_measure(&cs, item, self);
}
cat_str_alloc(&cs);
- for (index = 0, iter = args->list, more = args_more_nozap(args, index, iter);
- more;)
+ for (index = 0, iter = args->list; args_more_nozap(args, index, iter);)
{
val item = args_get_nozap(args, &index, &iter);
- cat_str_append(&cs, item, more = args_more_nozap(args, index, iter), self);
+ cat_str_append(&cs, item, self);
}
return cat_str_get(&cs);
diff --git a/tests/015/split.tl b/tests/015/split.tl
index 15b3f2a7..1cb13647 100644
--- a/tests/015/split.tl
+++ b/tests/015/split.tl
@@ -298,3 +298,16 @@
(spln 2 "," "a,b,c") ("a" "b" "c")
(spln 3 "," "a,b,c") ("a" "b" "c")
(spln 4 "," "a,b,c") ("a" "b" "c"))
+
+(mtest
+ (cat-str '()) ""
+ (cat-str '() "-") ""
+ (cat-str '(()) "-") ""
+ (cat-str '((()) ()) "-") ""
+ (cat-str '((()) #()) "-") ""
+ (cat-str '((("a" ("b")) #(#\c))) "-") "a-b-c")
+
+(mtest
+ (join-with "--" '()) ""
+ (join-with "--" '(("b"))) "b"
+ (join-with "--" '("b" #(("c") ()) "d")) "b--c--d")
diff --git a/txr.1 b/txr.1
index 2342276d..ef53c99a 100644
--- a/txr.1
+++ b/txr.1
@@ -25644,12 +25644,17 @@ functions combine items into a single string, which is returned.
Every
.meta item
-argument must be a character or string object. The same is true of the
+argument must be a character, string or else a possibly empty
+sequence of items. This rule applies recursively.
+
+If a
.meta sep
-argument, if present.
+argument is present, it must be a character or string.
+
The
.meta item-seq
-argument must be a sequence of any mixture of characters or strings.
+argument must be a sequence of any mixture of items which are
+characters, strings or sequences of items.
Note that this means that if
.meta item-seq
is a character string, it is a valid argument, since it is a sequence
@@ -25662,47 +25667,38 @@ is empty, or no
arguments are present, then all three functions return an
empty string.
-The
+All three functions operate on an abstract sequence of character and string
+items, produced by a left-to-right recursive traversal of their
+.meta item-seq
+or
+.meta item
+arguments.
+
+Under the
+.code join-with
+function, as well as the
.code cat-str
-function receives the items as a single list. If the
+function a
.meta sep
-argument is present, the items are catenated together such that
+argument is given to it,
+the items are catenated together such that
.meta sep
-is interposed between them. If
-.meta item-seq
-contains
+is interposed between them. If there are
.I n
-items, then
+character or string items, then
.I "n - 1"
copies of
.meta sep
-occur in the resulting string.
+occur in the resulting string, which is returned.
-If
-.meta sep
-is absent, then
-.code cat-str
-catenates the items together directly, without any separator.
-
-Copies of the items appear in the resulting string in the same
-order as the items appear in
-.metn item-seq .
-
-The
-.code join-with
-function receives the items as arguments rather than a single
-.meta item-seq
-arguments. The arguments are joined into a single character string
-in order, with
-.meta sep
-interposed between them.
-
-The
+Under the
.code join
-function takes no
+function, or
+.code cat-str
+function invoked without a
.meta sep
-argument. It joins all of its argument items into a single
-string, in order.
+argument, the items are catenated together directly, without any separator.
+The resulting string is returned.
.coNP Function @ split-str
.synb