join.ha (1858B)
1 // License: MPL-2.0 2 // (c) 2021-2022 Drew DeVault <sir@cmpwn.com> 3 use bytes; 4 use errors; 5 use strings; 6 7 // Joins several path elements together and copies them into a path buffer. 8 // Returns the new string value of the path. 9 export fn add(buf: *buffer, items: str...) (str | errors::overflow) = { 10 for (let i = 0z; i < len(items); i += 1) { 11 const elem = strings::toutf8(items[i]); 12 const tok = bytes::tokenize(elem, pathsep); 13 for (let j = 0z; true; j += 1) { 14 const next = match (bytes::next_token(&tok)) { 15 case let tok: []u8 => 16 yield tok; 17 case void => 18 break; 19 }; 20 if (len(next) == 0 && j == 0) { 21 // Handles the add("/foo") case as 22 // add("/", "foo"); 23 appendnorm(buf, pathsepstr)?; 24 }; 25 appendnorm(buf, next)?; 26 }; 27 }; 28 return string(buf); 29 }; 30 31 @test fn add() void = { 32 let buf = init(); 33 add(&buf, "foo", "bar", "baz")!; 34 let s = strings::join(pathsepstr, "foo", "bar", "baz"); 35 assert(string(&buf) == s); 36 free(s); 37 38 reset(&buf); 39 s = strings::join(pathsepstr, "", "foo", "bar"); 40 add(&buf, s, "baz")!; 41 free(s); 42 s = strings::join(pathsepstr, "", "foo", "bar", "baz"); 43 assert(string(&buf) == s); 44 free(s); 45 46 reset(&buf); 47 s = strings::join(pathsepstr, "foo", "bar"); 48 add(&buf, pathsepstr, s, "baz")!; 49 free(s); 50 s = strings::join(pathsepstr, "", "foo", "bar", "baz"); 51 assert(string(&buf) == s); 52 free(s); 53 54 reset(&buf); 55 s = strings::join(pathsepstr, ".", "foo", "bar"); 56 add(&buf, s)!; 57 free(s); 58 s = strings::join(pathsepstr, "foo", "bar"); 59 assert(string(&buf) == s); 60 free(s); 61 }; 62 63 // Joins a list of path components together, normalizes it, and returns the 64 // resulting string. The caller must free the return value. If the resulting 65 // path would exceed [[PATH_MAX]], the program aborts. 66 export fn join(items: str...) str = { 67 static let buf = buffer { ... }; 68 return strings::dup(set(&buf, items...)!); 69 };