Finish implementation of Byte String
This commit is contained in:
1 parent
2995b119b7
commit
8a1f30eeff
2 files changed
+214
-41
No files matched your search
+165
-41
@@ -29,14 +29,15 @@
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
// Type definition
|
||||
/* Byte String Type definition*/
|
||||
typedef struct m_bstring_s {
|
||||
size_t size;
|
||||
size_t alloc;
|
||||
size_t offset;
|
||||
uint8_t *ptr;
|
||||
size_t size; // Number of effective BYTES
|
||||
size_t alloc; // Size of the allocated buffer
|
||||
size_t offset; // Offset where the effective BYTES are stored in the allocated buffer
|
||||
uint8_t *ptr; // Pointer to the allocated buffer
|
||||
} m_bstring_t[1];
|
||||
|
||||
// Contract of a bstring
|
||||
#define M_BSTRING_CONTRACT(o) do { \
|
||||
M_ASSERT( (o)->size + (o)->offset >= (o)->size ); \
|
||||
M_ASSERT( (o)->alloc >= (o)->size + (o)->offset ); \
|
||||
@@ -47,18 +48,18 @@ M_INLINE size_t
|
||||
m_bstring_size(const m_bstring_t s)
|
||||
{
|
||||
M_BSTRING_CONTRACT(s);
|
||||
return (size_t) s->size;
|
||||
return s->size;
|
||||
}
|
||||
|
||||
M_INLINE size_t
|
||||
m_bstring_capacity(const m_bstring_t s)
|
||||
{
|
||||
M_BSTRING_CONTRACT(s);
|
||||
return (size_t) s->alloc;
|
||||
return s->alloc;
|
||||
}
|
||||
|
||||
M_INLINE uint8_t *
|
||||
m_br1nsg_ctr(const m_bstring_t v)
|
||||
m_bstr1ng_cstr(const m_bstring_t v)
|
||||
{
|
||||
return &v->ptr[v->offset];
|
||||
}
|
||||
@@ -77,7 +78,7 @@ M_INLINE void
|
||||
m_bstring_clear(m_bstring_t s)
|
||||
{
|
||||
M_BSTRING_CONTRACT(s);
|
||||
M_MEMORY_FREE( s->ptr);
|
||||
M_MEMORY_FREE(s->ptr);
|
||||
s->offset = (size_t) -1;
|
||||
}
|
||||
|
||||
@@ -90,6 +91,18 @@ m_bstring_reset(m_bstring_t s)
|
||||
M_BSTRING_CONTRACT(s);
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_swap(m_bstring_t s1, m_bstring_t s2)
|
||||
{
|
||||
M_BSTRING_CONTRACT(s1);
|
||||
M_BSTRING_CONTRACT(s2);
|
||||
m_bstring_t tmp;
|
||||
memcpy(tmp, s1, sizeof (m_bstring_t));
|
||||
memcpy(s1, s2, sizeof (m_bstring_t));
|
||||
memcpy(s2, tmp, sizeof (m_bstring_t));
|
||||
M_BSTRING_CONTRACT(s1);
|
||||
M_BSTRING_CONTRACT(s2);
|
||||
}
|
||||
|
||||
/* Return the selected byte-character of the string */
|
||||
M_INLINE uint8_t
|
||||
@@ -97,7 +110,7 @@ m_bstring_get_byte(const m_bstring_t v, size_t index)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(index, v->size);
|
||||
return m_br1nsg_ctr(v)[index];
|
||||
return m_bstr1ng_cstr(v)[index];
|
||||
}
|
||||
|
||||
/* Set the selected byte-character of the string */
|
||||
@@ -106,7 +119,7 @@ m_bstring_set_byte(m_bstring_t v, size_t index, const uint8_t c)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(index, v->size);
|
||||
m_br1nsg_ctr(v)[index] = c;
|
||||
m_bstr1ng_cstr(v)[index] = c;
|
||||
}
|
||||
|
||||
/* Test if the string is empty or not */
|
||||
@@ -118,13 +131,20 @@ m_bstring_empty_p(const m_bstring_t v)
|
||||
}
|
||||
|
||||
/* Internal method to fit the Byte string to the given size
|
||||
Ensures that the string capacity is greater than size_alloc+offset
|
||||
The string 'v' no longer has a working size field.
|
||||
Ensures that the Byte String capacity is greater than size_alloc+offset
|
||||
The returned Byte String 'v' no longer has a **correct** size field.
|
||||
If exact_alloc is true, it will request exactly the request size for the buffer
|
||||
on reallocation otherwise it will augment the requested size to amortize the future
|
||||
allocations.
|
||||
Return a pointer to the writable string.
|
||||
*/
|
||||
M_INLINE uint8_t *
|
||||
m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc)
|
||||
{
|
||||
// Very unlikely overflow case
|
||||
if (M_UNLIKELY_NOMEM (v->offset > v->offset + size_alloc)) {
|
||||
goto allocation_error;
|
||||
}
|
||||
M_ASSERT_INDEX (v->offset, v->offset + size_alloc);
|
||||
// Note: this function may be called in context where the contract is not fulfilled.
|
||||
if (M_UNLIKELY (v->offset + size_alloc > v->alloc)) {
|
||||
@@ -132,28 +152,23 @@ m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc)
|
||||
|
||||
// Check if there is a too big offset that can be reduced
|
||||
if (v->offset > v->size / 8 && v->offset > 16) {
|
||||
// Move back the effective bytes to the beginning of the buffer
|
||||
memmove(&v->ptr[0], &v->ptr[v->offset], v->size);
|
||||
v->offset = 0;
|
||||
// If it is now sufficient, we can return.
|
||||
if (size_alloc <= v->alloc)
|
||||
return v->ptr;
|
||||
}
|
||||
|
||||
// Alloc a new array
|
||||
// Alloc a new array. Compute the requested allocation size
|
||||
size_t alloc = (v->offset + size_alloc + (exact_alloc ? 0 : size_alloc / 2));
|
||||
alloc = M_MAX(alloc, 16);
|
||||
if (M_UNLIKELY_NOMEM (alloc < size_alloc)) {
|
||||
/* Overflow in alloc computation */
|
||||
M_MEMORY_FULL(alloc);
|
||||
// NOTE: Return is currently broken.
|
||||
abort();
|
||||
return NULL;
|
||||
goto allocation_error;
|
||||
}
|
||||
uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, alloc);
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
|
||||
M_MEMORY_FULL(alloc);
|
||||
// NOTE: Return is currently broken.
|
||||
abort();
|
||||
return NULL;
|
||||
goto allocation_error;
|
||||
}
|
||||
// The string cannot be fully embedded anymore.
|
||||
v->ptr = ptr;
|
||||
@@ -164,9 +179,14 @@ m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc)
|
||||
return &v->ptr[v->offset];
|
||||
}
|
||||
return &v->ptr[v->offset];
|
||||
allocation_error:
|
||||
M_MEMORY_FULL(size_alloc);
|
||||
// NOTE: Return is currently broken.
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Push the byte-character 'c' in the string 'v' */
|
||||
/* Push the byte 'c' in the bstring 'v' */
|
||||
M_INLINE void
|
||||
m_bstring_push_back (m_bstring_t v, uint8_t c)
|
||||
{
|
||||
@@ -178,6 +198,7 @@ m_bstring_push_back (m_bstring_t v, uint8_t c)
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Push the array of bytes from 'buffer' in the bstring 'v' */
|
||||
M_INLINE void
|
||||
m_bstring_push_back_bytes (m_bstring_t v, size_t n, const void *buffer)
|
||||
{
|
||||
@@ -194,14 +215,14 @@ M_INLINE void
|
||||
m_bstring_init_set(m_bstring_t v, const m_bstring_t org)
|
||||
{
|
||||
m_bstring_init(v);
|
||||
m_bstring_push_back_bytes(v, m_bstring_size(org), m_br1nsg_ctr(org));
|
||||
m_bstring_push_back_bytes(v, m_bstring_size(org), m_bstr1ng_cstr(org));
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_set(m_bstring_t v, const m_bstring_t org)
|
||||
{
|
||||
m_bstring_reset(v);
|
||||
m_bstring_push_back_bytes(v, m_bstring_size(org), m_br1nsg_ctr(org));
|
||||
m_bstring_push_back_bytes(v, m_bstring_size(org), m_bstr1ng_cstr(org));
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
@@ -219,6 +240,13 @@ m_bstring_move(m_bstring_t v, m_bstring_t org)
|
||||
m_bstring_init_move(v, org);
|
||||
}
|
||||
|
||||
M_INLINE size_t
|
||||
m_bstring_hash(const m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
return m_core_hash(m_bstr1ng_cstr(v), m_bstring_size(v));
|
||||
}
|
||||
|
||||
M_INLINE int
|
||||
m_bstring_cmp(const m_bstring_t v1, m_bstring_t v2)
|
||||
{
|
||||
@@ -226,7 +254,7 @@ m_bstring_cmp(const m_bstring_t v1, m_bstring_t v2)
|
||||
M_BSTRING_CONTRACT (v2);
|
||||
const size_t s1 = m_bstring_size(v1);
|
||||
const size_t s2 = m_bstring_size(v2);
|
||||
int ret = memcmp(m_br1nsg_ctr(v1), m_br1nsg_ctr(v2), M_MIN(s1, s2));
|
||||
int ret = memcmp(m_bstr1ng_cstr(v1), m_bstr1ng_cstr(v2), M_MIN(s1, s2));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (s1 != s2)
|
||||
@@ -239,7 +267,7 @@ m_bstring_cmp_bytes(const m_bstring_t v1, size_t s2, const void *p2)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v1);
|
||||
const size_t s1 = m_bstring_size(v1);
|
||||
int ret = memcmp(m_br1nsg_ctr(v1), p2, M_MIN(s1, s2));
|
||||
int ret = memcmp(m_bstr1ng_cstr(v1), p2, M_MIN(s1, s2));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (s1 != s2)
|
||||
@@ -256,7 +284,7 @@ m_bstring_equal_p(const m_bstring_t v1, m_bstring_t v2)
|
||||
const size_t s2 = m_bstring_size(v2);
|
||||
if (s1 != s2)
|
||||
return false;
|
||||
return memcmp(m_br1nsg_ctr(v1), m_br1nsg_ctr(v2), s1) == 0;
|
||||
return memcmp(m_bstr1ng_cstr(v1), m_bstr1ng_cstr(v2), s1) == 0;
|
||||
}
|
||||
|
||||
M_INLINE bool
|
||||
@@ -266,7 +294,7 @@ m_bstring_equal_bytes_p(const m_bstring_t v1, size_t s2, const void *buffer)
|
||||
const size_t s1 = m_bstring_size(v1);
|
||||
if (s1 != s2)
|
||||
return false;
|
||||
return memcmp(m_br1nsg_ctr(v1), buffer, s1) == 0;
|
||||
return memcmp(m_bstr1ng_cstr(v1), buffer, s1) == 0;
|
||||
}
|
||||
|
||||
M_INLINE uint8_t
|
||||
@@ -274,7 +302,7 @@ m_bstring_pop_back(m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(0, v->size);
|
||||
uint8_t c = m_br1nsg_ctr(v)[v->size-1];
|
||||
uint8_t c = m_bstr1ng_cstr(v)[v->size-1];
|
||||
v->size --;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
return c;
|
||||
@@ -285,7 +313,7 @@ m_bstring_pop_back_bytes(size_t n, void *buffer, m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(n-1, v->size);
|
||||
memcpy(buffer, &m_br1nsg_ctr(v)[v->size-n], n);
|
||||
memcpy(buffer, &m_bstr1ng_cstr(v)[v->size-n], n);
|
||||
v->size -= n;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
@@ -295,7 +323,7 @@ m_bstring_pop_front(m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(0, v->size);
|
||||
uint8_t c = m_br1nsg_ctr(v)[0];
|
||||
uint8_t c = m_bstr1ng_cstr(v)[0];
|
||||
v->size --;
|
||||
v->offset++;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
@@ -307,7 +335,7 @@ m_bstring_pop_front_bytes(size_t n, void *buffer, m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(n-1, v->size);
|
||||
memcpy(buffer, &m_br1nsg_ctr(v)[0], n);
|
||||
memcpy(buffer, &m_bstr1ng_cstr(v)[0], n);
|
||||
v->size -= n;
|
||||
v->offset += n;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
@@ -334,7 +362,7 @@ m_bstring_pop_bytes_at(size_t n, void *buffer, m_bstring_t v, size_t pos)
|
||||
const size_t size = v->size;
|
||||
M_ASSERT_INDEX (pos, size);
|
||||
M_ASSERT_INDEX(n-1, size-pos);
|
||||
uint8_t *ptr = m_br1nsg_ctr(v);
|
||||
uint8_t *ptr = m_bstr1ng_cstr(v);
|
||||
memcpy(buffer, &ptr[pos], n);
|
||||
memmove(&ptr[pos], &ptr[pos+n], size-pos-n);
|
||||
v->size -= n;
|
||||
@@ -385,7 +413,7 @@ m_bstring_view(const m_bstring_t v, size_t offset, size_t size_requested)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX (offset+size_requested, v->size+1);
|
||||
return &m_br1nsg_ctr(v)[offset];
|
||||
return &m_bstr1ng_cstr(v)[offset];
|
||||
}
|
||||
|
||||
// Acquire / release direct write access: once acquired, user can directly wite at the returned pointer for the requested size
|
||||
@@ -398,7 +426,7 @@ m_bstring_acquire_access(m_bstring_t v, size_t offset, size_t size_requested)
|
||||
M_ASSERT_INDEX (offset+size_requested, v->size+1);
|
||||
// Break canonical representation (this will generate assertion if a normal API is called now)
|
||||
M_SWAP(size_t, v->size, v->alloc);
|
||||
return &m_br1nsg_ctr(v)[offset];
|
||||
return &m_bstr1ng_cstr(v)[offset];
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
@@ -410,13 +438,103 @@ m_bstring_release_access(m_bstring_t v)
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
// TODO: Iterator
|
||||
// No Iterator planned for this container (No added value)
|
||||
|
||||
// TODO: IO
|
||||
#if M_USE_STDIO
|
||||
|
||||
// TODO: OPLIST
|
||||
M_INLINE size_t
|
||||
m_bstring_fwrite(FILE *f, const m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT (f != NULL);
|
||||
return fwrite(m_bstr1ng_cstr(v), 1, m_bstring_size(v), f);
|
||||
}
|
||||
|
||||
// TODO: Hash
|
||||
M_INLINE bool
|
||||
m_bstring_fread(m_bstring_t v, FILE *f, size_t num)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT (f != NULL);
|
||||
m_bstring_reset(v);
|
||||
if (M_UNLIKELY(num == 0)) {
|
||||
return true;
|
||||
}
|
||||
uint8_t *ptr = m_bstr1ng_fit2size(v, num, true);
|
||||
size_t n = fread(ptr, 1, num, f);
|
||||
M_ASSERT (n <= num);
|
||||
v->size = n;
|
||||
return n == num;
|
||||
}
|
||||
|
||||
#endif // Have stdio
|
||||
|
||||
// No formatted string input/output. Only serializer
|
||||
|
||||
/* Transform the Byte String 'v2'
|
||||
and output it in the given serializer
|
||||
See serialization for return code.
|
||||
*/
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_bstring_out_serial(m_serial_write_t serial, const m_bstring_t v)
|
||||
{
|
||||
M_ASSERT (serial != NULL && serial->m_interface != NULL);
|
||||
M_BSTRING_CONTRACT (v);
|
||||
m_serial_local_t local;
|
||||
m_serial_return_code_t ret;
|
||||
size_t size = m_bstring_size(v);
|
||||
uint8_t *ptr = m_bstr1ng_cstr(v);
|
||||
ret = serial->m_interface->write_array_start(local, serial, size);
|
||||
if (size > 0) {
|
||||
ret |= serial->m_interface->write_integer(serial, ptr[0], 1);
|
||||
for(size_t i = 1; i < size; i++) {
|
||||
ret |= serial->m_interface->write_array_next(local, serial);
|
||||
ret |= serial->m_interface->write_integer(serial, ptr[i], 1);
|
||||
}
|
||||
}
|
||||
ret |= serial->m_interface->write_array_end(local, serial);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read from the serializer
|
||||
and set the converted value in the byte string 'v'.
|
||||
See serialization for return code.
|
||||
*/
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_bstring_in_serial(m_bstring_t v, m_serial_read_t f)
|
||||
{
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL);
|
||||
M_BSTRING_CONTRACT (v);
|
||||
m_serial_return_code_t ret;
|
||||
m_serial_local_t local;
|
||||
size_t estimated_size = 0, real_size = 0;
|
||||
m_bstring_reset(v);
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size);
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) {
|
||||
return ret;
|
||||
}
|
||||
uint8_t *ptr = m_bstr1ng_fit2size(v, estimated_size, true);
|
||||
do {
|
||||
long long val;
|
||||
ret = f->m_interface->read_integer(f, &val, 1);
|
||||
if (ret != M_SERIAL_OK_DONE) { break; }
|
||||
ptr[real_size++] = (uint8_t) val;
|
||||
ret = f->m_interface->read_array_next(local, f);
|
||||
} while (ret == M_SERIAL_OK_CONTINUE);
|
||||
v->size = real_size;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Define the OPLIST of a BYTE STRING */
|
||||
#define M_BSTRING_OPLIST \
|
||||
(INIT(m_bstring_init),INIT_SET(m_bstring_init_set), SET(m_bstring_set), \
|
||||
INIT_MOVE(m_bstring_init_move), MOVE(m_bstring_move), \
|
||||
SWAP(m_bstring_swap), RESET(m_bstring_reset), \
|
||||
EMPTY_P(m_bstring_empty_p), \
|
||||
CLEAR(m_bstring_clear), HASH(m_bstring_hash), EQUAL(m_bstring_equal_p), \
|
||||
CMP(m_bstring_cmp), TYPE(m_bstring_t), GENTYPE(struct m_bstring_s*), \
|
||||
OUT_SERIAL(m_bstring_out_serial), IN_SERIAL(m_bstring_in_serial), \
|
||||
)
|
||||
|
||||
/********************************************************************************/
|
||||
/* */
|
||||
@@ -456,6 +574,12 @@ m_bstring_release_access(m_bstring_t v)
|
||||
#define bstring_view m_bstring_view
|
||||
#define bstring_acquire_access m_bstring_acquire_access
|
||||
#define bstring_release_access m_bstring_release_access
|
||||
#define bstring_hash m_bstring_hash
|
||||
#define bstring_fread m_bstring_fread
|
||||
#define bstring_fwrite m_bstring_fwrite
|
||||
#define bstring_out_serial m_bstring_out_serial
|
||||
#define bstring_in_serial m_bstring_in_serial
|
||||
#define bstring_swap m_bstring_swap
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ static void test0(void)
|
||||
assert( bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 0);
|
||||
assert( bstring_capacity(b) == 0);
|
||||
assert( bstring_hash(b) != 0);
|
||||
bstring_clear(b);
|
||||
|
||||
bstring_init(b);
|
||||
@@ -41,10 +42,12 @@ static void test0(void)
|
||||
assert( !bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 1);
|
||||
assert( bstring_capacity(b) != 0);
|
||||
assert( bstring_hash(b) != 0);
|
||||
bstring_reset(b);
|
||||
assert( bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 0);
|
||||
assert( bstring_capacity(b) != 0);
|
||||
assert( bstring_hash(b) != 0);
|
||||
bstring_clear(b);
|
||||
}
|
||||
|
||||
@@ -183,6 +186,10 @@ static void test2(void)
|
||||
assert (!bstring_equal_p(b1, b2));
|
||||
assert (bstring_cmp(b1, b2) < 0);
|
||||
|
||||
bstring_swap(b1, b2);
|
||||
assert (bstring_cmp(b1, b2) > 0);
|
||||
bstring_swap(b1, b2);
|
||||
|
||||
bstring_set(b1, b2);
|
||||
assert (bstring_equal_p(b1, b2));
|
||||
assert (bstring_cmp(b1, b2) == 0);
|
||||
@@ -261,6 +268,47 @@ static void test4(void)
|
||||
bstring_clear(b);
|
||||
}
|
||||
|
||||
static void test_io(void)
|
||||
{
|
||||
uint8_t tab1[] = { 1, 2, 3};
|
||||
bstring_t b;
|
||||
|
||||
bstring_init(b);
|
||||
|
||||
FILE *f = fopen("a-mbstring.dat", "wb");
|
||||
if (!f) abort();
|
||||
size_t n = bstring_fwrite(f, b);
|
||||
assert(n == 0);
|
||||
fclose (f);
|
||||
|
||||
bstring_push_back_bytes(b, sizeof tab1, tab1);
|
||||
|
||||
f = fopen("a-mbstring.dat", "rb");
|
||||
if (!f) abort();
|
||||
bool success = bstring_fread(b, f, 0);
|
||||
assert(success);
|
||||
assert(bstring_size(b) == 0);
|
||||
fclose (f);
|
||||
|
||||
bstring_push_back_bytes(b, sizeof tab1, tab1);
|
||||
|
||||
f = fopen("a-mbstring.dat", "wb");
|
||||
if (!f) abort();
|
||||
n = bstring_fwrite(f, b);
|
||||
assert(n == sizeof tab1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen("a-mbstring.dat", "rb");
|
||||
if (!f) abort();
|
||||
success = bstring_fread(b, f, sizeof tab1);
|
||||
assert(success);
|
||||
assert(bstring_size(b) == sizeof tab1);
|
||||
assert(m_bstring_equal_bytes_p(b, sizeof tab1, tab1));
|
||||
fclose (f);
|
||||
|
||||
bstring_clear(b);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test0();
|
||||
@@ -268,5 +316,6 @@ int main(void)
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test_io();
|
||||
exit(0);
|
||||
}
|
||||
Reference in new issue
Block a user