File: posix.ha

package info (click to toggle)
hare 0.25.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,948 kB
  • sloc: asm: 1,264; makefile: 123; sh: 114; lisp: 101
file content (72 lines) | stat: -rw-r--r-- 2,567 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

use bytes;
use strings;

// These functions have been confined here to POSIX jail. They are
// POSIX-compliant, for their sins, but they do not fit in semantically
// with the other stack-paradigm functions. Hence this POSIX-complaint.
// They are based primarily off of `man 1p basename/dirname`, and secondarily
// off of the examples in `man 3p basename`.

// A POSIX-compliant implementation of dirname. See the POSIX specification
// for more information. Note that this function does *not* normalize the
// input. The return value is either borrowed from the input or statically
// allocated; use [[strings::dup]] to extend its lifetime.
export fn dirname(path: const str) const str = {
	let path = strings::toutf8(path);
	if (len(path) == 0) return ".";

	path = bytes::rtrim(path, SEP);
	if (len(path) == 0) return sepstr;

	match (bytes::rindex(path, SEP)) {
	case void => return ".";
	case let z: size => path = path[..z];
	};
	path = bytes::rtrim(path, SEP);

	if (len(path) == 0) return sepstr;
	return strings::fromutf8_unsafe(path);
};

// A POSIX-compliant implementation of basename. See the POSIX specification
// for more information. Note that this function does *not* normalize the
// input. The return value is either borrowed from the input or statically
// allocated; use [[strings::dup]] to extend its lifetime.
export fn basename(path: const str) const str = {
	let path = strings::toutf8(path);
	if (len(path) == 0) return ".";

	path = bytes::rtrim(path, SEP);
	if (len(path) == 0) return sepstr;

	match (bytes::rindex(path, SEP)) {
	case void => void;
	case let z: size => path = path[z+1..];
	};
	return strings::fromutf8_unsafe(path);
};

@test fn dirname_basename() void = {
	const table = [
		// input           , dirname     , basename
		["usr"             , "."         , "usr" ],
		["usr/"            , "."         , "usr" ],
		[""                , "."         , "."   ],
		["/"               , "/"         , "/"   ],
		["//"              , "/"         , "/"   ], // implementation defined
		["///"             , "/"         , "/"   ],
		["/usr/"           , "/"         , "usr" ],
		["/usr/lib"        , "/usr"      , "lib" ],
		["//usr//lib//"    , "//usr"     , "lib" ],
		["/home//dwc//test", "/home//dwc", "test"],
	];
	for (let i = 0z; i < len(table); i += 1) {
		let input: [MAX]u8 = [0...];
		const input = _local(table[i][0], &input)!;
		assert(dirname(input) == local(table[i][1])!);
		assert(basename(input) == local(table[i][2])!);
	};
};