cstr

tape
import cstr from "cstr";

let home: []const u8 = cstr.as_view(getenv_from_c("HOME"));   // view a C string
let p: *u8 = cstr.from_view("hello");                          // make one for C
c_puts(p);
cstr.free(p);

C libraries and the operating system pass text as a pointer to bytes ending in a NUL (*u8, or *const u8 where C only reads it). The rest of the standard library takes []const u8 views. cstr converts between the two at the edge of your program. A tape string has no terminating NUL and never converts to a pointer: from_view is how one reaches C (a string literal can also go straight to a *const u8 parameter).

Reading C strings

FunctionReturns
len(p: *const u8) -> i64Bytes before the NUL; 0 for null
as_view(p: *const u8) -> []const u8The bytes before the NUL, as a view (empty for null)

as_view doesn’t copy: the view points at the C string’s memory, so it must not outlive it. Copy it with str.from_view when you need to keep it.

tape
let v: []const u8 = cstr.as_view(name_from_c);
io.println("got {v}");
let kept: string = str.from_view(v);

Making C strings

FunctionReturns
from_view(s: []const u8) -> *u8A new NUL-terminated copy of s
from_i64(v: i64) -> *u8v in decimal as a new C string
free(p: *u8)Releases a C string made by from_view or from_i64

The C string belongs to you until you free it; free(null) does nothing. Only free C strings that cstr made: memory a C library returns is released however that library says.

from_view stops the program with a trap when the text contains a NUL byte, since C would only see the part before it.

tape
let label: *u8 = cstr.from_i64(count);   // e.g. for a widget that takes *u8
defer cstr.free(label);

Deprecated: the old str functions

Before 2.1, str worked on *u8 pointers with u32 lengths. Those functions now live in cstr, unchanged, and are deprecated: they will be removed in a later minor release. Each has a replacement that takes views:

DeprecatedUse instead
cstr.is_digit, is_alpha, is_spaceascii.is_digit, is_alpha, is_space
cstr.char_at(s, len, i)cstr.as_view(s)[i]
cstr.equal(a, a_len, b, b_len)bytes.eq
cstr.starts_with, ends_with, containsbytes.starts_with, ends_with, contains
cstr.index_of (returns -1 when absent)bytes.index_of (returns null)
cstr.copy(dst, src, n)bytes.copy
cstr.concat(a, a_len, b, b_len)interpolation "{a}{b}" or str.join
cstr.to_upper(s, len), to_lower (in place)str.to_upper, str.to_lower
cstr.trim_left, trim_right (return offsets)bytes.trim_left, bytes.trim_right
cstr.parse_i64(s, len)conv.parse_i64
cstr.i64_to_str(v, buf, len)conv.fmt_i64
cstr.i64_to_cstr(v)cstr.from_i64

The old str.len is cstr.len, which now returns i64.

Last modified: