hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

posix.ha (2564B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use bytes;
      5 use strings;
      6 
      7 // These functions have been confined here to POSIX jail. They are
      8 // POSIX-compliant, for their sins, but they do not fit in semantically
      9 // with the other stack-paradigm functions. Hence this POSIX-complaint.
     10 // They are based primarily off of `man 1p basename/dirname`, and secondarily
     11 // off of the examples in `man 3p basename`.
     12 
     13 // A POSIX-compliant implementation of dirname. See the POSIX specification
     14 // for more information. Note that this function does *not* normalize the
     15 // input. The return value is either borrowed from the input or statically
     16 // allocated; use [[strings::dup]] to extend its lifetime.
     17 export fn dirname(path: const str) const str = {
     18 	let path = strings::toutf8(path);
     19 	if (len(path) == 0) return ".";
     20 
     21 	path = bytes::rtrim(path, SEP);
     22 	if (len(path) == 0) return sepstr;
     23 
     24 	match (bytes::rindex(path, SEP)) {
     25 	case void => return ".";
     26 	case let z: size => path = path[..z];
     27 	};
     28 	path = bytes::rtrim(path, SEP);
     29 
     30 	if (len(path) == 0) return sepstr;
     31 	return strings::fromutf8_unsafe(path);
     32 };
     33 
     34 // A POSIX-compliant implementation of basename. See the POSIX specification
     35 // for more information. Note that this function does *not* normalize the
     36 // input. The return value is either borrowed from the input or statically
     37 // allocated; use [[strings::dup]] to extend its lifetime.
     38 export fn basename(path: const str) const str = {
     39 	let path = strings::toutf8(path);
     40 	if (len(path) == 0) return ".";
     41 
     42 	path = bytes::rtrim(path, SEP);
     43 	if (len(path) == 0) return sepstr;
     44 
     45 	match (bytes::rindex(path, SEP)) {
     46 	case void => void;
     47 	case let z: size => path = path[z+1..];
     48 	};
     49 	return strings::fromutf8_unsafe(path);
     50 };
     51 
     52 @test fn dirname_basename() void = {
     53 	const table = [
     54 		// input           , dirname     , basename
     55 		["usr"             , "."         , "usr" ],
     56 		["usr/"            , "."         , "usr" ],
     57 		[""                , "."         , "."   ],
     58 		["/"               , "/"         , "/"   ],
     59 		["//"              , "/"         , "/"   ], // implementation defined
     60 		["///"             , "/"         , "/"   ],
     61 		["/usr/"           , "/"         , "usr" ],
     62 		["/usr/lib"        , "/usr"      , "lib" ],
     63 		["//usr//lib//"    , "//usr"     , "lib" ],
     64 		["/home//dwc//test", "/home//dwc", "test"],
     65 	];
     66 	for (let i = 0z; i < len(table); i += 1) {
     67 		let input: [MAX]u8 = [0...];
     68 		const input = _local(table[i][0], &input);
     69 		assert(dirname(input) == local(table[i][1]));
     70 		assert(basename(input) == local(table[i][2]));
     71 	};
     72 };