Ctrl K
ComunidadGuías…

std/path.zc

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot

import "./core.zc"
import "./string.zc"
import "./option.zc"
import "./vec.zc"

struct Path {
    str: String;
}

impl Path {
    /// Creates a Path from a string.
    fn new(s: char*) -> Path {
        return Path { str: String::new(s) };
    }
    
    fn from_string(s: String) -> Path {
        return Path { str: s };
    }
    
    /// Returns the underlying C string.
    fn c_str(self) -> char* {
        return self.str.c_str();
    }
    
    fn clone(self) -> Path {
        return Path { str: String::new(self.str.c_str()) };
    }
    
    /// Joins a component onto the path.
    fn join(self, other: char*) -> Path {
        let base_len = self.str.length();
        let new_s = String::from(self.str.c_str());
        
        if (base_len > 0) {
            let last = self.str.vec.get(base_len - 1);
            if (last != '/' && last != '\\') {
                let sep = String::new("/");
                new_s.append(&sep);
            }
        }
        
        let other_str = String::new(other);
        new_s.append(&other_str);
        
        return Path { str: new_s }; 
    }

    /// Returns the file extension, or `None`.
    fn extension(self) -> Option<String> {
        let s = self.c_str();
        let len = self.str.length();
        
        for (let i: usize = len; i > 0; i = i - 1) {
            let 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<String>::Some(self.str.substring(i, len - i));
            }
            if (c == '/' || c == '\\') {
                return Option<String>::None();
            }
        }
        return Option<String>::None();
    }
    
    /// Returns the final path component, or `None`.
    fn file_name(self) -> Option<String> {
        let s = self.c_str();
        let len = self.str.length();
        
        if (len == 0) return Option<String>::None();
        
        // Remove trailing separators
        let end = len;
        while (end > 0 && (s[end-1] == '/' || s[end-1] == '\\')) {
            end = end - 1;
        }
        if (end == 0) return Option<String>::None(); // Root
        
        let start = end;
        while (start > 0 && s[start-1] != '/' && s[start-1] != '\\') {
            start = start - 1;
        }
        
        return Option<String>::Some(self.str.substring(start, end - start));
    }
    
    /// Returns the parent directory, or `None`.
    fn parent(self) -> Option<Path> {
        let s = self.c_str();
        let len = self.str.length();
        if (len == 0) return Option<Path>::None();
        
        // Trim trailing separators
        let 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<Path>::None();
        
        while (end > 0 && (s[end-1] == '/' || s[end-1] == '\\')) {
            end = end - 1;
        }
        
        if (end == 0) {
            // Must be root
            return Option<Path>::Some(Path::new("/"));
        }
        
        let parent_str = self.str.substring(0, end);
        return Option<Path>::Some(Path { str: parent_str });
    }

    /// Frees the path memory.
    fn free(self) {
        self.str.free();
    }
}