DoxigAlpha

init

After init, next will return the first component after the root (there is no need to call first after init). To iterate backwards (from the end of the path to the beginning), call last after init and then iterate via previous calls. For Windows paths, error.BadPathName is returned if the path has an explicit namespace prefix (\\.\, \\?\, or \??\) or if it is a UNC path with more than two path separators at the beginning.

Function parameters

Parameters

#
path:[]const T

Type definitions in this namespace

Types

#

Returns if the given byte is a valid path separator

Functions

#
isSep
Returns if the given byte is a valid path separator
join
Naively combines a series of paths with the native path separator.
joinZ
Naively combines a series of paths with the native path separator and null terminator.
resolve
On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
resolveWindows
This function is like a series of `cd` statements executed one after another.
resolvePosix
This function is like a series of `cd` statements executed one after another.
dirname
Strip the last component from a file path.
relative
Returns the relative path from `from` to `to`.
extension
Searches for a file extension separated by a `.` and returns the string after that `.`.
stem
Returns the last component of this path without its extension (if any):
ComponentIterator
A path component iterator that can move forwards and backwards.
fmtAsUtf8Lossy
Format a path encoded as bytes for display as UTF-8.
fmtWtf16LeAsUtf8Lossy
Format a path encoded as WTF-16 LE for display as UTF-8.

= '\\'

Values

#
sep
= switch (native_os) { .windows, .uefi => sep_windows, else => sep_posix, }
sep_str
= switch (native_os) { .windows, .uefi => sep_str_windows, else => sep_str_posix, }
delimiter
= if (native_os == .windows) delimiter_windows else delimiter_posix

Source

Implementation

#
pub fn init(path: []const T) InitError!Self {
    const root_end_index: usize = switch (path_type) {
        .posix, .uefi => posix: {
            // Root on UEFI and POSIX only differs by the path separator
            var root_end_index: usize = 0;
            while (true) : (root_end_index += 1) {
                if (root_end_index >= path.len or !path_type.isSep(T, path[root_end_index])) {
                    break;
                }
            }
            break :posix root_end_index;
        },
        .windows => windows: {
            // Namespaces other than the Win32 file namespace are tricky
            // and basically impossible to determine a 'root' for, since it's
            // possible to construct an effectively arbitrarily long 'root',
            // e.g. `\\.\GLOBALROOT\??\UNC\localhost\C$\foo` is a
            // possible path that would be effectively equivalent to
            // `C:\foo`, and the `GLOBALROOT\??\` part can also be recursive,
            // so `GLOBALROOT\??\GLOBALROOT\??\...` would work for any number
            // of repetitions. Therefore, paths with an explicit namespace prefix
            // (\\.\, \??\, \\?\) are not allowed here.
            if (std.os.windows.getNamespacePrefix(T, path) != .none) {
                return error.BadPathName;
            }
            const windows_path_type = std.os.windows.getUnprefixedPathType(T, path);
            break :windows switch (windows_path_type) {
                .relative => 0,
                .root_local_device => path.len,
                .rooted => 1,
                .unc_absolute => unc: {
                    var end_index: usize = 2;
                    // Any extra separators between the first two and the server name are not allowed
                    // and will always lead to STATUS_OBJECT_PATH_INVALID if it is attempted
                    // to be used.
                    if (end_index < path.len and path_type.isSep(T, path[end_index])) {
                        return error.BadPathName;
                    }
                    // Server
                    while (end_index < path.len and !path_type.isSep(T, path[end_index])) {
                        end_index += 1;
                    }
                    // Slash(es) after server
                    while (end_index < path.len and path_type.isSep(T, path[end_index])) {
                        end_index += 1;
                    }
                    // Share
                    while (end_index < path.len and !path_type.isSep(T, path[end_index])) {
                        end_index += 1;
                    }
                    // Slash(es) after share
                    while (end_index < path.len and path_type.isSep(T, path[end_index])) {
                        end_index += 1;
                    }
                    break :unc end_index;
                },
                .drive_absolute => drive: {
                    var end_index: usize = 3;
                    while (end_index < path.len and path_type.isSep(T, path[end_index])) {
                        end_index += 1;
                    }
                    break :drive end_index;
                },
                .drive_relative => 2,
            };
        },
    };
    return .{
        .path = path,
        .root_end_index = root_end_index,
        .start_index = root_end_index,
        .end_index = root_end_index,
    };
}