import "./core.zc" import "./string.zc" import "./option.zc" import "./vec.zc" struct Path { str: String; } impl Path { fn new(s: char*) -> Path { return Path { str: String::new(s) }; } fn from_string(s: String) -> Path { return Path { str: s }; } fn c_str(self) -> char* { return self.str.c_str(); } fn clone(self) -> Path { return Path { str: String::new(self.str.c_str()) }; } fn join(self, other: char*) -> Path { var base_len = self.str.length(); var new_s = String::from(self.str.c_str()); if (base_len > 0) { var last = self.str.vec.get(base_len - 1); if (last != '/' && last != '\\') { var sep = String::new("/"); new_s.append(sep); } } var other_str = String::new(other); new_s.append(other_str); return Path { str: new_s }; } fn extension(self) -> Option { var s = self.c_str(); var len = self.str.length(); for (var i: usize = len; i > 0; i = i - 1) { var c = s[i-1]; if (c == '.') { // Check if we hit a separator before element // e.g. /d.ir/file - found dot // /d.ir/file.txt - found last dot return Option::Some(self.str.substring(i, len - i)); } if (c == '/' || c == '\\') { return Option::None(); } } return Option::None(); } fn file_name(self) -> Option { var s = self.c_str(); var len = self.str.length(); if (len == 0) return Option::None(); // Remove trailing separators var end = len; while (end > 0 && (s[end-1] == '/' || s[end-1] == '\\')) { end = end - 1; } if (end == 0) return Option::None(); // Root var start = end; while (start > 0 && s[start-1] != '/' && s[start-1] != '\\') { start = start - 1; } return Option::Some(self.str.substring(start, end - start)); } fn parent(self) -> Option { var s = self.c_str(); var len = self.str.length(); if (len == 0) return Option::None(); // Trim trailing separators var end = len; while (end > 0 && (s[end-1] == '/' || s[end-1] == '\\')) { end = end - 1; } // Scan back to separator while (end > 0 && s[end-1] != '/' && s[end-1] != '\\') { end = end - 1; } if (end == 0) return Option::None(); while (end > 0 && (s[end-1] == '/' || s[end-1] == '\\')) { end = end - 1; } if (end == 0) { // Must be root return Option::Some(Path::new("/")); } var parent_str = self.str.substring(0, end); return Option::Some(Path { str: parent_str }); } }