summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--buf.c77
-rw-r--r--tests/012/buf.tl31
-rw-r--r--txr.1129
3 files changed, 181 insertions, 56 deletions
diff --git a/buf.c b/buf.c
index 17bdde4b..4a35bc8b 100644
--- a/buf.c
+++ b/buf.c
@@ -142,25 +142,54 @@ static void prepare_pattern(mem_t **ppat, mem_t **pfree, mem_t pbuf[SIZEOF_PTR],
}
}
-val make_buf(val len, val init_val, val alloc_size)
+val make_buf(val len, val init_pat, val alloc_size)
{
val self = lit("make-buf");
+ val pat = default_arg(init_pat, zero);
cnum blen = buf_check_len(len, self);
val alloc = if3(null_or_missing_p(alloc_size), len, alloc_size);
cnum size = buf_check_alloc_size(alloc, blen, self);
- cnum iv = c_u8(default_arg(init_val, zero), self);
- mem_t *data = if3(iv == 0 && size == blen,
+ mem_t *data = if3(pat == zero && size == blen,
chk_calloc(size, 1),
chk_malloc(size));
val obj = make_obj();
+ cnum iv;
obj->b.type = BUF;
obj->b.data = data;
obj->b.len = len;
obj->b.size = num(size);
- if (iv != 0 || size != blen)
- memset(data, convert(unsigned char, iv), blen);
+ if ((is_num(pat) || is_chr(pat)) &&
+ -256 < (iv = c_num(pat, self)) && iv < 256)
+ {
+ if (iv != 0 || size != blen)
+ memset(data, convert(unsigned char, iv), blen);
+ } else {
+ mem_t *p = 0, *fr = 0;
+ unsigned char pbuf[SIZEOF_PTR] = { 0 };
+ int left = 0;
+ ucnum pl, l = size, i, j;
+
+ prepare_pattern(&p, &fr, pbuf, &pl, &left, pat, self);
+
+ if (left) {
+ for (i = 0, j = 0; i < l; i++) {
+ data[i] = p[j++];
+ if (j >= pl)
+ j = 0;
+ }
+ } else {
+ for (i = l - 1, j = pl; i != convert(ucnum, -1); --i) {
+ data[i] = p[--j];
+ if (j == 0)
+ j = pl;
+ }
+ }
+
+ free(fr);
+ gc_hint(pat);
+ }
return obj;
}
@@ -257,12 +286,11 @@ val buf_trim(val buf)
}
static val buf_do_set_len(val buf, struct buf *b, val newlen,
- val init_val, val self)
+ val init_pat, val self)
{
val oldlen = b->len;
cnum olen = c_num(oldlen, self), len = c_num(newlen, self);
cnum oldsize = c_num(b->size, self), size = oldsize;
- cnum iv = c_u8(default_arg(init_val, zero), self);
if (!b->size)
uw_throwf(error_s, lit("~a: ~s is a fixed buffer"),
@@ -286,8 +314,39 @@ static val buf_do_set_len(val buf, struct buf *b, val newlen,
b->size = num(size);
}
- if (len > olen)
- memset(b->data + olen, convert(unsigned char, iv), len - olen);
+ if (len > olen) {
+ val pat = default_arg(init_pat, zero);
+ cnum iv;
+ if ((is_num(pat) || is_chr(pat)) &&
+ -256 < (iv = c_num(pat, self)) && iv < 256)
+ {
+ memset(b->data + olen, convert(unsigned char, iv), len - olen);
+ } else {
+ mem_t *p = 0, *fr = 0;
+ unsigned char pbuf[SIZEOF_PTR] = { 0 };
+ int left = 0;
+ ucnum pl, from = olen, l = len, i, j;
+
+ prepare_pattern(&p, &fr, pbuf, &pl, &left, pat, self);
+
+ if (left) {
+ for (i = from, j = from % pl; i < l; i++) {
+ b->data[i] = p[j++];
+ if (j >= pl)
+ j = 0;
+ }
+ } else {
+ for (i = l - 1, j = pl; i != from - 1; --i) {
+ b->data[i] = p[--j];
+ if (j == 0)
+ j = pl;
+ }
+ }
+
+ free(fr);
+ gc_hint(pat);
+ }
+ }
return oldlen;
}
diff --git a/tests/012/buf.tl b/tests/012/buf.tl
index c0f392ee..082e0d9f 100644
--- a/tests/012/buf.tl
+++ b/tests/012/buf.tl
@@ -580,3 +580,34 @@
#b'2233445566778811 22334455667788'
(buf-xor-pattern #b'0000000000000000 00000000000000' #x-1122334455667788)
#b'1122334455667788 11223344556677')
+
+(mtest
+ (make-buf 1 #b'deadbeef') #b'ef'
+ (make-buf 2 #b'deadbeef') #b'beef'
+ (make-buf 3 #b'deadbeef') #b'adbeef'
+ (make-buf 4 #b'deadbeef') #b'deadbeef'
+ (make-buf 5 #b'deadbeef') #b'efdeadbeef')
+
+(mtest
+ (make-buf 1 #xdeadbeef) #b'ef'
+ (make-buf 2 #xdeadbeef) #b'beef'
+ (make-buf 3 #xdeadbeef) #b'adbeef'
+ (make-buf 4 #xdeadbeef) #b'deadbeef'
+ (make-buf 5 #xdeadbeef) #b'efdeadbeef')
+
+(mtest
+ (make-buf 1 #x-deadbeef) #b'de'
+ (make-buf 2 #x-deadbeef) #b'dead'
+ (make-buf 3 #x-deadbeef) #b'deadbe'
+ (make-buf 4 #x-deadbeef) #b'deadbeef'
+ (make-buf 5 #x-deadbeef) #b'deadbeefde')
+
+(let ((b (make-buf 0)))
+ (mtest
+ (buf-set-length b 3 #xff) 0 b #b'ffffff'
+ (buf-set-length b 9 #xdeadbeef) 3 b #b'ffffffbeefdeadbeef'
+ (buf-set-length b 1) 9 b #b'ff'
+ (buf-set-length b 2 #xdeadbeef) 1 b #b'ffef'
+ (buf-set-length b 3 #xdeadbeef) 2 b #b'ffefef'
+ (buf-set-length b 4 #x-deadbeef) 3 b #b'ffefefef'
+ (buf-set-length b 7 #x-deadbeef) 4 b #b'ffefefefdeadbe'))
diff --git a/txr.1 b/txr.1
index b7eb8f01..48c37097 100644
--- a/txr.1
+++ b/txr.1
@@ -28943,9 +28943,59 @@ The
function returns a value of type
.codn cptr .
+.NP* Fill Pattern Argument Conventions
+
+Several buffer functions accept a fill pattern argument,
+here referred to as
+.metn pat ,
+which specifies a repeating byte pattern to be applied in
+an operation. Those functions are:
+.codn make-buf ,
+.code buf-set-length
+and
+.codn buf-xor-pattern .
+
+If
+.meta pat
+is a negative integer, it specifies a left-aligned fill.
+In this case, the pattern is specified by the positive integer
+which is the additive inverse of the negative integer. If
+.meta pat
+is a buffer, the fill is always right-aligned.
+
+Left-aligned means that the the first byte of the to-be-filled buffer
+corresponds with the first byte of the pattern. Right aligned means that the
+last bytes of the buffer and pattern correspond.
+
+If
+.meta pat
+is a character, then it the character's code is taken
+as an integer pattern.
+
+An integer is turned into a pattern by dividing the integer's
+binary representation into octets, in a big-endian orientation.
+For instance the integer
+.code #x3FEDA
+is turned into the octets , given in hexadecimal:
+.codn 03 ,
+.code FE
+and
+.codn DA .
+The pattern has only as many bytes are are required to
+represent the integer value. Thus a value in the range
+0 to 255 specifies a one-byte pattern, a value in the
+range 256 to 65535 a two-byte pattern and so forth.
+
+If the pattern has fewer bytes than
+.meta buf
+then it is repeated. Any repetition of the pattern
+which doesn't fit into the buffer length is truncated
+on the opposite side of the alignment mode: truncated
+on the left under right alignment and vice versa.
+
.coNP Function @ make-buf
.synb
-.mets (make-buf < len >> [ init-val <> [ alloc-size ]])
+.mets (make-buf < len >> [ init-pat <> [ alloc-size ]])
.syne
.desc
The
@@ -28954,15 +29004,12 @@ function creates a new buffer object which holds
.meta len
bytes. This argument may be zero.
-If
-.meta init-val
-is present, it specifies the value with which the first
-.meta len
-bytes of the buffer are initialized. If omitted, it
-defaults to zero.
-The value of
-.meta init-val
-must lie in the range 0 to 255.
+The
+.meta init-pat
+argument, defaulting to zero if absent, specifies
+the fill pattern for the buffer.
+For details about its semantics, see the section
+Fill Pattern Argument Conventions.
The
.meta alloc-size
@@ -29035,12 +29082,20 @@ The
.code buf-set-length
function changes the length of the buffer. If the buffer
is made longer, the newly added bytes appear at the end,
-and are initialized to the value given by
-.metn init-val .
-If
-.meta init-val
-is specified, its value must be in the range 0 to 255.
-It defaults to zero.
+and are initialized according to the pattern given by
+.metn init-pat ,
+which defaults to zero.
+
+The semantics of
+.meta init-pat
+are given in detail in the section Fill Pattern Argument Conventions.
+
+The alignment of
+.meta init-pat
+is considered against the entire resized buffer, as if the
+entire buffer were to be filled with the pattern. However
+the pattern is only written to newly allocated bytes;
+no existing bytes are overwritten.
.coNP Function @ copy-buf
.synb
@@ -30593,41 +30648,21 @@ and
The
.meta pat
-argument may be an integer or a buffer.
+argument may be an integer or a buffer. For details, see
+the section Fill Pattern Argument Conventions.
-If
+For the purposes of the exclusive "or" operation,
.meta pat
-is a negative integer, it specifies a left-aligned operation.
-In this case, the pattern is specified by the positive integer
-which is the additive inverse of the negative integer. If
-.meta pat
-is a buffer, the operation is always right-aligned.
-
-Left-aligned means that the the first byte of the buffer
-corresponds with the first byte of the pattern. Right
-aligned means that the last bytes of the buffer and pattern
-correspond.
-
-An integer is turned into a pattern by dividing the integer's
-binary representation into octets, in a big-endian orientation.
-For instance the integer
-.code #x3FEDA
-is turned into the octets , given in hexadecimal:
-.codn 03 ,
-.code FE
-and
-.codn DA .
-The pattern has only as many bytes are are required to
-represent the integer value. Thus a value in the range
-0 to 255 specifies a one-byte pattern, a value in the
-range 256 to 65535 a two-byte pattern and so forth.
+is converted to a buffer of the same size as
+.metn buf ,
+filled with the pattern denoted by
+.metn pat .
-If the pattern has fewer bytes than
+The operation then proceeds as if
+.code buf-xor
+were applied to
.meta buf
-then it is repeated. Any repetition of the pattern
-which doesn't fit into the buffer length is truncated
-on the opposite side of the alignment mode: truncated
-on the left under right alignment and vice versa.
+and the pattern buffer.
.TP* Examples