diff --git a/vlib/os/filepath.v b/vlib/os/filepath.v new file mode 100644 index 0000000000..2770d26e5b --- /dev/null +++ b/vlib/os/filepath.v @@ -0,0 +1,86 @@ +module os + +// Collection of useful functions for manipulation, validation and analysis of system paths. +// The following functions handle paths depending on the operating system, +// therefore results may be different for certain operating systems. + +const ( + fslash = `/` + bslash = `\\` + dot = `.` +) + +// is_abs_path returns `true` if the given `path` is absolute. +pub fn is_abs_path(path string) bool { + if path.len == 0 { + return false + } + $if windows { + return is_device_path(path) || is_drive_rooted(path) || is_normal_path(path) + } + return path[0] == os.fslash +} + +// win_volume_len returns the length of the +// Windows volume/drive from the given `path`. +fn win_volume_len(path string) int { + plen := path.len + if plen < 2 { + return 0 + } + if has_drive_letter(path) { + return 2 + } + // its UNC path / DOS device path? + if path.len >= 5 && starts_w_slash_slash(path) && !is_slash(path[2]) { + for i := 3; i < plen; i++ { + if is_slash(path[i]) { + if i + 1 >= plen || is_slash(path[i + 1]) { + break + } + i++ + for ; i < plen; i++ { + if is_slash(path[i]) { + return i + } + } + return i + } + } + } + return 0 +} + +fn is_slash(b u8) bool { + $if windows { + return b == os.bslash || b == os.fslash + } + return b == os.fslash +} + +fn is_device_path(path string) bool { + return win_volume_len(path) >= 5 && starts_w_slash_slash(path) +} + +fn has_drive_letter(path string) bool { + return path.len >= 2 && path[0].is_letter() && path[1] == `:` +} + +fn starts_w_slash_slash(path string) bool { + return path.len >= 2 && is_slash(path[0]) && is_slash(path[1]) +} + +fn is_drive_rooted(path string) bool { + return path.len >= 3 && has_drive_letter(path) && is_slash(path[2]) +} + +// is_normal_path returns `true` if the given +// `path` is NOT a network or Windows device path. +fn is_normal_path(path string) bool { + plen := path.len + if plen == 0 { + return false + } + return (plen == 1 && is_slash(path[0])) || (plen >= 2 && is_slash(path[0]) + && !is_slash(path[1])) +} diff --git a/vlib/os/filepath_test.v b/vlib/os/filepath_test.v new file mode 100644 index 0000000000..0c74b7633c --- /dev/null +++ b/vlib/os/filepath_test.v @@ -0,0 +1,29 @@ +module os + +fn test_is_abs_path() { + $if windows { + assert is_abs_path('/') + assert is_abs_path('\\') + assert !is_abs_path('\\\\') + assert is_abs_path(r'C:\path\to\files\file.v') + assert is_abs_path(r'\\Host\share') + assert is_abs_path(r'//Host\share\files\file.v') + assert is_abs_path(r'\\.\BootPartition\Windows') + assert !is_abs_path(r'\\.\') + assert !is_abs_path(r'\\?\\') + assert !is_abs_path(r'C:path\to\dir') + assert !is_abs_path(r'dir') + assert !is_abs_path(r'.\') + assert !is_abs_path(r'.') + assert !is_abs_path(r'\\Host') + assert !is_abs_path(r'\\Host\') + return + } + assert is_abs_path('/') + assert is_abs_path('/path/to/files/file.v') + assert !is_abs_path('\\') + assert !is_abs_path('path/to/files/file.v') + assert !is_abs_path('dir') + assert !is_abs_path('./') + assert !is_abs_path('.') +} diff --git a/vlib/os/os.v b/vlib/os/os.v index c55b34b283..e37829e1a3 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -454,18 +454,6 @@ pub fn is_file(path string) bool { return exists(path) && !is_dir(path) } -// is_abs_path returns `true` if `path` is absolute. -pub fn is_abs_path(path string) bool { - if path.len == 0 { - return false - } - $if windows { - return path[0] == `/` || // incase we're in MingGW bash - (path[0].is_letter() && path.len > 1 && path[1] == `:`) - } - return path[0] == `/` -} - // join_path returns a path as string from input string parameter(s). [manualfree] pub fn join_path(base string, dirs ...string) string { diff --git a/vlib/os/os_test.v b/vlib/os/os_test.v index dd6f4e3bc4..1782c7d16f 100644 --- a/vlib/os/os_test.v +++ b/vlib/os/os_test.v @@ -590,14 +590,6 @@ fn test_ext() { assert os.file_ext('file') == '' } -fn test_is_abs() { - assert os.is_abs_path('/home/user') - assert os.is_abs_path('v/vlib') == false - $if windows { - assert os.is_abs_path('C:\\Windows\\') - } -} - fn test_join() { $if windows { assert os.join_path('v', 'vlib', 'os') == 'v\\vlib\\os'