summaryrefslogtreecommitdiffstats
path: root/buf.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-06-12 23:28:52 -0700
committerKaz Kylheku <kaz@kylheku.com>2019-06-12 23:28:52 -0700
commit8f72f80a49eeefc27d6790acec0d706d3852ed04 (patch)
tree2861e41915d34f08f435c53ca126191bb26d7862 /buf.c
parent07f19fe31673b1d04fd6d8a2b44adac9355f7efe (diff)
downloadtxr-8f72f80a49eeefc27d6790acec0d706d3852ed04.tar.gz
txr-8f72f80a49eeefc27d6790acec0d706d3852ed04.tar.bz2
txr-8f72f80a49eeefc27d6790acec0d706d3852ed04.zip
buffers: replace operation.
* buf.c (replace_buf): New function. * buf.h (replace_buf): Declared. * lib.c (replace): Wire in.
Diffstat (limited to 'buf.c')
-rw-r--r--buf.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/buf.c b/buf.c
index 06fb0abf..00babdf9 100644
--- a/buf.c
+++ b/buf.c
@@ -271,6 +271,95 @@ val sub_buf(val buf, val from, val to)
}
}
+val replace_buf(val buf, val items, val from, val to)
+{
+ val self = lit("replace");
+ val len = length_buf(buf);
+
+ if (missingp(from)) {
+ from = zero;
+ } else if (from == t) {
+ from = len;
+ } else if (!integerp(from)) {
+ seq_iter_t wh_iter, item_iter;
+ val wh, item;
+ seq_iter_init(self, &wh_iter, from);
+ seq_iter_init(self, &item_iter, items);
+
+ if (!missingp(to))
+ uw_throwf(error_s,
+ lit("~a: to-arg not applicable when from-arg is a list"),
+ self, nao);
+
+ while (seq_get(&wh_iter, &wh) && seq_get(&item_iter, &item)) {
+ if (ge(wh, len))
+ break;
+ buf_put_uchar(buf, wh, item);
+ }
+
+ return buf;
+ } else if (lt(from, zero)) {
+ from = plus(from, len);
+ if (to == zero)
+ to = len;
+ }
+
+ if (null_or_missing_p(to) || to == t)
+ to = len;
+ else if (lt(to, zero))
+ to = plus(to, len);
+
+ from = max2(zero, min2(from, len));
+ to = max2(zero, min2(to, len));
+
+ {
+ val len_rep = minus(to, from);
+ val len_it = length(items);
+
+ if (gt(len_rep, len_it)) {
+ val len_diff = minus(len_rep, len_it);
+ cnum t = c_num(to);
+ cnum l = c_num(len);
+
+ memmove(buf->b.data + t - c_num(len_diff),
+ buf->b.data + t,
+ l - t);
+
+ buf_set_length(buf, minus(len, len_diff), zero);
+ to = plus(from, len_it);
+ } else if (lt(len_rep, len_it)) {
+ val len_diff = minus(len_it, len_rep);
+ cnum t = c_num(to);
+ cnum l = c_num(len);
+
+ buf_set_length(buf, plus(len, len_diff), zero);
+
+ memmove(buf->b.data + t + c_num(len_diff),
+ buf->b.data + t,
+ l - t);
+ to = plus(from, len_it);
+ }
+
+ if (zerop(len_it))
+ return buf;
+ if (bufp(items)) {
+ memcpy(buf->b.data + c_num(from), items->b.data, c_num(len_it));
+ } else {
+ seq_iter_t item_iter;
+ seq_iter_init(self, &item_iter, items);
+ cnum f = c_num(from);
+ cnum t = c_num(to);
+
+ for (; f != t; f++) {
+ val item = seq_geti(&item_iter);
+ buf_put_uchar(buf, num(f), item);
+ }
+ }
+ }
+
+ return buf;
+}
+
static void buf_put_bytes(val buf, val pos, mem_t *ptr, cnum size, val self)
{
struct buf *b = buf_handle(buf, self);