소스 검색

Replace cstring with MemRef.
MemRef is just a stupid (ptr, len) pair. We no longer need the abstract cstring.

Ambroz Bizjak 11 년 전
부모
커밋
c1f4c57e8a

+ 5 - 13
examples/ncdval_test.c

@@ -48,19 +48,11 @@ static void test_string (NCDValRef str, const char *data, size_t length)
     FORCE( NCDVal_IsStringNoNulls(str) == !memchr(data, '\0', length) )
     FORCE( NCDVal_StringRegionEquals(str, 0, length, data) )
     
-    b_cstring cstr = NCDVal_StringCstring(str);
-    
-    for (size_t i = 0; i < length; i++) {
-        size_t chunk_length;
-        const char *chunk_data = b_cstring_get(cstr, i, length - i, &chunk_length);
-        
-        FORCE( chunk_length > 0 )
-        FORCE( chunk_length <= length - i )
-        FORCE( !memcmp(chunk_data, data + i, chunk_length) )
-        FORCE( NCDVal_StringRegionEquals(str, i, chunk_length, data + i) )
-        FORCE( b_cstring_memcmp(cstr, b_cstring_make_buf(data, length), i, i, chunk_length) == 0 )
-        FORCE( b_cstring_memcmp(cstr, b_cstring_make_buf(data + i, length - i), i, 0, chunk_length) == 0 )
-    }
+    MemRef mr = NCDVal_StringMemRef(str);
+    FORCE( mr.ptr == NCDVal_StringData(str) )
+    FORCE( mr.len == NCDVal_StringLength(str) )
+    FORCE( mr.len == length )
+    FORCE( !memcmp(mr.ptr, data, length) )
 }
 
 static void print_indent (int indent)

+ 0 - 20
misc/cmdline.h

@@ -40,7 +40,6 @@
 #include <misc/debug.h>
 #include <misc/exparray.h>
 #include <misc/strdup.h>
-#include <misc/cstring.h>
 
 typedef struct {
     struct ExpArray arr;
@@ -51,7 +50,6 @@ static int CmdLine_Init (CmdLine *c);
 static void CmdLine_Free (CmdLine *c);
 static int CmdLine_Append (CmdLine *c, const char *str);
 static int CmdLine_AppendNoNull (CmdLine *c, const char *str, size_t str_len);
-static int CmdLine_AppendCstring (CmdLine *c, b_cstring cstr, size_t offset, size_t length);
 static int CmdLine_AppendMulti (CmdLine *c, int num, ...);
 static int CmdLine_Finish (CmdLine *c);
 static char ** CmdLine_Get (CmdLine *c);
@@ -118,24 +116,6 @@ int CmdLine_AppendNoNull (CmdLine *c, const char *str, size_t str_len)
     return 1;
 }
 
