Skip to content

Commit cbb24d3

Browse files
authored
os: fix is_abs_path function for Windows systems (#14397)
1 parent 7fe3ef9 commit cbb24d3

File tree

4 files changed

+115
-20
lines changed

4 files changed

+115
-20
lines changed

vlib/os/filepath.v

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
module os
2+
3+
// Collection of useful functions for manipulation, validation and analysis of system paths.
4+
// The following functions handle paths depending on the operating system,
5+
// therefore results may be different for certain operating systems.
6+
7+
const (
8+
fslash = `/`
9+
bslash = `\\`
10+
dot = `.`
11+
)
12+
13+
// is_abs_path returns `true` if the given `path` is absolute.
14+
pub fn is_abs_path(path string) bool {
15+
if path.len == 0 {
16+
return false
17+
}
18+
$if windows {
19+
return is_device_path(path) || is_drive_rooted(path) || is_normal_path(path)
20+
}
21+
return path[0] == os.fslash
22+
}
23+
24+
// win_volume_len returns the length of the
25+
// Windows volume/drive from the given `path`.
26+
fn win_volume_len(path string) int {
27+
plen := path.len
28+
if plen < 2 {
29+
return 0
30+
}
31+
if has_drive_letter(path) {
32+
return 2
33+
}
34+
// its UNC path / DOS device path?
35+
if path.len >= 5 && starts_w_slash_slash(path) && !is_slash(path[2]) {
36+
for i := 3; i < plen; i++ {
37+
if is_slash(path[i]) {
38+
if i + 1 >= plen || is_slash(path[i + 1]) {
39+
break
40+
}
41+
i++
42+
for ; i < plen; i++ {
43+
if is_slash(path[i]) {
44+
return i
45+
}
46+
}
47+
return i
48+
}
49+
}
50+
}
51+
return 0
52+
}
53+
54+
fn is_slash(b u8) bool {
55+
$if windows {
56+
return b == os.bslash || b == os.fslash
57+
}
58+
return b == os.fslash
59+
}
60+
61+
fn is_device_path(path string) bool {
62+
return win_volume_len(path) >= 5 && starts_w_slash_slash(path)
63+
}
64+
65+
fn has_drive_letter(path string) bool {
66+
return path.len >= 2 && path[0].is_letter() && path[1] == `:`
67+
}
68+
69+
fn starts_w_slash_slash(path string) bool {
70+
return path.len >= 2 && is_slash(path[0]) && is_slash(path[1])
71+
}
72+
73+
fn is_drive_rooted(path string) bool {
74+
return path.len >= 3 && has_drive_letter(path) && is_slash(path[2])
75+
}
76+
77+
// is_normal_path returns `true` if the given
78+
// `path` is NOT a network or Windows device path.
79+
fn is_normal_path(path string) bool {
80+
plen := path.len
81+
if plen == 0 {
82+
return false
83+
}
84+
return (plen == 1 && is_slash(path[0])) || (plen >= 2 && is_slash(path[0])
85+
&& !is_slash(path[1]))
86+
}

vlib/os/filepath_test.v

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module os
2+
3+
fn test_is_abs_path() {
4+
$if windows {
5+
assert is_abs_path('/')
6+
assert is_abs_path('\\')
7+
assert !is_abs_path('\\\\')
8+
assert is_abs_path(r'C:\path\to\files\file.v')
9+
assert is_abs_path(r'\\Host\share')
10+
assert is_abs_path(r'//Host\share\files\file.v')
11+
assert is_abs_path(r'\\.\BootPartition\Windows')
12+
assert !is_abs_path(r'\\.\')
13+
assert !is_abs_path(r'\\?\\')
14+
assert !is_abs_path(r'C:path\to\dir')
15+
assert !is_abs_path(r'dir')
16+
assert !is_abs_path(r'.\')
17+
assert !is_abs_path(r'.')
18+
assert !is_abs_path(r'\\Host')
19+
assert !is_abs_path(r'\\Host\')
20+
return
21+
}
22+
assert is_abs_path('/')
23+
assert is_abs_path('/path/to/files/file.v')
24+
assert !is_abs_path('\\')
25+
assert !is_abs_path('path/to/files/file.v')
26+
assert !is_abs_path('dir')
27+
assert !is_abs_path('./')
28+
assert !is_abs_path('.')
29+
}

vlib/os/os.v

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -454,18 +454,6 @@ pub fn is_file(path string) bool {
454454
return exists(path) && !is_dir(path)
455455
}
456456

457-
// is_abs_path returns `true` if `path` is absolute.
458-
pub fn is_abs_path(path string) bool {
459-
if path.len == 0 {
460-
return false
461-
}
462-
$if windows {
463-
return path[0] == `/` || // incase we're in MingGW bash
464-
(path[0].is_letter() && path.len > 1 && path[1] == `:`)
465-
}
466-
return path[0] == `/`
467-
}
468-
469457
// join_path returns a path as string from input string parameter(s).
470458
[manualfree]
471459
pub fn join_path(base string, dirs ...string) string {

vlib/os/os_test.v

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -590,14 +590,6 @@ fn test_ext() {
590590
assert os.file_ext('file') == ''
591591
}
592592

593-
fn test_is_abs() {
594-
assert os.is_abs_path('/home/user')
595-
assert os.is_abs_path('v/vlib') == false
596-
$if windows {
597-
assert os.is_abs_path('C:\\Windows\\')
598-
}
599-
}
600-
601593
fn test_join() {
602594
$if windows {
603595
assert os.join_path('v', 'vlib', 'os') == 'v\\vlib\\os'

0 commit comments

Comments
 (0)