summaryrefslogtreecommitdiffstats
path: root/lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c196
1 files changed, 91 insertions, 105 deletions
diff --git a/lib.c b/lib.c
index 99720212..65bee46b 100644
--- a/lib.c
+++ b/lib.c
@@ -4049,152 +4049,138 @@ val replace_str(val str_in, val items, val from, val to)
return str_in;
}
-val cat_str(val list, val sep)
-{
- size_t total = 1;
- val iter;
- wchar_t *str, *ptr;
- wchar_t onech[] = wini(" ");
+struct cat_str {
+ val sep;
cnum len_sep;
+ size_t total;
+ wchar_t *str, *ptr;
+};
+
+static void cat_str_init(struct cat_str *cs, val sep, wchar_t *onech)
+{
+ cs->sep = sep;
+ cs->total = 1;
+ cs->str = cs->ptr = 0;
if (null_or_missing_p(sep)) {
- len_sep = 0;
+ cs->len_sep = 0;
} else if (chrp(sep)) {
onech[0] = c_chr(sep);
- len_sep = 1;
- sep = auto_str(coerce(const wchli_t *, wref(onech)));
+ cs->len_sep = 1;
+ cs->sep = auto_str(coerce(const wchli_t *, wref(onech)));
} else {
- len_sep = c_num(length_str(sep));
+ cs->len_sep = c_num(length_str(cs->sep));
}
+}
- for (iter = list; iter != nil; iter = cdr(iter)) {
- val item = car(iter);
- if (!item)
- continue;
- if (stringp(item)) {
- size_t ntotal = total + c_num(length_str(item));
-
- if (len_sep && cdr(iter))
- ntotal += len_sep;
-
- if (ntotal < total)
- goto oflow;
-
- total = ntotal;
-
- continue;
- }
- if (chrp(item)) {
- size_t ntotal = total + 1;
+static void cat_str_measure(struct cat_str *cs, val item, val more_p)
+{
+ if (!item)
+ return;
- if (len_sep && cdr(iter))
- ntotal += len_sep;
+ if (stringp(item)) {
+ size_t ntotal = cs->total + c_num(length_str(item));
- if (ntotal < total)
- goto oflow;
+ if (cs->len_sep && more_p)
+ ntotal += cs->len_sep;
- total = ntotal;
+ if (ntotal < cs->total)
+ goto oflow;
- continue;
- }
- uw_throwf(error_s, lit("cat-str: ~s is not a character or string"),
- item, nao);
+ cs->total = ntotal;
+ return;
}
- str = chk_wmalloc(total);
+ if (chrp(item)) {
+ size_t ntotal = cs->total + 1;
- for (ptr = str, iter = list; iter != nil; iter = cdr(iter)) {
- val item = car(iter);
+ if (cs->len_sep && more_p)
+ ntotal += cs->len_sep;
- if (!item)
- continue;
- if (stringp(item)) {
- cnum len = c_num(length_str(item));
- wmemcpy(ptr, c_str(item), len);
- ptr += len;
- } else {
- *ptr++ = c_chr(item);
- }
+ if (ntotal < cs->total)
+ goto oflow;
- if (len_sep && cdr(iter)) {
- wmemcpy(ptr, c_str(sep), len_sep);
- ptr += len_sep;
- }
+ cs->total = ntotal;
+ return;
}
- *ptr = 0;
-
- return string_own(str);
+ uw_throwf(error_s, lit("cat-str: ~s is not a character or string"),
+ item, nao);
oflow:
uw_throwf(error_s, lit("cat-str: string length overflow"), nao);
}
-static val vscat(val sep, va_list vl1, va_list vl2)
+static void cat_str_alloc(struct cat_str *cs)
{
- size_t total = 1;
- val item, next;
- wchar_t *str, *ptr;
- cnum len_sep = (!null_or_missing_p(sep)) ? c_num(length_str(sep)) : 0;
+ cs->ptr = cs->str = chk_wmalloc(cs->total);
+}
- for (item = va_arg(vl1, val); item != nao; item = next)
- {
- next = va_arg(vl1, val);
+static void cat_str_append(struct cat_str *cs, val item, val more_p)
+{
+ if (!item)
+ return;
+ if (stringp(item)) {
+ cnum len = c_num(length_str(item));
+ wmemcpy(cs->ptr, c_str(item), len);
+ cs->ptr += len;
+ } else {
+ *cs->ptr++ = c_chr(item);
+ }
- if (stringp(item)) {
- size_t ntotal = total + c_num(length_str(item));
+ if (cs->len_sep && more_p) {
+ wmemcpy(cs->ptr, c_str(cs->sep), cs->len_sep);
+ cs->ptr += cs->len_sep;
+ }
+}
- if (len_sep && next != nao)
- ntotal += len_sep;
+static val cat_str_get(struct cat_str *cs)
+{
+ *cs->ptr = 0;
+ return string_own(cs->str);
+}
- if (ntotal < total)
- goto oflow;
+val cat_str(val list, val sep)
+{
+ val iter;
+ struct cat_str cs;
+ wchar_t onech[] = wini(" ");
- total = ntotal;
+ cat_str_init(&cs, sep, onech);
- continue;
- }
- if (chrp(item)) {
- size_t ntotal = total + 1;
+ for (iter = list; iter != nil; iter = cdr(iter))
+ cat_str_measure(&cs, car(iter), cdr(iter));
- if (len_sep && next != nao)
- ntotal += len_sep;
+ cat_str_alloc(&cs);
- if (ntotal < total)
- goto oflow;
+ for (iter = list; iter != nil; iter = cdr(iter))
+ cat_str_append(&cs, car(iter), cdr(iter));
- total = ntotal;
+ return cat_str_get(&cs);
+}
- continue;
- }
- uw_throwf(error_s, lit("scat: ~s is not a character or string"),
- item, nao);
- }
+static val vscat(val sep, va_list vl1, va_list vl2)
+{
+ val item, next;
+ struct cat_str cs;
+ wchar_t onech[] = wini(" ");
- str = chk_wmalloc(total);
+ cat_str_init(&cs, sep, onech);
- for (ptr = str, item = va_arg(vl2, val); item != nao; item = next)
+ for (item = va_arg(vl1, val); item != nao; item = next)
{
- next = va_arg(vl2, val);
+ next = va_arg(vl1, val);
+ cat_str_measure(&cs, item, tnil(next != nao));
+ }
- if (stringp(item)) {
- cnum len = c_num(length_str(item));
- wmemcpy(ptr, c_str(item), len);
- ptr += len;
- } else {
- *ptr++ = c_chr(item);
- }
+ cat_str_alloc(&cs);
- if (len_sep && next != nao) {
- wmemcpy(ptr, c_str(sep), len_sep);
- ptr += len_sep;
- }
+ for (item = va_arg(vl2, val); item != nao; item = next)
+ {
+ next = va_arg(vl2, val);
+ cat_str_append(&cs, item, tnil(next != nao));
}
- *ptr = 0;
- return string_own(str);
-
-oflow:
- uw_throwf(error_s, lit("scat: string length overflow"), nao);
+ return cat_str_get(&cs);
}
val scat(val sep, ...)