-int CmdLine_AppendCstring (CmdLine *c, b_cstring cstr, size_t offset, size_t length)
-{
-    b_cstring_assert_range(cstr, offset, length);
-    ASSERT(!b_cstring_memchr(cstr, offset, length, '\0', NULL))
-    
-    if (!ExpArray_resize(&c->arr, c->n + 1)) {
-        return 0;
-    }
-    
-    if (!(((char **)c->arr.v)[c->n] = b_cstring_strdup(cstr, offset, length))) {
-        return 0;
-    }
-    
-    c->n++;
-    
-    return 1;
-}
-
 int CmdLine_AppendMulti (CmdLine *c, int num, ...)
 {
     int res = 1;

+ 0 - 347
misc/cstring.h

@@ -1,347 +0,0 @@
-/**
- * @file cstring.h
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_COMPOSED_STRING_H
-#define BADVPN_COMPOSED_STRING_H
-
-#include <stddef.h>
-#include <string.h>
-#include <limits.h>
-
-#include <misc/debug.h>
-#include <misc/balloc.h>
-
-struct b_cstring_s;
-
-/**
- * Callback function which is called by {@link b_cstring_get} to access the underlying resource.
- * \a cstr points to the cstring being accessed, and the callback can use the userN members to
- * retrieve any state information.
- * \a offset is the offset from the beginning of the string; offset < cstr->length.
- * This callback must set *\a out_length and return a pointer, representing a continuous
- * region of the string that starts at the byte at index \a offset. Returning a region that
- * spans past the end of the string is allowed.
- */
-typedef const char * (*b_cstring_func) (const struct b_cstring_s *cstr, size_t offset, size_t *out_length);
-
-/**
- * An abstract string which is not necessarily continuous. Given a cstring, its length
- * can be determined by reading the 'length' member, and its data can be read using
- * {@link b_cstring_get} (which internally invokes the {@link b_cstring_func} callback).
- */
-typedef struct b_cstring_s {
-    size_t length;
-    b_cstring_func func;
-    union {
-        size_t size;
-        void *ptr;
-        void (*fptr) (void);
-    } user1;
-    union {
-        size_t size;
-        void *ptr;
-        void (*fptr) (void);
-    } user2;
-    union {
-        size_t size;
-        void *ptr;
-        void (*fptr) (void);
-    } user3;
-} b_cstring;
-
-/**
- * Makes a cstring pointing to a buffer.
- * \a data may be NULL if \a length is 0.
- */
-static b_cstring b_cstring_make_buf (const char *data, size_t length);
-
-/**
- * Makes a cstring which represents an empty string.
- */
-static b_cstring b_cstring_make_empty (void);
-
-/**
- * Retrieves a pointer to a continuous region of the string.
- * \a offset specifies the starting offset of the region to retrieve, and must be < cstr.length.
- * \a maxlen specifies the maximum length of the returned region, and must be > 0.
- * The length of the region will be stored in *\a out_chunk_len, and it will always be > 0.
- * It is possible that the returned region spans past the end of the string, unless limited
- * by \a maxlen. The pointer to the region will be returned; it will point to the byte
- * at offset exactly \a offset into the string.
- */
-static const char * b_cstring_get (b_cstring cstr, size_t offset, size_t maxlen, size_t *out_chunk_len);
-
-/**
- * Retrieves the byte in the string at position \a pos.
- */
-static char b_cstring_at (b_cstring cstr, size_t pos);
-
-/**
- * Asserts that the range given by \a offset and \a length is valid for the string.
- */
-static void b_cstring_assert_range (b_cstring cstr, size_t offset, size_t length);
-
-/**
- * Copies a range to an external buffer.
- */
-static void b_cstring_copy_to_buf (b_cstring cstr, size_t offset, size_t length, char *dest);
-
-/**
- * Performs a memcmp-like operation on the given ranges of two cstrings.
- */
-static int b_cstring_memcmp (b_cstring cstr1, b_cstring cstr2, size_t offset1, size_t offset2, size_t length);
-
-/**
- * Determines if a range within a string is equal to the bytes in an external buffer.
- */
-static int b_cstring_equals_buffer (b_cstring cstr, size_t offset, size_t length, const char *data);
-
-/**
- * Determines if a range within a string contains the byte \a ch.
- * Returns 1 if it does, and 0 if it does not. If it does contain it, and \a out_pos is not
- * NULL, *\a out_pos is set to the index of the first matching byte in the range, relative
- * to the beginning of the range \a offset.
- */
-static int b_cstring_memchr (b_cstring cstr, size_t offset, size_t length, char ch, size_t *out_pos);
-
-/**
- * Allocates a buffer for a range and copies it. The buffer is allocated using {@link BAlloc}.
- * An extra null byte will be appended. On failure, returns NULL.
- */
-static char * b_cstring_strdup (b_cstring cstr, size_t offset, size_t length);
-
-/**
- * Macro which iterates the continuous regions of a range within a cstring.
- * For reach region, the statements in \a body are executed, in order.
- * \a cstr is the string to be iterated.
- * \a offset and \a length specify the range of the string to iterate; they must
- * refer to a valid range for the string.
- * \a rel_pos_var, \a chunk_data_var and \a chunk_length_var specify names of variables
- * which will be available in \a body.
- * \a rel_pos_var will hold the offset (size_t) of the current continuous region, relative
- * to \a offset.
- * \a chunk_data_var will hold a pointer (const char *) to the beginning of the region, and
- * \a chunk_length_var will hold its length (size_t).
- * 
- * Note: \a cstr, \a offset and \a length may be evaluated multiple times, or not at all.
- * Note: do not use 'continue' or 'break' from inside the body, their behavior depends
- *       on the internal implementation of this macro.
- * 
- * See the implementation of {@link b_cstring_copy_to_buf} for a usage example.
- */
-#define B_CSTRING_LOOP_RANGE(cstr, offset, length, rel_pos_var, chunk_data_var, chunk_length_var, body) \
-{ \
-    size_t rel_pos_var = 0; \
-    while (rel_pos_var < (length)) { \
-        size_t chunk_length_var; \
-        const char *chunk_data_var = b_cstring_get((cstr), (offset) + rel_pos_var, (length) - rel_pos_var, &chunk_length_var); \
-        { body } \
-        rel_pos_var += chunk_length_var; \
-    } \
-}
-
-/**
- * Like {@link B_CSTRING_LOOP_RANGE}, but iterates the entire string,
- * i.e. offset==0 and length==cstr.length.
- */
-#define B_CSTRING_LOOP(cstr, rel_pos_var, chunk_data_var, chunk_length_var, body) B_CSTRING_LOOP_RANGE(cstr, 0, (cstr).length, rel_pos_var, chunk_data_var, chunk_length_var, body)
-
-/**
- * Macro which iterates the characters of a range within a cstring.
- * For each character, the statements in \a body are executed, in order.
- * \a cstr is the string to be iterated.
- * \a offset and \a length specify the range of the string to iterate; they must
- * refer to a valid range for the string.
- * \a char_rel_pos_var and \a char_var specify names of variables which will be
- * available in \a body.
- * \a char_rel_pos_var will hold the position (size_t) of the current character
- * relative to \a offset.
- * \a char_var will hold the current character (char).
- * 
- * Note: \a cstr, \a offset and \a length may be evaluated multiple times, or not at all.
- * Note: do not use 'continue' or 'break' from inside the body, their behavior depends
- *       on the internal implementation of this macro.
- */
-#define B_CSTRING_LOOP_CHARS_RANGE(cstr, offset, length, char_rel_pos_var, char_var, body) \
-B_CSTRING_LOOP_RANGE(cstr, offset, length, b_cstring_loop_chars_pos, b_cstring_loop_chars_chunk_data, b_cstring_loop_chars_chunk_length, { \
-    for (size_t b_cstring_loop_chars_chunk_pos = 0; b_cstring_loop_chars_chunk_pos < b_cstring_loop_chars_chunk_length; b_cstring_loop_chars_chunk_pos++) { \
-        size_t char_rel_pos_var = b_cstring_loop_chars_pos + b_cstring_loop_chars_chunk_pos; \
-        B_USE(char_rel_pos_var) \
-        char char_var = b_cstring_loop_chars_chunk_data[b_cstring_loop_chars_chunk_pos]; \
-        { body } \
-    } \
-})
-
-/**
- * Like {@link B_CSTRING_LOOP_CHARS_RANGE}, but iterates the entire string,
- * i.e. offset==0 and length==cstr.length.
- */
-#define B_CSTRING_LOOP_CHARS(cstr, char_rel_pos_var, char_var, body) B_CSTRING_LOOP_CHARS_RANGE(cstr, 0, (cstr).length, char_rel_pos_var, char_var, body)
-
-static const char * b_cstring__buf_func (const b_cstring *cstr, size_t offset, size_t *out_length)
-{
-    ASSERT(offset < cstr->length)
-    ASSERT(out_length)
-    ASSERT(cstr->func == b_cstring__buf_func)
-    ASSERT(cstr->user1.ptr)
-    
-    *out_length = cstr->length - offset;
-    return (const char *)cstr->user1.ptr + offset;
-}
-
-static b_cstring b_cstring_make_buf (const char *data, size_t length)
-{
-    ASSERT(length == 0 || data)
-    
-    b_cstring cstr;
-    cstr.length = length;
-    cstr.func = b_cstring__buf_func;
-    cstr.user1.ptr = (void *)data;
-    return cstr;
-}
-
-static b_cstring b_cstring_make_empty (void)
-{
-    b_cstring cstr;
-    cstr.length = 0;
-    cstr.func = NULL;
-    return cstr;
-}
-
-static const char * b_cstring_get (b_cstring cstr, size_t offset, size_t maxlen, size_t *out_chunk_len)
-{
-    ASSERT(offset < cstr.length)
-    ASSERT(maxlen > 0)
-    ASSERT(out_chunk_len)
-    ASSERT(cstr.func)
-    
-    const char *data = cstr.func(&cstr, offset, out_chunk_len);
-    ASSERT(data)
-    ASSERT(*out_chunk_len > 0)
-    
-    if (*out_chunk_len > maxlen) {
-        *out_chunk_len = maxlen;
-    }
-    
-    return data;
-}
-
-static char b_cstring_at (b_cstring cstr, size_t pos)
-{
-    ASSERT(pos < cstr.length)
-    ASSERT(cstr.func)
-    
-    size_t chunk_len;
-    const char *data = cstr.func(&cstr, pos, &chunk_len);
-    ASSERT(data)
-    ASSERT(chunk_len > 0)
-    
-    return *data;
-}
-
-static void b_cstring_assert_range (b_cstring cstr, size_t offset, size_t length)
-{
-    ASSERT(offset <= cstr.length)
-    ASSERT(length <= cstr.length - offset)
-}
-
-static void b_cstring_copy_to_buf (b_cstring cstr, size_t offset, size_t length, char *dest)
-{
-    b_cstring_assert_range(cstr, offset, length);
-    ASSERT(length == 0 || dest)
-    
-    B_CSTRING_LOOP_RANGE(cstr, offset, length, pos, chunk_data, chunk_length, {
-        memcpy(dest + pos, chunk_data, chunk_length);
-    })
-}
-
-static int b_cstring_memcmp (b_cstring cstr1, b_cstring cstr2, size_t offset1, size_t offset2, size_t length)
-{
-    b_cstring_assert_range(cstr1, offset1, length);
-    b_cstring_assert_range(cstr2, offset2, length);
-    
-    B_CSTRING_LOOP_RANGE(cstr1, offset1, length, pos1, chunk_data1, chunk_len1, {
-        B_CSTRING_LOOP_RANGE(cstr2, offset2 + pos1, chunk_len1, pos2, chunk_data2, chunk_len2, {
-            int cmp = memcmp(chunk_data1 + pos2, chunk_data2, chunk_len2);
-            if (cmp) {
-                return cmp;
-            }
-        })
-    })
-    
-    return 0;
-}
-
-static int b_cstring_equals_buffer (b_cstring cstr, size_t offset, size_t length, const char *data)
-{
-    b_cstring_assert_range(cstr, offset, length);
-    
-    B_CSTRING_LOOP_RANGE(cstr, offset, length, pos, chunk_data, chunk_len, {
-        if (memcmp(chunk_data, data + pos, chunk_len)) {
-            return 0;
-        }
-    })
-    
-    return 1;
-}
-
-static int b_cstring_memchr (b_cstring cstr, size_t offset, size_t length, char ch, size_t *out_pos)
-{
-    b_cstring_assert_range(cstr, offset, length);
-    
-    B_CSTRING_LOOP_CHARS_RANGE(cstr, offset, length, cur_ch_pos, cur_ch, {
-        if (cur_ch == ch) {
-            if (out_pos) {
-                *out_pos = cur_ch_pos;
-            }
-            return 1;
-        }
-    })
-    
-    return 0;
-}
-
-static char * b_cstring_strdup (b_cstring cstr, size_t offset, size_t length)
-{
-    b_cstring_assert_range(cstr, offset, length);
-    
-    if (length == SIZE_MAX) {
-        return NULL;
-    }
-    
-    char *buf = (char *)BAlloc(length + 1);
-    if (buf) {
-        b_cstring_copy_to_buf(cstr, offset, length, buf);
-        buf[length] = '\0';
-    }
-    
-    return buf;
-}
-
-#endif

+ 142 - 0
misc/memref.h

@@ -0,0 +1,142 @@
+/**
+ * @file memref.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BADVPN_MEMREF_H
+#define BADVPN_MEMREF_H
+
+#include <stddef.h>
+#include <string.h>
+#include <limits.h>
+
+#include <misc/debug.h>
+#include <misc/balloc.h>
+#include <misc/strdup.h>
+
+typedef struct {
+    char const *ptr;
+    size_t len;
+} MemRef;
+
+static MemRef MemRef_Make (char const *ptr, size_t len);
+static char MemRef_At (MemRef o, size_t pos);
+static void MemRef_AssertRange (MemRef o, size_t offset, size_t length);
+static MemRef MemRef_SubFrom (MemRef o, size_t offset);
+static MemRef MemRef_SubTo (MemRef o, size_t length);
+static MemRef MemRef_Sub (MemRef o, size_t offset, size_t length);
+static char * MemRef_StrDup (MemRef o);
+static void MemRef_CopyOut (MemRef o, char *out);
+
+#define MEMREF_LOOP_CHARS__BODY(char_rel_pos_var, char_var, body) \
+{ \
+    for (size_t char_rel_pos_var = 0; char_rel_pos_var < MemRef__Loop_length; char_rel_pos_var++) { \
+        char char_var = MemRef__Loop_o.ptr[MemRef__Loop_offset + char_rel_pos_var]; \
+        { body } \
+    } \
+}
+
+#define MEMREF_LOOP_CHARS_RANGE(o, offset, length, char_rel_pos_var, char_var, body) \
+{ \
+    MemRef MemRef__Loop_o = (o); \
+    size_t MemRef__Loop_offset = (offset); \
+    size_t MemRef__Loop_length = (length); \
+    MEMREF_LOOP_CHARS__BODY(char_rel_pos_var, char_var, body) \
+}
+
+#define MEMREF_LOOP_CHARS(o, char_rel_pos_var, char_var, body) \
+{ \
+    MemRef MemRef__Loop_o = (o); \
+    size_t MemRef__Loop_offset = 0; \
+    size_t MemRef__Loop_length = MemRef__Loop_o.len; \
+    MEMREF_LOOP_CHARS__BODY(char_rel_pos_var, char_var, body) \
+}
+
+//
+
+static MemRef MemRef_Make (char const *ptr, size_t len)
+{
+    MemRef res;
+    res.ptr = ptr;
+    res.len = len;
+    return res;
+}
+
+static char MemRef_At (MemRef o, size_t pos)
+{
+    ASSERT(o.ptr)
+    ASSERT(pos < o.len)
+    
+    return o.ptr[pos];
+}
+
+static void MemRef_AssertRange (MemRef o, size_t offset, size_t length)
+{
+    ASSERT(offset <= o.len)
+    ASSERT(length <= o.len - offset)
+}
+
+static MemRef MemRef_SubFrom (MemRef o, size_t offset)
+{
+    ASSERT(o.ptr)
+    ASSERT(offset <= o.len)
+    
+    return MemRef_Make(o.ptr + offset, o.len - offset);
+}
+
+static MemRef MemRef_SubTo (MemRef o, size_t length)
+{
+    ASSERT(o.ptr)
+    ASSERT(length <= o.len)
+    
+    return MemRef_Make(o.ptr, length);
+}
+
+static MemRef MemRef_Sub (MemRef o, size_t offset, size_t length)
+{
+    ASSERT(o.ptr)
+    MemRef_AssertRange(o, offset, length);
+    
+    return MemRef_Make(o.ptr + offset, length);
+}
+
+static char * MemRef_StrDup (MemRef o)
+{
+    ASSERT(o.ptr)
+    
+    return b_strdup_bin(o.ptr, o.len);
+}
+
+static void MemRef_CopyOut (MemRef o, char *out)
+{
+    ASSERT(o.ptr)
+    ASSERT(out)
+    
+    memcpy(out, o.ptr, o.len);
+}
+
+#endif

+ 0 - 53
misc/parse_number.h

@@ -40,19 +40,16 @@
 #include <limits.h>
 
 #include <misc/debug.h>
-#include <misc/cstring.h>
 
 // public parsing functions
 static int decode_decimal_digit (char c);
 static int decode_hex_digit (char c);
 static int parse_unsigned_integer_bin (const char *str, size_t str_len, uintmax_t *out) WARN_UNUSED;
 static int parse_unsigned_integer (const char *str, uintmax_t *out) WARN_UNUSED;
-static int parse_unsigned_integer_cstr (b_cstring cstr, size_t offset, size_t length, uintmax_t *out) WARN_UNUSED;
 static int parse_unsigned_hex_integer_bin (const char *str, size_t str_len, uintmax_t *out) WARN_UNUSED;
 static int parse_unsigned_hex_integer (const char *str, uintmax_t *out) WARN_UNUSED;
 static int parse_signmag_integer_bin (const char *str, size_t str_len, int *out_sign, uintmax_t *out_mag) WARN_UNUSED;
 static int parse_signmag_integer (const char *str, int *out_sign, uintmax_t *out_mag) WARN_UNUSED;
-static int parse_signmag_integer_cstr (b_cstring cstr, size_t offset, size_t length, int *out_sign, uintmax_t *out_mag) WARN_UNUSED;
 
 // public generation functions
 static int compute_decimal_repr_size (uintmax_t x);
@@ -156,37 +153,6 @@ int parse_unsigned_integer (const char *str, uintmax_t *out)
     return parse_unsigned_integer_bin(str, strlen(str), out);
 }
 
-int parse_unsigned_integer_cstr (b_cstring cstr, size_t offset, size_t length, uintmax_t *out)
-{
-    b_cstring_assert_range(cstr, offset, length);
-    
-    if (length == 0) {
-        return 0;
-    }
-    
-    uintmax_t n = 0;
-    
-    B_CSTRING_LOOP_RANGE(cstr, offset, length, pos, chunk_data, chunk_length, {
-        for (size_t i = 0; i < chunk_length; i++) {
-            int digit = decode_decimal_digit(chunk_data[i]);
-            if (digit < 0) {
-                return 0;
-            }
-            if (n > UINTMAX_MAX / 10) {
-                return 0;
-            }
-            n *= 10;
-            if (digit > UINTMAX_MAX - n) {
-                return 0;
-            }
-            n += digit;
-        }
-    })
-    
-    *out = n;
-    return 1;
-}
-
 int parse_unsigned_hex_integer_bin (const char *str, size_t str_len, uintmax_t *out)
 {
     uintmax_t n = 0;
@@ -246,25 +212,6 @@ int parse_signmag_integer (const char *str, int *out_sign, uintmax_t *out_mag)
     return parse_signmag_integer_bin(str, strlen(str), out_sign, out_mag);
 }
 
-int parse_signmag_integer_cstr (b_cstring cstr, size_t offset, size_t length, int *out_sign, uintmax_t *out_mag)
-{
-    b_cstring_assert_range(cstr, offset, length);
-    
-    int sign = 1;
-    if (length > 0 && (b_cstring_at(cstr, offset) == '+' || b_cstring_at(cstr, offset) == '-')) {
-        sign = 1 - 2 * (b_cstring_at(cstr, offset) == '-');
-        offset++;
-        length--;
-    }
-    
-    if (!parse_unsigned_integer_cstr(cstr, offset, length, out_mag)) {
-        return 0;
-    }
-    
-    *out_sign = sign;
-    return 1;
-}
-
 int compute_decimal_repr_size (uintmax_t x)
 {
     int size = 0;

+ 0 - 34
misc/write_file.h

@@ -35,7 +35,6 @@
 #include <stdio.h>
 
 #include <misc/debug.h>
-#include <misc/cstring.h>
 
 static int write_file (const char *file, const uint8_t *data, size_t len)
 {
@@ -68,37 +67,4 @@ fail0:
     return 0;
 }
 
-static int write_file_cstring (const char *file, b_cstring cstr, size_t offset, size_t length)
-{
-    b_cstring_assert_range(cstr, offset, length);
-    
-    FILE *f = fopen(file, "w");
-    if (!f) {
-        goto fail0;
-    }
-    
-    B_CSTRING_LOOP_RANGE(cstr, offset, length, pos, chunk_data, chunk_length, {
-        size_t chunk_pos = 0;
-        while (chunk_pos < chunk_length) {
-            size_t res = fwrite(chunk_data + chunk_pos, 1, chunk_length - chunk_pos, f);
-            if (res == 0) {
-                goto fail1;
-            }
-            ASSERT(res <= chunk_length - chunk_pos)
-            chunk_pos += res;
-        }
-    })
-    
-    if (fclose(f) != 0) {
-        return 0;
-    }
-    
-    return 1;
-    
-fail1:
-    fclose(f);
-fail0:
-    return 0;
-}
-
 #endif

+ 5 - 5
ncd/NCDVal.c

@@ -953,7 +953,7 @@ size_t NCDVal_StringLength (NCDValRef string)
     }
 }
 
-b_cstring NCDVal_StringCstring (NCDValRef string)
+MemRef NCDVal_StringMemRef (NCDValRef string)
 {
     ASSERT(NCDVal_IsString(string))
     
@@ -962,22 +962,22 @@ b_cstring NCDVal_StringCstring (NCDValRef string)
     switch (get_internal_type(*(int *)ptr)) {
         case STOREDSTRING_TYPE: {
             struct NCDVal__string *str_e = ptr;
-            return b_cstring_make_buf(str_e->data, str_e->length);
+            return MemRef_Make(str_e->data, str_e->length);
         } break;
         
         case IDSTRING_TYPE: {
             struct NCDVal__idstring *ids_e = ptr;
-            return b_cstring_make_buf(NCDStringIndex_Value(ids_e->string_index, ids_e->string_id), NCDStringIndex_Length(ids_e->string_index, ids_e->string_id));
+            return MemRef_Make(NCDStringIndex_Value(ids_e->string_index, ids_e->string_id), NCDStringIndex_Length(ids_e->string_index, ids_e->string_id));
         } break;
         
         case EXTERNALSTRING_TYPE: {
             struct NCDVal__externalstring *exs_e = ptr;
-            return b_cstring_make_buf(exs_e->data, exs_e->length);
+            return MemRef_Make(exs_e->data, exs_e->length);
         } break;
         
         default: {
             ASSERT(0);
-            return b_cstring_make_empty();
+            return MemRef_Make(NULL, 0);
         } break;
     }
 }

+ 5 - 5
ncd/NCDVal.h

@@ -34,8 +34,8 @@
 #include <stdint.h>
 
 #include <misc/debug.h>
-#include <misc/cstring.h>
 #include <misc/BRefTarget.h>
+#include <misc/memref.h>
 #include <ncd/NCDStringIndex.h>
 #include <ncd/NCDVal_types.h>
 
@@ -278,12 +278,12 @@ const char * NCDVal_StringData (NCDValRef string);
 size_t NCDVal_StringLength (NCDValRef string);
 
 /**
- * Returns a {@link b_cstring} interface to the given string value.
- * The returned cstring is valid as long as the memory object exists.
- * However, if the memory object is moved or copied, the cstring is
+ * Returns a MemRef interface to the given string value.
+ * The returned MemRef is valid as long as the memory object exists.
+ * However, if the memory object is moved or copied, the MemRef is
  * invalid in the new or moved (respectively) memory object.
  */
-b_cstring NCDVal_StringCstring (NCDValRef string);
+MemRef NCDVal_StringMemRef (NCDValRef string);
 
 /**
  * Produces a null-terminated version of a String. On success, the result is

+ 1 - 3
ncd/NCDValGenerator.c

@@ -45,14 +45,12 @@ static int generate_val (NCDValRef value, ExpString *out_str)
     
     switch (NCDVal_Type(value)) {
         case NCDVAL_STRING: {
-            b_cstring cstr = NCDVal_StringCstring(value);
-            
             if (!ExpString_AppendChar(out_str, '"')) {
                 BLog(BLOG_ERROR, "ExpString_AppendChar failed");
                 goto fail;
             }
             
-            B_CSTRING_LOOP_CHARS(cstr, char_pos, ch, {
+            MEMREF_LOOP_CHARS(NCDVal_StringMemRef(value), char_pos, ch, {
                 if (ch == '\0') {
                     char buf[5];
                     snprintf(buf, sizeof(buf), "\\x%02"PRIx8, (uint8_t)ch);

+ 2 - 3
ncd/extra/NCDBProcessOpts.c

@@ -82,10 +82,9 @@ int NCDBProcessOpts_Init2 (NCDBProcessOpts *o, NCDValRef opts_arg, NCDBProcessOp
                     NCDModuleInst_Backend_Log(i, blog_channel, BLOG_ERROR, "username must be a string without nulls");
                     goto fail1;
                 }
-                b_cstring cstr = NCDVal_StringCstring(val);
-                o->username = b_cstring_strdup(cstr, 0, cstr.length);
+                o->username = MemRef_StrDup(NCDVal_StringMemRef(val));
                 if (!o->username) {
-                    NCDModuleInst_Backend_Log(i, blog_channel, BLOG_ERROR, "b_cstring_strdup failed");
+                    NCDModuleInst_Backend_Log(i, blog_channel, BLOG_ERROR, "MemRef_StrDup failed");
                     goto fail1;
                 }
             }

+ 3 - 3
ncd/extra/build_cmdline.c

@@ -85,9 +85,9 @@ int ncd_build_cmdline (NCDModuleInst *i, int log_channel, NCDValRef cmd_arg, cha
             goto fail2;
         }
         
-        b_cstring cstr = NCDVal_StringCstring(arg);
-        if (!CmdLine_AppendCstring(&cl, cstr, 0, cstr.length)) {
-            NCDModuleInst_Backend_Log(i, log_channel, BLOG_ERROR, "CmdLine_AppendCstring failed");
+        MemRef mr = NCDVal_StringMemRef(arg);
+        if (!CmdLine_AppendNoNull(&cl, mr.ptr, mr.len)) {
+            NCDModuleInst_Backend_Log(i, log_channel, BLOG_ERROR, "CmdLine_AppendNoNull failed");
             goto fail2;
         }
     }

+ 6 - 9
ncd/modules/basic_functions.c

@@ -180,13 +180,11 @@ DEFINE_VALUE_COMPARE(different, (cmp != 0))
 static int concat_recurser (ExpString *estr, NCDValRef arg, NCDCall const *call)
 {
     if (NCDVal_IsString(arg)) {
-        b_cstring arg_cstr = NCDVal_StringCstring(arg);
-        B_CSTRING_LOOP(arg_cstr, pos, chunk_data, chunk_length, {
-            if (!ExpString_AppendBinary(estr, (uint8_t const *)chunk_data, chunk_length)) {
-                FunctionLog(call, BLOG_ERROR, "ExpString_AppendBinary failed");
-                return 0;
-            }
-        })
+        MemRef mr = NCDVal_StringMemRef(arg);
+        if (!ExpString_AppendBinary(estr, (uint8_t const *)mr.ptr, mr.len)) {
+            FunctionLog(call, BLOG_ERROR, "ExpString_AppendBinary failed");
+            return 0;
+        }
     } else if (NCDVal_IsList(arg)) {
         size_t count = NCDVal_ListCount(arg);
         for (size_t i = 0; i < count; i++) {
@@ -405,8 +403,7 @@ static void perchar_eval (NCDCall call, perchar_func func)
         return;
     }
     char *out_data = (char *)NCDVal_StringData(value);
-    b_cstring arg_cstr = NCDVal_StringCstring(arg);
-    B_CSTRING_LOOP_CHARS(arg_cstr, i, ch, {
+    MEMREF_LOOP_CHARS(NCDVal_StringMemRef(arg), i, ch, {
         out_data[i] = func(ch);
     })
     NCDCall_SetResult(&call, value);

+ 3 - 3
ncd/modules/concat.c

@@ -102,9 +102,9 @@ static void new_concat_common (void *vo, NCDModuleInst *i, NCDValRef list)
     o->result->length = 0;
     for (size_t j = 0; j < count; j++) {
         NCDValRef arg = NCDVal_ListGet(list, j);
-        b_cstring cstr = NCDVal_StringCstring(arg);
-        b_cstring_copy_to_buf(cstr, 0, cstr.length, o->result->data + o->result->length);
-        o->result->length += cstr.length;
+        MemRef mr = NCDVal_StringMemRef(arg);
+        MemRef_CopyOut(mr, o->result->data + o->result->length);
+        o->result->length += mr.len;
     }
     
     // signal up

+ 3 - 3
ncd/modules/daemon.c

@@ -129,9 +129,9 @@ static int build_cmdline (NCDModuleInst *i, NCDValRef cmd_arg, char **exec, CmdL
             goto fail2;
         }
         
-        b_cstring cstr = NCDVal_StringCstring(arg);
-        if (!CmdLine_AppendCstring(cl, cstr, 0, cstr.length)) {
-            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendCstring failed");
+        MemRef mr = NCDVal_StringMemRef(arg);
+        if (!CmdLine_AppendNoNull(cl, mr.ptr, mr.len)) {
+            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendNoNull failed");
             goto fail2;
         }
     }

+ 2 - 2
ncd/modules/file.c

@@ -186,8 +186,8 @@ static void write_func_new (void *unused, NCDModuleInst *i, const struct NCDModu
     }
     
     // write file
-    b_cstring contents_cstr = NCDVal_StringCstring(contents_arg);
-    int res = write_file_cstring(filename_nts.data, contents_cstr, 0, contents_cstr.length);
+    MemRef contents_mr = NCDVal_StringMemRef(contents_arg);
+    int res = write_file(filename_nts.data, (uint8_t const *)contents_mr.ptr, contents_mr.len);
     NCDValNullTermString_Free(&filename_nts);
     if (!res) {
         ModuleLog(i, BLOG_ERROR, "failed to write file");

+ 20 - 22
ncd/modules/file_open.c

@@ -125,19 +125,19 @@ struct read_instance {
     size_t length;
 };
 
-static int parse_mode (b_cstring cstr, char *out)
+static int parse_mode (MemRef mr, char *out)
 {
     size_t pos = 0;
-    size_t left = cstr.length;
+    size_t left = mr.len;
     
     if (left == 0) {
         return 0;
     }
-    switch (b_cstring_at(cstr, pos)) {
+    switch (MemRef_At(mr, pos)) {
         case 'r':
         case 'w':
         case 'a':
-            *out++ = b_cstring_at(cstr, pos);
+            *out++ = MemRef_At(mr, pos);
             pos++;
             left--;
             break;
@@ -148,9 +148,9 @@ static int parse_mode (b_cstring cstr, char *out)
     if (left == 0) {
         goto finish;
     }
-    switch (b_cstring_at(cstr, pos)) {
+    switch (MemRef_At(mr, pos)) {
         case '+':
-            *out++ = b_cstring_at(cstr, pos);
+            *out++ = MemRef_At(mr, pos);
             pos++;
             left--;
             break;
@@ -210,7 +210,7 @@ static void open_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleIns
     
     // check mode
     char mode[5];
-    if (!parse_mode(NCDVal_StringCstring(mode_arg), mode)) {
+    if (!parse_mode(NCDVal_StringMemRef(mode_arg), mode)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong mode");
         goto fail0;
     }
@@ -404,20 +404,18 @@ static void write_func_new (void *unused, NCDModuleInst *i, const struct NCDModu
     }
     
     // write all the data
-    b_cstring data_cstr = NCDVal_StringCstring(data_arg);
-    B_CSTRING_LOOP(data_cstr, pos, chunk_data, chunk_length, {
-        size_t chunk_pos = 0;
-        while (chunk_pos < chunk_length) {
-            size_t written = fwrite(chunk_data + chunk_pos, 1, chunk_length - chunk_pos, open_inst->fh);
-            if (written == 0) {
-                ModuleLog(i, BLOG_ERROR, "fwrite failed");
-                trigger_error(open_inst);
-                return;
-            }
-            ASSERT(written <= chunk_length - chunk_pos)
-            chunk_pos += written;
+    MemRef data_mr = NCDVal_StringMemRef(data_arg);
+    size_t pos = 0;
+    while (pos < data_mr.len) {
+        size_t written = fwrite(data_mr.ptr + pos, 1, data_mr.len - pos, open_inst->fh);
+        if (written == 0) {
+            ModuleLog(i, BLOG_ERROR, "fwrite failed");
+            trigger_error(open_inst);
+            return;
         }
-    })
+        ASSERT(written <= data_mr.len - pos)
+        pos += written;
+    }
     
     // go up
     NCDModuleInst_Backend_Up(i);
@@ -444,8 +442,8 @@ static void seek_func_new (void *unused, NCDModuleInst *i, const struct NCDModul
     // parse position
     int position_sign;
     uintmax_t position_mag;
-    b_cstring position_cstr = NCDVal_StringCstring(position_arg);
-    if (!parse_signmag_integer_cstr(position_cstr, 0, position_cstr.length, &position_sign, &position_mag)) {
+    MemRef position_mr = NCDVal_StringMemRef(position_arg);
+    if (!parse_signmag_integer_bin(position_mr.ptr, position_mr.len, &position_sign, &position_mag)) {
         ModuleLog(i, BLOG_ERROR, "wrong position");
         goto fail0;
     }

+ 8 - 10
ncd/modules/print.c

@@ -87,18 +87,16 @@ static void do_print (NCDModuleInst *i, NCDValRef args, int ln)
         NCDValRef arg = NCDVal_ListGet(args, j);
         ASSERT(NCDVal_IsString(arg))
         
-        b_cstring arg_cstr = NCDVal_StringCstring(arg);
+        MemRef arg_mr = NCDVal_StringMemRef(arg);
         
-        B_CSTRING_LOOP_RANGE(arg_cstr, 0, arg_cstr.length, pos, chunk_data, chunk_length, {
-            size_t chunk_pos = 0;
-            while (chunk_pos < chunk_length) {
-                ssize_t res = fwrite(chunk_data + chunk_pos, 1, chunk_length - chunk_pos, stdout);
-                if (res <= 0) {
-                    goto out;
-                }
-                chunk_pos += res;
+        size_t pos = 0;
+        while (pos < arg_mr.len) {
+            ssize_t res = fwrite(arg_mr.ptr + pos, 1, arg_mr.len - pos, stdout);
+            if (res <= 0) {
+                goto out;
             }
-        })
+            pos += res;
+        }
     }
     
 out:

+ 3 - 3
ncd/modules/run.c

@@ -114,9 +114,9 @@ static int build_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **e
             goto fail2;
         }
         
-        b_cstring arg_cstr = NCDVal_StringCstring(arg);
-        if (!CmdLine_AppendCstring(cl, arg_cstr, 0, arg_cstr.length)) {
-            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendCstring failed");
+        MemRef arg_mr = NCDVal_StringMemRef(arg);
+        if (!CmdLine_AppendNoNull(cl, arg_mr.ptr, arg_mr.len)) {
+            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendNoNull failed");
             goto fail2;
         }
     }

+ 3 - 3
ncd/modules/runonce.c

@@ -124,9 +124,9 @@ static int build_cmdline (NCDModuleInst *i, NCDValRef cmd_arg, char **exec, CmdL
             goto fail2;
         }
         
-        b_cstring arg_cstr = NCDVal_StringCstring(arg);
-        if (!CmdLine_AppendCstring(cl, arg_cstr, 0, arg_cstr.length)) {
-            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendCstring failed");
+        MemRef arg_mr = NCDVal_StringMemRef(arg);
+        if (!CmdLine_AppendNoNull(cl, arg_mr.ptr, arg_mr.len)) {
+            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendNoNull failed");
             goto fail2;
         }
     }

+ 10 - 17
ncd/modules/socket.c

@@ -195,8 +195,7 @@ struct read_instance {
 struct write_instance {
     NCDModuleInst *i;
     struct connection *con_inst;
-    b_cstring cstr;
-    size_t pos;
+    MemRef data;
 };
 
 struct listen_instance {
@@ -449,21 +448,18 @@ static void connection_send_handler_done (void *user, int data_len)
     ASSERT(o->state == CONNECTION_STATE_ESTABLISHED)
     ASSERT(o->write_inst)
     ASSERT(o->write_inst->con_inst == o)
-    ASSERT(o->write_inst->pos < o->write_inst->cstr.length)
     ASSERT(data_len > 0)
-    ASSERT(data_len <= o->write_inst->cstr.length - o->write_inst->pos)
+    ASSERT(data_len <= o->write_inst->data.len)
     
     struct write_instance *wr = o->write_inst;
     
     // update send state
-    wr->pos += data_len;
+    wr->data = MemRef_SubFrom(wr->data, data_len);
     
     // if there's more to send, send again
-    if (wr->pos < wr->cstr.length) {
-        size_t chunk_len;
-        const char *chunk_data = b_cstring_get(wr->cstr, wr->pos, wr->cstr.length - wr->pos, &chunk_len);
-        size_t to_send = (chunk_len > INT_MAX ? INT_MAX : chunk_len);
-        StreamPassInterface_Sender_Send(BConnection_SendAsync_GetIf(&o->connection), (uint8_t *)chunk_data, to_send);
+    if (wr->data.len > 0) {
+        size_t to_send = (wr->data.len > INT_MAX) ? INT_MAX : wr->data.len;
+        StreamPassInterface_Sender_Send(BConnection_SendAsync_GetIf(&o->connection), (uint8_t *)wr->data.ptr, to_send);
         return;
     }
     
@@ -848,11 +844,10 @@ static void write_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleIn
     }
     
     // set send state
-    o->cstr = NCDVal_StringCstring(data_arg);
-    o->pos = 0;
+    o->data = NCDVal_StringMemRef(data_arg);
     
     // if there's nothing to send, go up immediately
-    if (o->cstr.length == 0) {
+    if (o->data.len == 0) {
         o->con_inst = NULL;
         NCDModuleInst_Backend_Up(i);
         return;
@@ -865,10 +860,8 @@ static void write_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleIn
     con_inst->write_inst = o;
     
     // send
-    size_t chunk_len;
-    const char *chunk_data = b_cstring_get(o->cstr, o->pos, o->cstr.length - o->pos, &chunk_len);
-    size_t to_send = (chunk_len > INT_MAX ? INT_MAX : chunk_len);
-    StreamPassInterface_Sender_Send(BConnection_SendAsync_GetIf(&con_inst->connection), (uint8_t *)chunk_data, to_send);
+    size_t to_send = (o->data.len > INT_MAX) ? INT_MAX : o->data.len;
+    StreamPassInterface_Sender_Send(BConnection_SendAsync_GetIf(&con_inst->connection), (uint8_t *)o->data.ptr, to_send);
     return;
     
 fail0:

+ 11 - 19
ncd/modules/sys_start_process.c

@@ -214,8 +214,7 @@ struct write_pipe_instance {
 struct write_instance {
     NCDModuleInst *i;
     struct write_pipe_instance *write_pipe_inst;
-    b_cstring cstr;
-    size_t pos;
+    MemRef data;
 };
 
 static int parse_mode (NCDModuleInst *i, NCDValRef mode_arg, int *out_read, int *out_write)
@@ -228,9 +227,7 @@ static int parse_mode (NCDModuleInst *i, NCDValRef mode_arg, int *out_read, int
     *out_read = 0;
     *out_write = 0;
     
-    b_cstring cstr = NCDVal_StringCstring(mode_arg);
-    
-    B_CSTRING_LOOP_CHARS(cstr, char_pos, ch, {
+    MEMREF_LOOP_CHARS(NCDVal_StringMemRef(mode_arg), char_pos, ch, {
         if (ch == 'r') {
             *out_read = 1;
         }
@@ -986,19 +983,17 @@ static void write_pipe_send_handler_done (void *vo, int data_len)
     ASSERT(o->write_inst)
     ASSERT(o->write_inst->write_pipe_inst == o)
     ASSERT(data_len > 0)
-    ASSERT(data_len <= o->write_inst->cstr.length - o->write_inst->pos)
+    ASSERT(data_len <= o->write_inst->data.len)
     
     struct write_instance *wr = o->write_inst;
     
     // update write progress
-    wr->pos += data_len;
+    wr->data = MemRef_SubFrom(wr->data, data_len);
     
     // if there is more data, start another write operation
-    if (wr->pos < wr->cstr.length) {
-        size_t chunk_length;
-        const char *chunk_data = b_cstring_get(wr->cstr, wr->pos, wr->cstr.length - wr->pos, &chunk_length);
-        size_t to_send = (chunk_length > INT_MAX ? INT_MAX : chunk_length);
-        StreamPassInterface_Sender_Send(BConnection_SendAsync_GetIf(&o->connection), (uint8_t *)chunk_data, to_send);
+    if (wr->data.len > 0) {
+        size_t to_send = (wr->data.len > INT_MAX) ? INT_MAX : wr->data.len;
+        StreamPassInterface_Sender_Send(BConnection_SendAsync_GetIf(&o->connection), (uint8_t *)wr->data.ptr, to_send);
         return;
     }
     
@@ -1123,11 +1118,10 @@ static void write_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleIn
     }
     
     // initialize write progress state
-    o->cstr = NCDVal_StringCstring(data_arg);
-    o->pos = 0;
+    o->data = NCDVal_StringMemRef(data_arg);
     
     // if there's nothing to send, go up immediately
-    if (o->cstr.length == 0) {
+    if (o->data.len == 0) {
         o->write_pipe_inst = NULL;
         NCDModuleInst_Backend_Up(i);
         return;
@@ -1140,10 +1134,8 @@ static void write_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleIn
     write_pipe_inst->write_inst = o;
     
     // start send operation
-    size_t chunk_length;
-    const char *chunk_data = b_cstring_get(o->cstr, o->pos, o->cstr.length - o->pos, &chunk_length);
-    size_t to_send = (chunk_length > INT_MAX ? INT_MAX : chunk_length);
-    StreamPassInterface_Sender_Send(BConnection_SendAsync_GetIf(&write_pipe_inst->connection), (uint8_t *)chunk_data, to_send);
+    size_t to_send = (o->data.len > INT_MAX) ? INT_MAX : o->data.len;
+    StreamPassInterface_Sender_Send(BConnection_SendAsync_GetIf(&write_pipe_inst->connection), (uint8_t *)o->data.ptr, to_send);
     return;
     
 fail0: