summaryrefslogtreecommitdiffstats
path: root/buf.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2025-05-30 06:00:40 -0700
committerKaz Kylheku <kaz@kylheku.com>2025-05-30 06:00:40 -0700
commitb17df7c06379615e4d1d1f912d6e57fb125294d1 (patch)
tree30b0caffb4b784c622214e722b99f3d5133e9405 /buf.c
parentedfe34e241aafe19e6b29840e18ce318a2d22d61 (diff)
downloadtxr-b17df7c06379615e4d1d1f912d6e57fb125294d1.tar.gz
txr-b17df7c06379615e4d1d1f912d6e57fb125294d1.tar.bz2
txr-b17df7c06379615e4d1d1f912d6e57fb125294d1.zip
buf: use C types in buf and buf_strm structures.
Using Lisp types for lengths, indices and buffer sizes has been awkward due to all the conversions. The code in buf.c and other code elsewhere that touches buffers, overall improves when we revise this decision. Mostly there are fewer conversion from Lisp to C which require a type check and self symbol for error diagnsotis, like c_unum(len, self). In a few places, there are conversions in the other direction that were not needed before, like unum(b->len). These are simpler and faster. * lib.h (struct buf): Members len and size change from val to ucnum (pointer-sized unsigned integer). * gc.c (mark_obj): No need to do anything with BUF any more; it has no Lisp object references. * buf.c (BUR_BORROWED): New preprocessor symbol. Because the allocation size can no longer be nil to indicate that the buffer is borrowed (the buffer object doesn't own the memory) we use this value instead: the highest value of the ucnum type. (buf_check_alloc_size): len parameter changes from cnum to ucnum. Defends against the BUF_BORROWED value. (buf_check_index): Returns ucnum rather than cnum. (err_oflow): NORETURN attribute added to prevent some spurious compiler warnings. (prepare_pattern): Drop c_unum conversion of len. (make_buf): Some locals change from cnum to ucnum. We lose an unnecessary conversion. (init_borrowed_buf): Take len as ucnum rather than val. Use BUF_BORROWED value for allocated size to indicate borrowed status. (make_borrowed_buf): Take len as ucnum. (make_duplicate_buf, make_owned_buf): Take len as ucnum, and take a self argument. Check for the size being BUF_BORROWED and reject. (make_ubuf): Parameter renamed. Lose a conversion from ucnum to val. (copy_buf): Check for allocated size being BUF_BORROWED to distinguish the two cases, rather than it being nil or not. (buf_shrink): Simplifies: loses a C to Lisp integer conversion, and no longer needs the local variable self. (buf_trim): Reject borrowed buffers by noticing the BUF_BORROWED value. (buf_do_set_len): len param becomes ucnum. Two Lisp-to-C integer conversiond disappear; one C-to-Lisp moves elsewhere in the code. (buf_set_length): Use buf_check_len to check and convert incoming len to ucnum. This is an improvement over the previous approach of letting buf_do_set_len to just rely on c_num conversions and their generic diagnostics. (buf_free): Check for borrowed buffer by comparing allocated size to BUF_BORROWED constant. (length_buf): ucnum to Lisp conversion now required here. (buf_alloc_size): Check for alloc_size being BUF_BORROWED and convert that to a nil return value. When returning an integer size, we need a conversion to a Lisp integer. (sub_buf): Use self symbol rather than lit("sub") when obtaining buffer handle. Use buf_check_len to validate the length and convert to C type. (replace_buf): Some cnum local variables become ucnum. We need a very careful comparison of w and l because w remains signed while l is unsigned. (buf_list): Substantially rewritten. We don't calculate the length of the sequence upfront, but extend the buffer as we add the elements to it. (buf_move_bytes): size parameter changes from cnum to ucnum. Lisp arithmetic replaced with C arithmetic; conversions eliminated. (buf_put_buf): Conversion eliminated in call to buf_move_bytes. (buf_put_bytes): Function reduced to wrapper for but_move_bytes, since it is almost identical. The only difference is that it performs memcpy rather than memmove which is not worth a separate function. (buf_put_i8, buf_put_u8, buf_put_char, buf_put_uchar, buf_get_i8, buf_get_u8): Simplified with C arithmetic and fewer conversions; cnum use replaced with ucnum. (buf_get_bytes): size parameter goes from cnum to ucnum. Overflow check for p + size addition added. (buf_print): Two conversions removed. (buf_str_sep): Conversion removed. (struct buf_strm): pos member changes from val to ucnum. (buf_strm_mark): Do not mark p->pos, no longer a Lisp object. (buf_strm_put_byte_callback): Lisp arithmetic removed, but a unum conversion is needed now in calling buf_put_uchar. That could be eliminated by not using the public interface. (buf_strm_get_byte_callback): Eliminate buf_check_index to validate the stream position; we simply check it against b->len. Becomes simple one liner. (buf_strm_get_char): Local variable index renamd to pos. Two conversions from and to Lisp eliminated, leaving no conversions. (buf_strm_unget_byte): Local variable p renamed to pos and changes from cnum to ucnum. Two conversions eliminated leaving no conversions. (buf_strm_fill_buf): Conversions eliminated. Check for the allocated size being BUF_BORROWED, in which case we fall back on using the length. Lisp arithmetic eliminated. (buf_strm_seek): Offset calculation done with C arithmetic and bounds checks. (buf_strm_truncate): Check incoming len with buf_check_len and convert to ucnum. Lisp arithmetic and conversions eliminated; buf_do_set_len used instead of public interface buf_set_length. (buf_strm_get_error): Use C comparison rather than ge function, and convert to t or nil result. (buf_strm_get_error_str): Bug: do not call errno_to_string since buffers don't talk to an operating system API that uses errno. The only error condition is eof. Thus, return either "eof" or "no error". (make_buf_stream): Initialize pos to 0 rather than Lisp zero. (swap32, buf_str, str_buf, buf_int, buf_uint, int_buf, uint_buf): Conversions eliminated; int_buf and uint_buf use C multiplication by 8. We know this doesn't overflow because the MPI bignums restrict the number of bits to something countable by a word. (buf_compress, buf_decompress, str_compress, str_decompress): Conversions eliminated. (buf_ash, buf_fash, buf_and, buf_test, buf_or, buf_xor, buf_not, buf_trunc, buf_bitset, buf_bit, buf_zero_p, buf_count_ones, binary_width, buf_xor_pattern): Make necessary adjustments, adding and/or elimiating conversions. * buf.h (make_borrowed_buf, init_borrowed_buf, make_owned_buf, make_duplicate_buf, buf_put_bytes): Declarations updated. * lib.c (equal, less): Conversions eliminated in BUF cases. * eval.c (map_common): Add self argument to make_owned_buf call. * chksum.c (chksum_ensure_buf): len param changes from cnum to ucnum. Conversions eliminated and use of lt() switches to C less-than operator. (sha1_stream, sha1_buf, sha1, sha1_hash, sha1_end, sha256_stream, sha256_buf, sha256, sha256_hash, sha256_end, md5_stream, md5_buf, md5, md5_hash, md5_end): Adjustments: conversions eliminated. (crc32_buf): Conversion eliminated. * genchksum.txr: Changes to chksum.c actually made here. * ffi.c (ffi_buf_in, ffi_buf_get, ffi_buf_d_in, ffi_buf_d_get, buf_carray, put_carray, fill_carray, put_obj, get_obj): Simplified with removal of conversions. (fill_obj): Necessary adjustments, leaving same number of conversions. * hash.c (equal_hash): Remove conversion from BUF case. * rand.c (make_random_state): Remove conversion of seed to Lisp integer. (random_buf): Pass self to make_owned_buf. * strudel.c (strudel_unget_byte, strudel_fill_buf): Coversions removed, streamlining code. * stream.c (iobuf_get, iobuf_put): We cannot overload the len field with serving as a linked list since it's no longer a pointer. We instead use the struct any union member, which has a next pointer for this purpose. Because "t.next" overlaps with "b.size", and we must not clobber the size field, we save "b.size" by copying it into "b.len". When pulling buffers from the iobuf_free_list, we restore b.size from b.len. For good measure, We add a bug_unless assertion that the size is the expected one. I ran into a test case failure while working on this due to the size being clobbered to zero, and subsequent I/O with that zero-sized buffer being interpreted as EOF.
Diffstat (limited to 'buf.c')
-rw-r--r--buf.c422
1 files changed, 225 insertions, 197 deletions
diff --git a/buf.c b/buf.c
index 41de5b28..73695e7d 100644
--- a/buf.c
+++ b/buf.c
@@ -52,40 +52,64 @@
#include "txr.h"
#include "buf.h"
+#define BUF_BORROWED UINT_PTR_MAX
+
#define min(a, b) ((a) < (b) ? (a) : (b))
static struct buf *buf_handle(val buf, val ctx);
-static cnum buf_check_len(val len, val self)
+static ucnum buf_check_len(val len, val self)
{
- cnum l = c_num(len, self);
- if (l < 0)
+ if (minusp(len)) {
uw_throwf(error_s, lit("~a: negative length ~s specified"),
self, len, nao);
- return l;
+ } else {
+ ucnum l = c_unum(len, self);
+
+ if (l == BUF_BORROWED)
+ uw_throwf(error_s, lit("~a: reserved length value ~s specified"),
+ self, len, nao);
+
+ return l;
+ }
}
-static cnum buf_check_alloc_size(val alloc_size, cnum len, val self)
+static ucnum buf_check_alloc_size(val alloc_size, ucnum len, val self)
{
- cnum ah = c_num(alloc_size, self);
- if (ah < len)
+ ucnum as = c_unum(alloc_size, self);
+
+ if (as == BUF_BORROWED)
+ uw_throwf(error_s, lit("~a: reserved alloc size value ~s specified"),
+ self, alloc_size, nao);
+
+ if (as < len)
uw_throwf(error_s, lit("~a: alloc size size ~s lower than length"),
self, alloc_size, nao);
- return ah;
+
+ return as;
}
-static cnum buf_check_index(struct buf *b, val index, val self)
+static ucnum buf_check_index(struct buf *b, val index_in, val self)
{
- cnum ix = c_num(index, self);
- if (ix < 0)
- ix = c_num(plus(b->len, index), self);
- if (ix < 0)
+ val index = minusp(index_in) ? plus(unum(b->len), index_in) : index_in;
+ ucnum ix;
+
+ if (minusp(index)) {
uw_throwf(error_s, lit("~a: negative byte index ~s specified"),
self, index, nao);
+ }
+
+ ix = c_unum(index, self);
+
+ if (ix >= BUF_BORROWED - 1) {
+ uw_throwf(error_s, lit("~a: index ~s disallowed"),
+ self, index, nao);
+ }
+
return ix;
}
-static void err_oflow(val self)
+NORETURN static void err_oflow(val self)
{
uw_throwf(error_s, lit("~a: array size overflow"), self, nao);
}
@@ -137,7 +161,7 @@ static void prepare_pattern(mem_t **ppat, mem_t **pfree, mem_t pbuf[SIZEOF_PTR],
case BUF:
{
struct buf *pb = buf_handle(pat, self);
- ucnum l = c_unum(pb->len, self);
+ ucnum l = pb->len;
if (l > 0) {
*ppat = pb->data;
@@ -157,9 +181,9 @@ 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);
+ ucnum 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);
+ ucnum size = buf_check_alloc_size(alloc, blen, self);
mem_t *data = if3(pat == zero && size == blen,
chk_calloc(size, 1),
chk_malloc(size));
@@ -168,8 +192,8 @@ val make_buf(val len, val init_pat, val alloc_size)
obj->b.type = BUF;
obj->b.data = data;
- obj->b.len = len;
- obj->b.size = num(size);
+ obj->b.len = blen;
+ obj->b.size = size;
if ((is_num(pat) || is_chr(pat)) &&
-256 < (iv = c_num(pat, self)) && iv < 256)
@@ -210,45 +234,51 @@ val bufp(val object)
return tnil(type(object) == BUF);
}
-val init_borrowed_buf(obj_t *obj, val len, mem_t *data)
+val init_borrowed_buf(obj_t *obj, ucnum len, mem_t *data)
{
obj->b.type = BUF;
obj->b.data = data;
obj->b.len = len;
- obj->b.size = nil;
+ obj->b.size = BUF_BORROWED;
return obj;
}
-val make_borrowed_buf(val len, mem_t *data)
+val make_borrowed_buf(ucnum len, mem_t *data)
{
return init_borrowed_buf(make_obj(), len, data);
}
-val make_duplicate_buf(val len, mem_t *data)
+val make_duplicate_buf(ucnum len, mem_t *data, val self)
{
- val self = lit("make-duplicate-buf");
- val obj = make_obj();
+ if (len < BUF_BORROWED) {
+ val obj = make_obj();
- obj->b.type = BUF;
- obj->b.data = chk_copy_obj(data, c_num(len, self));
- obj->b.len = len;
- obj->b.size = len;
+ obj->b.type = BUF;
+ obj->b.data = chk_copy_obj(data, len);
+ obj->b.len = len;
+ obj->b.size = len;
- return obj;
+ return obj;
+ } else {
+ err_oflow(self);
+ }
}
-val make_owned_buf(val len, mem_t *data)
+val make_owned_buf(ucnum len, mem_t *data, val self)
{
- val buf = make_borrowed_buf(len, data);
- buf->b.size = len;
- return buf;
+ if (len < BUF_BORROWED) {
+ val buf = make_borrowed_buf(len, data);
+ buf->b.size = len;
+ return buf;
+ } else {
+ err_oflow(self);
+ }
}
-static val make_ubuf(ucnum clen)
+static val make_ubuf(ucnum len)
{
- mem_t *data = chk_malloc(clen);
- val len = unum(clen);
+ mem_t *data = chk_malloc(len);
val buf = make_borrowed_buf(len, data);
buf->b.size = len;
return buf;
@@ -269,22 +299,22 @@ INLINE struct buf *us_buf_handle(val buf)
val copy_buf(val buf)
{
- struct buf *b = buf_handle(buf, lit("copy-buf"));
- return if3(b->size,
- make_duplicate_buf(b->len, b->data),
+ val self = lit("copy-buf");
+ struct buf *b = buf_handle(buf, self);
+ return if3(b->size != BUF_BORROWED,
+ make_duplicate_buf(b->len, b->data, self),
make_borrowed_buf(b->len, b->data));
}
static void buf_shrink(struct buf *b)
{
- val self = lit("buf-trim");
- val len = b->len;
+ ucnum len = b->len;
- if (len == zero)
- len = succ(len); /* avoid reallocing to zero length; i.e. freeing */
+ if (len == 0)
+ len = 1; /* avoid zero size realloc */
if (len != b->size) {
- b->data = chk_realloc(b->data, c_unum(len, self));
+ b->data = chk_realloc(b->data, len);
b->size = b->len;
}
}
@@ -293,27 +323,25 @@ val buf_trim(val buf)
{
val self = lit("buf-trim");
struct buf *b = buf_handle(buf, self);
- val oldsize = b->size;
- if (!oldsize)
+ ucnum oldsize = b->size;
+ if (oldsize == BUF_BORROWED)
uw_throwf(error_s, lit("~a: ~s is a fixed buffer"),
self, buf, nao);
buf_shrink(b);
- return oldsize;
+ return unum(oldsize);
}
-static val buf_do_set_len(val buf, struct buf *b, val newlen,
+static val buf_do_set_len(val buf, struct buf *b, ucnum len,
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;
+ ucnum olen = b->len;
+ ucnum oldsize = b->size, size = oldsize;
- if (!b->size)
+ if (b->size == BUF_BORROWED)
uw_throwf(error_s, lit("~a: ~s is a fixed buffer"),
self, buf, nao);
- (void) buf_check_len(newlen, self);
- b->len = newlen;
+ b->len = len;
if (size < len) {
if (size > INT_PTR_MAX - INT_PTR_MAX / 5) {
@@ -327,7 +355,7 @@ static val buf_do_set_len(val buf, struct buf *b, val newlen,
if (size > oldsize) {
b->data = chk_realloc(b->data, size);
- b->size = num(size);
+ b->size = size;
}
if (len > olen) {
@@ -364,24 +392,24 @@ static val buf_do_set_len(val buf, struct buf *b, val newlen,
}
}
- return oldlen;
+ return unum(olen);
}
val buf_set_length(val buf, val len, val init_val)
{
val self = lit("buf-set-len");
struct buf *b = buf_handle(buf, self);
- return buf_do_set_len(buf, b, len, init_val, self);
+ ucnum l = buf_check_len(len, self);
+ return buf_do_set_len(buf, b, l, init_val, self);
}
val buf_free(val buf)
{
val self = lit("buf-free");
struct buf *b = buf_handle(buf, self);
- if (b->size) {
+ if (b->size != BUF_BORROWED) {
free(b->data);
b->data = 0;
- b->len = b->size = zero;
return t;
}
return nil;
@@ -391,14 +419,14 @@ val length_buf(val buf)
{
val self = lit("length-buf");
struct buf *b = buf_handle(buf, self);
- return b->len;
+ return unum(b->len);
}
val buf_alloc_size(val buf)
{
val self = lit("buf-alloc-size");
struct buf *b = buf_handle(buf, self);
- return b->size;
+ return b->size == BUF_BORROWED ? nil : unum(b->size);
}
mem_t *buf_get(val buf, val self)
@@ -410,8 +438,8 @@ mem_t *buf_get(val buf, val self)
val sub_buf(val buf, val from, val to)
{
val self = lit("sub-buf");
- struct buf *b = buf_handle(buf, lit("sub"));
- val len = b->len;
+ struct buf *b = buf_handle(buf, self);
+ val len = unum(b->len);
if (null_or_missing_p(from))
from = zero;
@@ -436,7 +464,8 @@ val sub_buf(val buf, val from, val to)
} else if (from == zero && to == len) {
return buf;
} else {
- return make_duplicate_buf(minus(to, from), b->data + c_num(from, self));
+ return make_duplicate_buf(buf_check_len(minus(to, from), self),
+ b->data + c_num(from, self), self);
}
}
@@ -451,8 +480,8 @@ val replace_buf(val buf, val items, val from, val to)
from = len;
} else if (!integerp(from)) {
seq_iter_t wh_iter, item_iter;
- cnum offs = 0;
- cnum l = c_num(len, self), ol = l;
+ ucnum offs = 0;
+ ucnum l = c_unum(len, self), ol = l;
val wh, item;
seq_iter_init(self, &wh_iter, from);
seq_iter_init(self, &item_iter, items);
@@ -480,7 +509,7 @@ val replace_buf(val buf, val items, val from, val to)
w -= offs;
- if (w >= l)
+ if (l <= INT_PTR_MAX && w >= convert(cnum, l))
break;
memmove(buf->b.data + w,
@@ -516,8 +545,8 @@ val replace_buf(val buf, val items, val from, val to)
if (gt(len_rep, len_it)) {
val len_diff = minus(len_rep, len_it);
- cnum t = c_num(to, self);
- cnum l = c_num(len, self);
+ ucnum t = c_unum(to, self);
+ ucnum l = c_unum(len, self);
memmove(buf->b.data + t - c_num(len_diff, self),
buf->b.data + t,
@@ -527,8 +556,8 @@ val replace_buf(val buf, val items, val from, val to)
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, self);
- cnum l = c_num(len, self);
+ ucnum t = c_unum(to, self);
+ ucnum l = c_unum(len, self);
buf_set_length(buf, plus(len, len_diff), zero);
@@ -544,8 +573,8 @@ val replace_buf(val buf, val items, val from, val to)
memmove(buf->b.data + c_num(from, self), items->b.data, c_num(len_it, self));
} else {
seq_iter_t item_iter;
- cnum f = c_num(from, self);
- cnum t = c_num(to, self);
+ ucnum f = c_unum(from, self);
+ ucnum t = c_unum(to, self);
seq_iter_init(self, &item_iter, items);
@@ -562,26 +591,29 @@ val replace_buf(val buf, val items, val from, val to)
val buf_list(val list)
{
val self = lit("buf-list");
- val len = length(list);
- val buf = make_buf(zero, zero, len);
+ val buf = make_buf(zero, zero, num_fast(32));
+ struct buf *b = us_buf_handle(buf);
seq_iter_t iter;
val elem;
- cnum i;
-
- for (i = 0, seq_iter_init(self, &iter, list); seq_get(&iter, &elem); i++)
- buf->b.data[i] = c_uchar(elem, self);
+ ucnum i;
- buf->b.len = len;
+ for (i = 0, seq_iter_init(self, &iter, list); seq_get(&iter, &elem); i++) {
+ if (i + 1 < i)
+ err_oflow(self);
+ buf_do_set_len(buf, b, i + 1, elem, self);
+ }
return buf;
}
-static void buf_move_bytes(val buf, val pos, mem_t *ptr, cnum size, val self)
+static void buf_move_bytes(val buf, val pos, mem_t *ptr, ucnum size, val self)
{
struct buf *b = buf_handle(buf, self);
- cnum p = buf_check_index(b, pos, self);
- val req_len = plus(num(p), num(size));
- if (gt(req_len, b->len))
+ ucnum p = buf_check_index(b, pos, self);
+ ucnum req_len = p + size;
+ if (req_len < p)
+ err_oflow(self);
+ if (req_len > b->len)
buf_do_set_len(buf, b, req_len, nil, self);
memmove(b->data + p, ptr, size);
}
@@ -590,7 +622,7 @@ val buf_put_buf(val dbuf, val pos, val sbuf)
{
val self = lit("buf-put-buf");
struct buf *sb = buf_handle(sbuf, self);
- buf_move_bytes(dbuf, pos, sb->data, c_num(sb->len, self), self);
+ buf_move_bytes(dbuf, pos, sb->data, sb->len, self);
return sbuf;
}
@@ -602,14 +634,9 @@ static val compat_buf_put_buf(val dbuf, val pos, val sbuf)
return buf_put_buf(dbuf, pos, sbuf);
}
-void buf_put_bytes(val buf, val pos, mem_t *ptr, cnum size, val self)
+void buf_put_bytes(val buf, val pos, mem_t *ptr, ucnum size, val self)
{
- struct buf *b = buf_handle(buf, self);
- cnum p = buf_check_index(b, pos, self);
- val req_len = plus(num(p), num(size));
- if (gt(req_len, b->len))
- buf_do_set_len(buf, b, req_len, nil, self);
- memcpy(b->data + p, ptr, size);
+ return buf_move_bytes(buf, pos, ptr, size, self);
}
#if HAVE_I8
@@ -617,10 +644,10 @@ val buf_put_i8(val buf, val pos, val num)
{
val self = lit("buf-put-i8");
struct buf *b = buf_handle(buf, self);
- cnum p = buf_check_index(b, pos, self);
+ ucnum p = buf_check_index(b, pos, self);
i8_t v = c_i8(num, self);
- if (p >= c_num(b->len, self))
- buf_do_set_len(buf, b, succ(pos), nil, self);
+ if (p >= b->len)
+ buf_do_set_len(buf, b, p + 1, nil, self);
b->data[p] = v;
return num;
}
@@ -629,10 +656,10 @@ val buf_put_u8(val buf, val pos, val num)
{
val self = lit("buf-put-u8");
struct buf *b = buf_handle(buf, self);
- cnum p = buf_check_index(b, pos, self);
+ ucnum p = buf_check_index(b, pos, self);
cnum v = c_u8(num, self);
- if (p >= c_num(b->len, self))
- buf_do_set_len(buf, b, succ(pos), nil, self);
+ if (p >= b->len)
+ buf_do_set_len(buf, b, p + 1, nil, self);
b->data[p] = v;
return num;
}
@@ -696,10 +723,10 @@ val buf_put_char(val buf, val pos, val num)
{
val self = lit("buf-put-char");
struct buf *b = buf_handle(buf, self);
- cnum p = buf_check_index(b, pos, self);
+ ucnum p = buf_check_index(b, pos, self);
char v = c_char(num, self);
- if (p >= c_num(b->len, self))
- buf_do_set_len(buf, b, succ(pos), nil, self);
+ if (p >= b->len)
+ buf_do_set_len(buf, b, p + 1, nil, self);
b->data[p] = v;
return num;
}
@@ -708,10 +735,10 @@ val buf_put_uchar(val buf, val pos, val num)
{
val self = lit("buf-put-uchar");
struct buf *b = buf_handle(buf, self);
- cnum p = buf_check_index(b, pos, self);
+ ucnum p = buf_check_index(b, pos, self);
unsigned char v = c_uchar(num, self);
- if (p >= c_num(b->len, self))
- buf_do_set_len(buf, b, succ(pos), nil, self);
+ if (p >= b->len)
+ buf_do_set_len(buf, b, p + 1, nil, self);
b->data[p] = v;
return num;
}
@@ -794,14 +821,17 @@ val buf_put_cptr(val buf, val pos, val cptr)
return cptr;
}
-void buf_get_bytes(val buf, val pos, mem_t *ptr, cnum size, val self)
+void buf_get_bytes(val buf, val pos, mem_t *ptr, ucnum size, val self)
{
struct buf *b = buf_handle(buf, self);
- cnum p = buf_check_index(b, pos, self);
- cnum e = p + size;
- cnum l = c_num(b->len, self);
+ ucnum p = buf_check_index(b, pos, self);
+ ucnum e = p + size;
+ ucnum l = b->len;
- if (e > l || e < 0)
+ if (e < p)
+ err_oflow(self);
+
+ if (e > l)
uw_throwf(error_s, lit("~a: attempted read past buffer end"), self, nao);
memcpy(ptr, b->data + p, size);
@@ -812,8 +842,8 @@ val buf_get_i8(val buf, val pos)
{
val self = lit("buf-get-i8");
struct buf *b = buf_handle(buf, self);
- cnum p = buf_check_index(b, pos, self);
- if (p >= c_num(b->len, self))
+ ucnum p = buf_check_index(b, pos, self);
+ if (p >= b->len)
uw_throwf(error_s, lit("~a: attempted read past buffer end"), self, nao);
return num_fast(convert(i8_t, b->data[p]));
}
@@ -822,8 +852,8 @@ val buf_get_u8(val buf, val pos)
{
val self = lit("buf-get-u8");
struct buf *b = buf_handle(buf, self);
- cnum p = buf_check_index(b, pos, self);
- if (p >= c_num(b->len, self))
+ ucnum p = buf_check_index(b, pos, self);
+ if (p >= b->len)
uw_throwf(error_s, lit("~a: attempted read past buffer end"), self, nao);
return num_fast(convert(u8_t, b->data[p]));
}
@@ -996,7 +1026,7 @@ val buf_print(val buf, val stream_in)
val self = lit("buf-print");
val stream = default_arg(stream_in, std_output);
struct buf *b = buf_handle(buf, self);
- cnum len = c_num(b->len, self), count = 0;
+ ucnum len = b->len, count = 0;
mem_t *data = b->data;
val save_mode = test_neq_set_indent_mode(stream, num_fast(indent_foff),
num_fast(indent_data));
@@ -1028,7 +1058,7 @@ val buf_pprint(val buf, val stream_in)
val self = lit("buf-pprint");
val stream = default_arg(stream_in, std_output);
struct buf *b = buf_handle(buf, self);
- cnum len = c_num(b->len, self);
+ ucnum len = b->len;
mem_t *data = b->data;
if (opt_compat && opt_compat <= 294) {
@@ -1045,7 +1075,7 @@ val buf_pprint(val buf, val stream_in)
val buf_str_sep(val buf, val sep, val self)
{
struct buf *b = buf_handle(buf, self);
- ucnum len = c_unum(b->len, self);
+ ucnum len = b->len;
val ret = null_string;
if (len > 0) {
@@ -1085,7 +1115,7 @@ struct buf_strm {
utf8_decoder_t ud;
int is_byte_oriented;
val buf;
- val pos;
+ ucnum pos;
};
static void buf_strm_mark(val stream)
@@ -1093,14 +1123,13 @@ static void buf_strm_mark(val stream)
struct buf_strm *b = coerce(struct buf_strm *, stream->co.handle);
strm_base_mark(&b->a);
gc_mark(b->buf);
- gc_mark(b->pos);
}
static int buf_strm_put_byte_callback(int b, mem_t *ctx)
{
struct buf_strm *s = coerce(struct buf_strm *, ctx);
- (void) buf_put_uchar(s->buf, s->pos, num_fast(b));
- s->pos = succ(s->pos);
+ (void) buf_put_uchar(s->buf, unum(s->pos), num_fast(b));
+ s->pos++;
return 1;
}
@@ -1134,12 +1163,9 @@ static val buf_strm_put_byte(val stream, int b)
static int buf_strm_get_byte_callback(mem_t *ctx)
{
- val self = lit("get-byte");
struct buf_strm *s = coerce(struct buf_strm *, ctx);
struct buf *b = us_buf_handle(s->buf);
- cnum p = buf_check_index(b, s->pos, self);
- s->pos = num(p + 1);
- return (p >= c_num(b->len, self)) ? EOF : b->data[p];
+ return (s->pos >= b->len) ? EOF : b->data[s->pos++];
}
static val buf_strm_get_char(val stream)
@@ -1173,22 +1199,22 @@ static val buf_strm_unget_char(val stream, val ch)
struct buf *b = us_buf_handle(s->buf);
struct utf8_tiny_buf bu;
unsigned char *bend = bu.buf + sizeof bu.buf;
- ucnum index = c_unum(s->pos, self);
+ ucnum pos = s->pos;
bu.ptr = bend;
(void) utf8_encode(c_chr(ch), utf8_tiny_buf_putc, coerce(mem_t *, &bu));
- if (convert(size_t, bend - bu.ptr) > index) {
+ if (convert(size_t, bend - bu.ptr) > pos) {
uw_throwf(file_error_s,
lit("~a: cannot push back past start of stream ~s"),
stream, self, nao);
}
while (bu.ptr < bend)
- b->data[--index] = *bu.ptr++;
+ b->data[--pos] = *bu.ptr++;
- s->pos = unum(index);
+ s->pos = pos;
return ch;
}
@@ -1198,16 +1224,16 @@ static val buf_strm_unget_byte(val stream, int byte)
val self = lit("unget-byte");
struct buf_strm *s = coerce(struct buf_strm *, stream->co.handle);
struct buf *b = us_buf_handle(s->buf);
- cnum p = c_num(s->pos, self);
+ ucnum pos = s->pos;
- if (p <= 0) {
+ if (pos <= 0) {
uw_throwf(file_error_s,
lit("~a: cannot push back past start of stream ~s"),
self, stream, nao);
}
- b->data[--p] = byte;
- s->pos = num(p);
+ b->data[--pos] = byte;
+ s->pos = pos;
return num_fast(byte);
}
@@ -1222,12 +1248,12 @@ static ucnum buf_strm_fill_buf(val stream, mem_t *ptr, ucnum len, ucnum pos)
if (pos >= len) {
return len;
} else {
- size_t index = c_unum(s->pos, self);
size_t room = len - pos;
- size_t avail = c_u(b->size) - index;
+ size_t blen = b->size == BUF_BORROWED ? b->len : b->size;
+ size_t avail = blen - s->pos;
size_t copy = min(room, avail);
- memcpy(ptr + pos, b->data + index, copy);
- s->pos = plus(s->pos, unum(copy));
+ memcpy(ptr + pos, b->data + s->pos, copy);
+ s->pos += copy;
return pos + copy;
}
}
@@ -1238,31 +1264,35 @@ static val buf_strm_seek(val stream, val offset, enum strm_whence whence)
val self = lit("seek-stream");
struct buf_strm *s = coerce(struct buf_strm *, stream->co.handle);
struct buf *b = us_buf_handle(s->buf);
- val npos;
+ cnum off = c_num(offset, self);
+ ucnum npos;
+ ucnum from;
switch (whence) {
case strm_start:
- npos = offset;
+ from = 0;
break;
case strm_cur:
- if (offset == zero)
- return s->pos;
- npos = plus(s->pos, offset);
+ if (off == 0)
+ return unum(s->pos);
+ from = s->pos;
break;
case strm_end:
- npos = plus(b->len, offset);
+ from = b->len;
break;
default:
internal_error("invalid whence value");
}
+ npos = from + off;
- if (minusp(npos))
- uw_throwf(file_error_s, lit("~a: cannot seek to negative position ~s"),
- self, npos, nao);
+ if ((off >= 0 && npos < from) ||
+ (off < 0 && npos > from))
+ uw_throwf(file_error_s, lit("~a: overflow in seeking ~s bytes from ~s"),
+ self, offset, unum(from), nao);
- if (gt(npos, b->len))
- buf_set_length(s->buf, npos, zero);
+ if (npos > b->len)
+ buf_set_length(s->buf, unum(npos), zero);
s->pos = npos;
return t;
@@ -1271,19 +1301,15 @@ static val buf_strm_seek(val stream, val offset, enum strm_whence whence)
static val buf_strm_truncate(val stream, val len)
{
val self = lit("truncate-stream");
+ ucnum blen = buf_check_len(len, self);
struct buf_strm *s = coerce(struct buf_strm *, stream->co.handle);
struct buf *b = us_buf_handle(s->buf);
- if (ge(len, s->pos)) {
- buf_set_length(s->buf, len, zero);
- } else if (minusp(len)) {
- uw_throwf(file_error_s, lit("~a: negative length~s specified"),
- self, len, nao);
+ if (blen >= s->pos) {
+ buf_do_set_len(s->buf, b, blen, nil, self);
} else {
- cnum p = c_num(s->pos, self);
- cnum l = c_num(len, self);
- buf_set_length(s->buf, s->pos, zero);
- memset(b->data + l, 0, p - l);
+ buf_do_set_len(s->buf, b, s->pos, nil, self);
+ memset(b->data + blen, 0, s->pos - blen);
}
return t;
@@ -1319,12 +1345,12 @@ static val buf_strm_get_error(val stream)
{
struct buf_strm *s = coerce(struct buf_strm *, stream->co.handle);
struct buf *b = us_buf_handle(s->buf);
- return ge(s->pos, b->len);
+ return tnil(s->pos >= b->len);
}
static val buf_strm_get_error_str(val stream)
{
- return errno_to_string(buf_strm_get_error(stream));
+ return buf_strm_get_error(stream) ? lit("eof") : lit("no error");
}
static struct strm_ops buf_strm_ops =
@@ -1378,7 +1404,7 @@ val make_buf_stream(val buf_opt)
strm_base_init(&s->a);
utf8_decoder_init(&s->ud);
s->buf = nil;
- s->pos = zero;
+ s->pos = 0;
s->is_byte_oriented = 0;
stream = cobj(coerce(mem_t *, s), stream_cls, &buf_strm_ops.cobj_ops);
s->buf = buf;
@@ -1397,7 +1423,7 @@ void buf_swap32(val buf)
{
val self = lit("buf-swap32");
struct buf *b = buf_handle(buf, self);
- mem_t *data = b->data, *end = data + c_num(b->len, self);
+ mem_t *data = b->data, *end = data + b->len;
for (; data + 3 < end; data += 4) {
u32_t sw32 = *coerce(u32_t *, data);
@@ -1413,7 +1439,7 @@ static val buf_str(val str, val null_term)
size_t sz;
val nt = default_null_arg(null_term);
unsigned char *u8 = utf8_dup_to_buf(c_str(str, self), &sz, nt != nil);
- return make_owned_buf(unum(sz), u8);
+ return make_owned_buf(sz, u8, self);
}
static val str_buf(val buf, val null_term)
@@ -1421,8 +1447,8 @@ static val str_buf(val buf, val null_term)
val self = lit("str-buf");
struct buf *b = buf_handle(buf, self);
val nt = default_null_arg(null_term);
- size_t blen = c_unum(b->len, self);
- size_t len = (nt && blen > 0 && !b->data[blen-1]) ? blen - 1 : blen;
+ size_t blen = b->len;
+ size_t len = (nt && blen > 0 && !b->data[blen - 1]) ? blen - 1 : blen;
wchar_t *str = utf8_dup_from_buf(coerce(const char *, b->data), len);
return string_own(str);
}
@@ -1451,7 +1477,7 @@ static val buf_int(val num)
mem_t *data = chk_malloc(bufsize);
data[0] = 0;
mp_to_unsigned_bin(m, data + (bufsize - numsize));
- return make_owned_buf(unum(bufsize), data);
+ return make_owned_buf(bufsize, data, self);
}
default:
uw_throwf(type_error_s, lit("~a: ~s isn't an integer or character"),
@@ -1476,7 +1502,7 @@ static val buf_uint(val num)
size_t size = mp_unsigned_bin_size(m);
mem_t *data = chk_malloc(size);
mp_to_unsigned_bin(m, data);
- return make_owned_buf(unum(size), data);
+ return make_owned_buf(size, data, self);
}
}
uw_throwf(type_error_s, lit("~a: ~s isn't a non-negative integer"),
@@ -1491,19 +1517,19 @@ static val int_buf(val buf)
{
val self = lit("int-buf");
struct buf *b = buf_handle(buf, self);
- ucnum size = c_unum(b->len, self);
+ ucnum size = b->len;
val ubn = make_bignum();
mp_err mpe = mp_read_unsigned_bin(mp(ubn), b->data, size);
if (mpe != MP_OKAY)
do_mp_error(self, mpe);
- return sign_extend(normalize(ubn), mul(b->len, num_fast(8)));
+ return sign_extend(normalize(ubn), unum(b->len * 8));
}
static val uint_buf(val buf)
{
val self = lit("uint-buf");
struct buf *b = buf_handle(buf, self);
- ucnum size = c_unum(b->len, self);
+ ucnum size = b->len;
val ubn = make_bignum();
mp_err mpe = mp_read_unsigned_bin(mp(ubn), b->data, size);
if (mpe != MP_OKAY)
@@ -1519,7 +1545,7 @@ static val buf_compress(val buf, val level_opt)
val level = default_arg(level_opt, negone);
int lev = c_int(level, self);
struct buf *b = buf_handle(buf, self);
- ucnum size = c_unum(b->len, self);
+ ucnum size = b->len;
uLong bound = compressBound(size), zsize = bound;
mem_t *zdata = chk_malloc(bound);
@@ -1534,14 +1560,14 @@ static val buf_compress(val buf, val level_opt)
}
zdata = chk_realloc(zdata, zsize);
- return make_owned_buf(unum(zsize), zdata);
+ return make_owned_buf(zsize, zdata, self);
}
static val buf_decompress(val buf)
{
val self = lit("buf-decompress");
struct buf *b = buf_handle(buf, self);
- ucnum zsize = c_unum(b->len, self);
+ ucnum zsize = b->len;
uLong zsz10 = 10 * zsize;
uLong size = if3(zsz10 > zsize, zsz10, convert(uLong, -1));
mem_t *data = chk_malloc(size);
@@ -1550,7 +1576,7 @@ static val buf_decompress(val buf)
switch (uncompress(data, &size, b->data, zsize)) {
case Z_OK:
data = chk_realloc(data, size);
- return make_owned_buf(unum(size), data);
+ return make_owned_buf(size, data, self);
case Z_BUF_ERROR:
if (size == convert(uLong, -1))
break;
@@ -1593,14 +1619,14 @@ static val str_compress(val str, val level_opt)
}
zdata = chk_realloc(zdata, zsize);
- return make_owned_buf(unum(zsize), zdata);
+ return make_owned_buf(zsize, zdata, self);
}
static val str_decompress(val buf)
{
val self = lit("str-decompress");
struct buf *b = buf_handle(buf, self);
- ucnum zsize = c_unum(b->len, self);
+ ucnum zsize = b->len;
uLong zsz10 = 10 * zsize;
uLong size = if3(zsz10 > zsize, zsz10, convert(uLong, -1));
mem_t *data = chk_malloc(size);
@@ -1642,7 +1668,7 @@ val buf_ash(val buf, val bits)
val self = lit("buf-ash");
cnum b = c_num(bits, self);
struct buf *bh = buf_handle(buf, self);
- ucnum len = c_unum(bh->len, self);
+ ucnum len = bh->len;
if (b == 0) {
return buf;
@@ -1721,7 +1747,7 @@ val buf_fash(val buf, val bits)
val self = lit("buf-ash");
cnum b = c_num(bits, self);
struct buf *bh = buf_handle(buf, self);
- ucnum len = c_unum(bh->len, self);
+ const ucnum len = bh->len;
if (b == 0 || len == 0) {
return buf;
@@ -1729,7 +1755,8 @@ val buf_fash(val buf, val bits)
ucnum bytes = b / 8;
if (bytes >= len) {
- return make_buf(bh->len, zero, bh->len);
+ val len = unum(bh->len);
+ return make_buf(len, zero, len);
} else {
ucnum r = b % 8;
unsigned acc = 0;
@@ -1753,7 +1780,8 @@ val buf_fash(val buf, val bits)
ucnum bytes = (-b) / 8;
if (bytes >= len) {
- return make_buf(bh->len, zero, bh->len);
+ val len = unum(bh->len);
+ return make_buf(len, zero, len);
} else {
ucnum r = (-b) % 8;
unsigned acc = 0;
@@ -1783,13 +1811,13 @@ val buf_and(val bufa, val bufb)
val self = lit("buf-and");
struct buf *ab = buf_handle(bufa, self);
struct buf *bb = buf_handle(bufb, self);
- ucnum la = c_unum(ab->len, self);
- ucnum lb = c_unum(bb->len, self);
+ ucnum la = ab->len;
+ ucnum lb = bb->len;
if (la == 0) {
- return make_buf(bb->len, zero, bb->len);
+ return make_buf(unum(bb->len), zero, unum(bb->len));
} else if (lb == 0) {
- return make_buf(ab->len, zero, ab->len);
+ return make_buf(unum(ab->len), zero, unum(ab->len));
} else if (la < lb) {
return buf_and(bufb, bufa);
} else {
@@ -1812,8 +1840,8 @@ val buf_test(val bufa, val bufb)
val self = lit("buf-test");
struct buf *ab = buf_handle(bufa, self);
struct buf *bb = buf_handle(bufb, self);
- ucnum la = c_unum(ab->len, self);
- ucnum lb = c_unum(bb->len, self);
+ ucnum la = ab->len;
+ ucnum lb = bb->len;
if (la == 0 || lb == 0 ) {
return nil;
@@ -1837,8 +1865,8 @@ val buf_or(val bufa, val bufb)
val self = lit("buf-or");
struct buf *ab = buf_handle(bufa, self);
struct buf *bb = buf_handle(bufb, self);
- ucnum la = c_unum(ab->len, self);
- ucnum lb = c_unum(bb->len, self);
+ ucnum la = ab->len;
+ ucnum lb = bb->len;
if (la == 0) {
return bufb;
@@ -1866,8 +1894,8 @@ val buf_xor(val bufa, val bufb)
val self = lit("buf-xor");
struct buf *ab = buf_handle(bufa, self);
struct buf *bb = buf_handle(bufb, self);
- ucnum la = c_unum(ab->len, self);
- ucnum lb = c_unum(bb->len, self);
+ ucnum la = ab->len;
+ ucnum lb = bb->len;
if (la == 0) {
return bufb;
@@ -1894,7 +1922,7 @@ val buf_not(val buf)
{
val self = lit("buf-not");
struct buf *b = buf_handle(buf, self);
- ucnum l = c_unum(b->len, self);
+ ucnum l = b->len;
if (l == 0) {
return buf;
@@ -1915,7 +1943,7 @@ val buf_trunc(val buf, val bits)
val self = lit("buf-trunc");
cnum b = c_num(bits, self);
struct buf *bh = buf_handle(buf, self);
- ucnum l = c_unum(bh->len, self);
+ ucnum l = bh->len;
if (b <= 0) {
return make_buf(zero, nil, zero);
@@ -1942,7 +1970,7 @@ val buf_bitset(val buf)
{
val self = lit("buf-bitset");
struct buf *b = buf_handle(buf, self);
- ucnum l = c_unum(b->len, self), i, j;
+ ucnum l = b->len, i, j;
list_collect_decl (out, ptail);
for (i = l - 1, j = 0; i != convert(ucnum, -1); --i, j++) {
@@ -1975,7 +2003,7 @@ val buf_bit(val buf, val bit)
{
val self = lit("buf-bit");
struct buf *bh = buf_handle(buf, self);
- ucnum l = c_unum(bh->len, self);
+ ucnum l = bh->len;
cnum b = c_num(bit, self);
if (b < 0) {
@@ -1995,7 +2023,7 @@ val buf_zero_p(val buf)
{
val self = lit("buf-zero-p");
struct buf *b = buf_handle(buf, self);
- ucnum l = c_unum(b->len, self), i;
+ ucnum l = b->len, i;
ucnum *ucdata = coerce(ucnum *, b->data);
for (i = 0; i < l / sizeof (ucnum); i++) {
@@ -2014,7 +2042,7 @@ val buf_count_ones(val buf)
{
val self = lit("buf-count-ones");
struct buf *b = buf_handle(buf, self);
- ucnum l = c_unum(b->len, self), i;
+ ucnum l = b->len, i;
ucnum *ucdata = coerce(ucnum *, b->data);
ucnum total[2] = { 0, 0 };
@@ -2079,7 +2107,7 @@ val buf_binary_width(val buf)
{
val self = lit("buf-bit-width");
struct buf *b = buf_handle(buf, self);
- ucnum l = c_unum(b->len, self), i;
+ ucnum l = b->len, i;
ucnum *ucdata = coerce(ucnum *, b->data);
ucnum zeros[2] = { 0, 0 };
int found = 0;
@@ -2167,7 +2195,7 @@ val buf_xor_pattern(val buf, val pat)
{
val self = lit("buf-xor-pattern");
struct buf *b = buf_handle(buf, self);
- ucnum l = c_unum(b->len, self), pl;
+ ucnum l = b->len, pl;
mem_t *p = 0, *fr = 0;
unsigned char pbuf[SIZEOF_PTR] = { 0 };
int left = 0;