Notcurses-Native.git | lib/Notcurses/Native/ | Str.rakumod edit
use NativeCall;
unit module Notcurses::Native::Str;
#|( Helpers for safely transferring C-allocated char* across the
NativeCall boundary into Raku-owned C<Str>s.
Notcurses returns C<char*> from many calls with three distinct
ownership semantics, and using C<--> Str> on the binding only
works for one of them:
=item B<malloc'd, caller frees> (e.g. C<notcurses_at_yx>,
C<notcurses_detected_terminal>, C<nccell_strdup>) — the C
function strdups; the caller must C<free(3)> the returned
pointer. C<--> Str> would copy and leak the original.
Use C<strdup-copy-and-free>.
=item B<pointer into a caller-provided buffer> (e.g. the
C<ncnmetric> / C<ncqprefix> family) — the returned pointer
is inside the C<CArray[uint8] $buf> the caller passed in.
Freeing it would corrupt the buf. Use C<borrowed-str-from-pointer>.
=item B<pointer into library-owned memory> (e.g. C<ncplane_name>,
C<ncselector_selected>, C<nccell_extended_gcluster>) — the
pointer is into notcurses's internal storage; the caller MUST
NOT free. C<--> Str> works (Raku copies and never frees the
original), so these bindings stay unchanged. )
# libc resolver, shared with Notcurses::Native (used by both the free
# helper here and the setenv wrapper there). Resolved at BEGIN time —
# the file shipped on disk doesn't change between BEGIN and runtime, so
# this is safe to cache. Defers the actual library lookup to NativeCall.
sub libc-name(--> Str) is export {
state $resolved = do {
if $*DISTRO.is-win {
'msvcrt'
}
elsif $*KERNEL.name.lc.contains('darwin') {
'libc.dylib'
}
elsif '/lib/ld-musl-x86_64.so.1'.IO.e {
# musl Alpine / distroless — libc is the dynamic linker
# itself, exposed under architecture-specific filenames.
'libc.musl-x86_64.so.1'
}
elsif '/lib/ld-musl-aarch64.so.1'.IO.e {
'libc.musl-aarch64.so.1'
}
else {
'libc.so.6'
}
};
$resolved
}
sub c-free(Pointer $p) is export
is native(&libc-name) is symbol('free') { * }
#|( Decode a malloc'd C string into a Raku-owned C<Str> and free the
original pointer. Returns the type object C<Str> on a null pointer.
Use as the wrapper around any notcurses binding whose contract is
"caller frees the returned char*". The binding should be declared
with C<--> Pointer> instead of C<--> Str> so NativeCall doesn't
auto-decode-and-leak. )
sub strdup-copy-and-free(Pointer $p --> Str) is export {
return Str unless $p.defined && +$p;
my $s = nativecast(Str, $p);
c-free($p);
$s
}
#|( Decode a borrowed C-string pointer into a Raku-owned C<Str> WITHOUT
freeing the source. Use when the pointer is into a caller-provided
buffer or library-owned storage. Returns C<Str> (type object) on
null. )
sub borrowed-str-from-pointer(Pointer $p --> Str) is export {
return Str unless $p.defined && +$p;
nativecast(Str, $p)
}