diff options
-rw-r--r-- | buf.c | 77 | ||||
-rw-r--r-- | tests/012/buf.tl | 31 | ||||
-rw-r--r-- | txr.1 | 129 |
3 files changed, 181 insertions, 56 deletions
@@ -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')) @@ -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 |