lib/path: #138 c3-posix dirname/basename — faithful posix.ha port, table-driven @test (cstage)
dirname/basename ported verbatim from ref/hare/path/posix.ha:17,37, re-routing Hare's byte scanning to bytes.rtrim/rindex. Additive to the c2-stack buffer core; no harness/Makefile/module-const changes. Work-var renamed path->p to avoid Hare's param-shadowing `let path = toutf8(path)`: ww's cgen N_LET prepends the new local into the name-keyed localfind chain BEFORE the init is emitted, so the shadow-init reads the fresh uninit slot — a silent miscompile, both-wrong-identical, filed #152 and fixed independently next. drew ruled path->p a permanent acceptable spelling (internal work-var, not API surface; avoids a param-shadow footgun; not a rule-7 workaround). WHY-comment + #152 pointer at both sites. Tests: 10-row dirname/basename table (posix.ha:51-71 verbatim) — root, no-sep, empty, trailing-sep, multi-sep all covered, expecteds traced. C-first: cstage @test green; the str-view-vs-literal rows are #146-deferred (wwstage byte-id, rides #125). Gate: all 324 passed, byte-id 990-997 green, w6c/w6c_ww unchanged (lib-only additive).
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
// path — filesystem path manipulation. UTF-8 paths, '/' separator.
|
||||
// Mirrors Hare's path:: surface (ref/hare/path/). This is the
|
||||
// path::buffer stack-buffer port (c2-stack subset: error/posix defs +
|
||||
// buffer + isroot + appendlit + appendnorm + push + string + set).
|
||||
// init/abs/dirname/basename and the rest land in later folds.
|
||||
// buffer + isroot + appendlit + appendnorm + push + string + set) plus
|
||||
// the c3-posix subset (dirname + basename, ref/hare/path/posix.ha).
|
||||
// init/abs and the rest land in later folds.
|
||||
|
||||
package path;
|
||||
|
||||
@@ -137,3 +138,51 @@ export fn set(buf: *buffer, items: str...) (str | error) = {
|
||||
buf.end = 0;
|
||||
return push(buf, items...);
|
||||
};
|
||||
|
||||
// ---- POSIX jail (ref/hare/path/posix.ha) ------------------------------
|
||||
// POSIX-compliant dirname/basename. They do NOT normalize the input and
|
||||
// operate on plain str (no buffer), so they sit apart from the stack
|
||||
// paradigm above — same POSIX-complaint as posix.ha:7-11.
|
||||
|
||||
// ref/hare/path/posix.ha:17. Does *not* normalize; the return is either a
|
||||
// literal ("."/sepstr) or a borrowed view of the input. Div: toutf8 stays
|
||||
// strings.toutf8; len(path)→path.len; fromutf8_unsafe→strings.frombytes
|
||||
// (rule-9 carve-out); rindex z:size→i32; reslice `[..z]`→`[0:z]` (div #4).
|
||||
// Div: Hare shadows the param (`let path = strings::toutf8(path)`); ww's
|
||||
// new `let` binding is in scope for its OWN initializer, so the shadow
|
||||
// reads the uninitialized local — work var renamed `p` (cstage self-init
|
||||
// scope bug, #152).
|
||||
export fn dirname(path: str) str = {
|
||||
let p: []u8 = strings.toutf8(path);
|
||||
if (p.len == 0) { return "."; };
|
||||
|
||||
p = bytes.rtrim(p, SEP);
|
||||
if (p.len == 0) { return sepstr; };
|
||||
|
||||
match (bytes.rindex(p, SEP)) {
|
||||
case void => { return "."; };
|
||||
case let z: i32 => { p = p[0:z]; };
|
||||
};
|
||||
p = bytes.rtrim(p, SEP);
|
||||
|
||||
if (p.len == 0) { return sepstr; };
|
||||
return strings.frombytes(p);
|
||||
};
|
||||
|
||||
// ref/hare/path/posix.ha:37. Does *not* normalize; the return is a
|
||||
// borrowed view of the input. Div: as dirname (incl. param-shadow rename
|
||||
// to `p`, #152); reslice `[z+1..]`→`[z+1:]` (div #4); empty-match no-op
|
||||
// arm spelled `case void => void;` (bytes.ww:130 precedent).
|
||||
export fn basename(path: str) str = {
|
||||
let p: []u8 = strings.toutf8(path);
|
||||
if (p.len == 0) { return "."; };
|
||||
|
||||
p = bytes.rtrim(p, SEP);
|
||||
if (p.len == 0) { return sepstr; };
|
||||
|
||||
match (bytes.rindex(p, SEP)) {
|
||||
case void => void;
|
||||
case let z: i32 => { p = p[z+1:]; };
|
||||
};
|
||||
return strings.frombytes(p);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user