diff options
-rw-r--r-- | lib.c | 196 |
1 files changed, 91 insertions, 105 deletions
@@ -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, ...) |