From b03c8286c44b0ab1fb767f91d957824f96c59ef7 Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Mon, 20 Jan 2025 09:01:31 +0800 Subject: [PATCH 1/3] os: add split_path --- vlib/os/os.v | 41 ++++++++++++++++++++++++-- vlib/os/os_test.c.v | 71 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/vlib/os/os.v b/vlib/os/os.v index 5fda75b42e6adf..5641056f2ed34b 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -288,8 +288,8 @@ pub fn dir(opath string) string { other_separator := if path_separator == '/' { '\\' } else { '/' } path := opath.replace(other_separator, path_separator) pos := path.last_index(path_separator) or { return '.' } - if pos == 0 && path_separator == '/' { - return '/' + if pos == 0 { + return path_separator } return path[..pos] } @@ -324,6 +324,43 @@ pub fn file_name(opath string) string { return path.all_after_last(path_separator) } +// split_path will split `opath` into (`dir`,`filename`,`ext`). +// Examples: +// ```v +// dir,filename,ext := os.split_path('/usr/lib/test.so') +// assert [dir,filename,ext] == ['/usr/lib','test','.so'] +// ``` +pub fn split_path(opath string) (string, string, string) { + if opath == '.' { + return '.', '', '' + } else if opath == '..' { + return '..', '', '' + } + + other_separator := if path_separator == '/' { '\\' } else { '/' } + path := opath.replace(other_separator, path_separator) + if path == path_separator { + return path_separator, '', '' + } + if path.ends_with(path_separator) { + return path[..path.len - 1], '', '' + } + mut dir := '.' + if pos := path.last_index(path_separator) { + if pos == 0 { + dir = path_separator + } else { + dir = path[..pos] + } + } + file_name := path.all_after_last(path_separator) + pos_ext := file_name.last_index_u8(`.`) + if pos_ext == -1 || pos_ext == 0 || pos_ext + 1 >= file_name.len { + return dir, file_name, '' + } + return dir, file_name[..pos_ext], file_name[pos_ext..] +} + // input_opt returns a one-line string from stdin, after printing a prompt. // Returns `none` in case of an error (end of input). pub fn input_opt(prompt string) ?string { diff --git a/vlib/os/os_test.c.v b/vlib/os/os_test.c.v index f6973baaf44c55..7b5837bcff65f7 100644 --- a/vlib/os/os_test.c.v +++ b/vlib/os/os_test.c.v @@ -641,6 +641,7 @@ fn test_rmdir_not_exist() ! { fn test_dir() { $if windows { + assert os.dir('\\') == '\\' assert os.dir('C:\\a\\b\\c') == 'C:\\a\\b' assert os.dir('C:\\a\\b\\') == 'C:\\a\\b' assert os.dir('C:/a/b/c') == 'C:\\a\\b' @@ -684,6 +685,76 @@ fn test_file_name() { assert os.file_name('filename') == 'filename' } +fn test_split_path() { + mut dir := '' + mut filename := '' + mut ext := '' + $if windows { + dir, filename, ext = os.split_path(r'\') + assert [dir, filename, ext] == [r'\', '', ''] + + dir, filename, ext = os.split_path('.') + assert [dir, filename, ext] == ['.', '', ''] + + dir, filename, ext = os.split_path('..') + assert [dir, filename, ext] == ['..', '', ''] + + dir, filename, ext = os.split_path(r'\x.c.v') + assert [dir, filename, ext] == [r'\', 'x.c', '.v'] + + dir, filename, ext = os.split_path(r'.\x.c.v') + assert [dir, filename, ext] == ['.', 'x.c', '.v'] + + dir, filename, ext = os.split_path(r'x.c.v') + assert [dir, filename, ext] == ['.', 'x.c', '.v'] + + dir, filename, ext = os.split_path(r'..\x.c.v') + assert [dir, filename, ext] == ['..', 'x.c', '.v'] + + dir, filename, ext = os.split_path(r'\lib\x.c.v') + assert [dir, filename, ext] == [r'\lib', 'x.c', '.v'] + + dir, filename, ext = os.split_path(r'\lib\x.c.v\') + assert [dir, filename, ext] == [r'\lib\x.c.v', '', ''] + + dir, filename, ext = os.split_path(r'\lib\x.c.') + assert [dir, filename, ext] == [r'\lib', 'x.c.', ''] + } $else { + dir, filename, ext = os.split_path('/') + assert [dir, filename, ext] == ['/', '', ''] + + dir, filename, ext = os.split_path('.') + assert [dir, filename, ext] == ['.', '', ''] + + dir, filename, ext = os.split_path('..') + assert [dir, filename, ext] == ['..', '', ''] + + dir, filename, ext = os.split_path('/x.c.v') + assert [dir, filename, ext] == ['/', 'x.c', '.v'] + + dir, filename, ext = os.split_path('./x.c.v') + assert [dir, filename, ext] == ['.', 'x.c', '.v'] + + dir, filename, ext = os.split_path('x.c.v') + assert [dir, filename, ext] == ['.', 'x.c', '.v'] + + dir, filename, ext = os.split_path('../x.c.v') + assert [dir, filename, ext] == ['..', 'x.c', '.v'] + + dir, filename, ext = os.split_path('/lib/x.c.v') + assert [dir, filename, ext] == ['/lib', 'x.c', '.v'] + + dir, filename, ext = os.split_path('/lib/x.c.v/') + assert [dir, filename, ext] == ['/lib/x.c.v', '', ''] + + dir, filename, ext = os.split_path('/lib/../x.c.v/') + assert [dir, filename, ext] == ['/lib/../x.c.v', '', ''] + + dir, filename, ext = os.split_path('/lib/x.c.') + assert [dir, filename, ext] == ['/lib', 'x.c.', ''] + } +} + fn test_uname() { u := os.uname() assert u.sysname.len > 0 From c25f991c4376baee808a37f12bf72d45411dcdaf Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Mon, 20 Jan 2025 15:26:06 +0800 Subject: [PATCH 2/3] handle both windows/\!windows case --- vlib/os/os.v | 26 +++++++------ vlib/os/os_test.c.v | 89 ++++++++++++++++++++++----------------------- 2 files changed, 58 insertions(+), 57 deletions(-) diff --git a/vlib/os/os.v b/vlib/os/os.v index 5641056f2ed34b..56bdf0587e438f 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -324,36 +324,38 @@ pub fn file_name(opath string) string { return path.all_after_last(path_separator) } -// split_path will split `opath` into (`dir`,`filename`,`ext`). +// split_path will split `path` into (`dir`,`filename`,`ext`). // Examples: // ```v // dir,filename,ext := os.split_path('/usr/lib/test.so') // assert [dir,filename,ext] == ['/usr/lib','test','.so'] // ``` -pub fn split_path(opath string) (string, string, string) { - if opath == '.' { +pub fn split_path(path string) (string, string, string) { + if path == '' { + return '', '', '' + } else if path == '.' { return '.', '', '' - } else if opath == '..' { + } else if path == '..' { return '..', '', '' } - other_separator := if path_separator == '/' { '\\' } else { '/' } - path := opath.replace(other_separator, path_separator) - if path == path_separator { - return path_separator, '', '' + my_path_separator := if path.contains('/') { '/' } else { '\\' } + + if path == my_path_separator { + return my_path_separator, '', '' } - if path.ends_with(path_separator) { + if path.ends_with(my_path_separator) { return path[..path.len - 1], '', '' } mut dir := '.' - if pos := path.last_index(path_separator) { + if pos := path.last_index(my_path_separator) { if pos == 0 { - dir = path_separator + dir = my_path_separator } else { dir = path[..pos] } } - file_name := path.all_after_last(path_separator) + file_name := path.all_after_last(my_path_separator) pos_ext := file_name.last_index_u8(`.`) if pos_ext == -1 || pos_ext == 0 || pos_ext + 1 >= file_name.len { return dir, file_name, '' diff --git a/vlib/os/os_test.c.v b/vlib/os/os_test.c.v index 7b5837bcff65f7..d53572bc1240a9 100644 --- a/vlib/os/os_test.c.v +++ b/vlib/os/os_test.c.v @@ -689,70 +689,69 @@ fn test_split_path() { mut dir := '' mut filename := '' mut ext := '' - $if windows { - dir, filename, ext = os.split_path(r'\') - assert [dir, filename, ext] == [r'\', '', ''] - dir, filename, ext = os.split_path('.') - assert [dir, filename, ext] == ['.', '', ''] + dir, filename, ext = os.split_path('') + assert [dir, filename, ext] == ['', '', ''] - dir, filename, ext = os.split_path('..') - assert [dir, filename, ext] == ['..', '', ''] + dir, filename, ext = os.split_path('a') + assert [dir, filename, ext] == ['.', 'a', ''] - dir, filename, ext = os.split_path(r'\x.c.v') - assert [dir, filename, ext] == [r'\', 'x.c', '.v'] + dir, filename, ext = os.split_path('.') + assert [dir, filename, ext] == ['.', '', ''] - dir, filename, ext = os.split_path(r'.\x.c.v') - assert [dir, filename, ext] == ['.', 'x.c', '.v'] + dir, filename, ext = os.split_path('..') + assert [dir, filename, ext] == ['..', '', ''] - dir, filename, ext = os.split_path(r'x.c.v') - assert [dir, filename, ext] == ['.', 'x.c', '.v'] + dir, filename, ext = os.split_path('\\') + assert [dir, filename, ext] == ['\\', '', ''] - dir, filename, ext = os.split_path(r'..\x.c.v') - assert [dir, filename, ext] == ['..', 'x.c', '.v'] + dir, filename, ext = os.split_path('\\x.c.v') + assert [dir, filename, ext] == ['\\', 'x.c', '.v'] - dir, filename, ext = os.split_path(r'\lib\x.c.v') - assert [dir, filename, ext] == [r'\lib', 'x.c', '.v'] + dir, filename, ext = os.split_path('.\\x.c.v') + assert [dir, filename, ext] == ['.', 'x.c', '.v'] - dir, filename, ext = os.split_path(r'\lib\x.c.v\') - assert [dir, filename, ext] == [r'\lib\x.c.v', '', ''] + dir, filename, ext = os.split_path('x.c.v') + assert [dir, filename, ext] == ['.', 'x.c', '.v'] - dir, filename, ext = os.split_path(r'\lib\x.c.') - assert [dir, filename, ext] == [r'\lib', 'x.c.', ''] - } $else { - dir, filename, ext = os.split_path('/') - assert [dir, filename, ext] == ['/', '', ''] + dir, filename, ext = os.split_path('..\\x.c.v') + assert [dir, filename, ext] == ['..', 'x.c', '.v'] - dir, filename, ext = os.split_path('.') - assert [dir, filename, ext] == ['.', '', ''] + dir, filename, ext = os.split_path('\\lib\\x.c.v') + assert [dir, filename, ext] == ['\\lib', 'x.c', '.v'] - dir, filename, ext = os.split_path('..') - assert [dir, filename, ext] == ['..', '', ''] + dir, filename, ext = os.split_path('\\lib\\x.c.v\\') + assert [dir, filename, ext] == ['\\lib\\x.c.v', '', ''] - dir, filename, ext = os.split_path('/x.c.v') - assert [dir, filename, ext] == ['/', 'x.c', '.v'] + dir, filename, ext = os.split_path('\\lib\\x.c.') + assert [dir, filename, ext] == ['\\lib', 'x.c.', ''] - dir, filename, ext = os.split_path('./x.c.v') - assert [dir, filename, ext] == ['.', 'x.c', '.v'] + dir, filename, ext = os.split_path('C:\\lib\\x.c.') + assert [dir, filename, ext] == ['C:\\lib', 'x.c.', ''] - dir, filename, ext = os.split_path('x.c.v') - assert [dir, filename, ext] == ['.', 'x.c', '.v'] + dir, filename, ext = os.split_path('/') + assert [dir, filename, ext] == ['/', '', ''] - dir, filename, ext = os.split_path('../x.c.v') - assert [dir, filename, ext] == ['..', 'x.c', '.v'] + dir, filename, ext = os.split_path('/x.c.v') + assert [dir, filename, ext] == ['/', 'x.c', '.v'] - dir, filename, ext = os.split_path('/lib/x.c.v') - assert [dir, filename, ext] == ['/lib', 'x.c', '.v'] + dir, filename, ext = os.split_path('./x.c.v') + assert [dir, filename, ext] == ['.', 'x.c', '.v'] - dir, filename, ext = os.split_path('/lib/x.c.v/') - assert [dir, filename, ext] == ['/lib/x.c.v', '', ''] + dir, filename, ext = os.split_path('../x.c.v') + assert [dir, filename, ext] == ['..', 'x.c', '.v'] - dir, filename, ext = os.split_path('/lib/../x.c.v/') - assert [dir, filename, ext] == ['/lib/../x.c.v', '', ''] + dir, filename, ext = os.split_path('/lib/x.c.v') + assert [dir, filename, ext] == ['/lib', 'x.c', '.v'] - dir, filename, ext = os.split_path('/lib/x.c.') - assert [dir, filename, ext] == ['/lib', 'x.c.', ''] - } + dir, filename, ext = os.split_path('/lib/x.c.v/') + assert [dir, filename, ext] == ['/lib/x.c.v', '', ''] + + dir, filename, ext = os.split_path('/lib/../x.c.v/') + assert [dir, filename, ext] == ['/lib/../x.c.v', '', ''] + + dir, filename, ext = os.split_path('/lib/x.c.') + assert [dir, filename, ext] == ['/lib', 'x.c.', ''] } fn test_uname() { From e9d6c4838d73d8ea19accfe63732b88a74321d72 Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Tue, 21 Jan 2025 08:13:35 +0800 Subject: [PATCH 3/3] fix IfGuard; fix dir(),base(),file_name() support Win/non-Win --- vlib/os/os.v | 63 +++++++++++++++++++++++---------------------- vlib/os/os_test.c.v | 63 ++++++++++++++++++++------------------------- 2 files changed, 60 insertions(+), 66 deletions(-) diff --git a/vlib/os/os.v b/vlib/os/os.v index 56bdf0587e438f..b298b99a910794 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -281,15 +281,14 @@ pub fn file_ext(opath string) string { // If the path is empty, dir returns ".". If the path consists entirely of separators, // dir returns a single separator. // The returned path does not end in a separator unless it is the root directory. -pub fn dir(opath string) string { - if opath == '' { +pub fn dir(path string) string { + if path == '' { return '.' } - other_separator := if path_separator == '/' { '\\' } else { '/' } - path := opath.replace(other_separator, path_separator) - pos := path.last_index(path_separator) or { return '.' } + detected_path_separator := if path.contains('/') { '/' } else { '\\' } + pos := path.last_index(detected_path_separator) or { return '.' } if pos == 0 { - return path_separator + return detected_path_separator } return path[..pos] } @@ -298,30 +297,28 @@ pub fn dir(opath string) string { // Trailing path separators are removed before extracting the last element. // If the path is empty, base returns ".". If the path consists entirely of separators, base returns a // single separator. -pub fn base(opath string) string { - if opath == '' { +pub fn base(path string) string { + if path == '' { return '.' } - other_separator := if path_separator == '/' { '\\' } else { '/' } - path := opath.replace(other_separator, path_separator) - if path == path_separator { - return path_separator + detected_path_separator := if path.contains('/') { '/' } else { '\\' } + if path == detected_path_separator { + return detected_path_separator } - if path.ends_with(path_separator) { + if path.ends_with(detected_path_separator) { path2 := path[..path.len - 1] - pos := path2.last_index(path_separator) or { return path2.clone() } + pos := path2.last_index(detected_path_separator) or { return path2.clone() } return path2[pos + 1..] } - pos := path.last_index(path_separator) or { return path.clone() } + pos := path.last_index(detected_path_separator) or { return path.clone() } return path[pos + 1..] } // file_name will return all characters found after the last occurrence of `path_separator`. // file extension is included. -pub fn file_name(opath string) string { - other_separator := if path_separator == '/' { '\\' } else { '/' } - path := opath.replace(other_separator, path_separator) - return path.all_after_last(path_separator) +pub fn file_name(path string) string { + detected_path_separator := if path.contains('/') { '/' } else { '\\' } + return path.all_after_last(detected_path_separator) } // split_path will split `path` into (`dir`,`filename`,`ext`). @@ -332,30 +329,34 @@ pub fn file_name(opath string) string { // ``` pub fn split_path(path string) (string, string, string) { if path == '' { - return '', '', '' + return '.', '', '' } else if path == '.' { return '.', '', '' } else if path == '..' { return '..', '', '' } - my_path_separator := if path.contains('/') { '/' } else { '\\' } + detected_path_separator := if path.contains('/') { '/' } else { '\\' } - if path == my_path_separator { - return my_path_separator, '', '' + if path == detected_path_separator { + return detected_path_separator, '', '' } - if path.ends_with(my_path_separator) { + if path.ends_with(detected_path_separator) { return path[..path.len - 1], '', '' } mut dir := '.' - if pos := path.last_index(my_path_separator) { - if pos == 0 { - dir = my_path_separator - } else { - dir = path[..pos] - } + /* + TODO: JS backend does not support IfGuard yet. + */ + pos := path.last_index(detected_path_separator) or { -1 } + if pos == -1 { + dir = '.' + } else if pos == 0 { + dir = detected_path_separator + } else { + dir = path[..pos] } - file_name := path.all_after_last(my_path_separator) + file_name := path.all_after_last(detected_path_separator) pos_ext := file_name.last_index_u8(`.`) if pos_ext == -1 || pos_ext == 0 || pos_ext + 1 >= file_name.len { return dir, file_name, '' diff --git a/vlib/os/os_test.c.v b/vlib/os/os_test.c.v index d53572bc1240a9..7d8e155306fe73 100644 --- a/vlib/os/os_test.c.v +++ b/vlib/os/os_test.c.v @@ -596,6 +596,7 @@ fn test_is_executable_writable_readable() { } fn test_file_ext() { + assert os.file_ext('') == '' assert os.file_ext('file.v') == '.v' assert os.file_ext('file.js.v') == '.v' assert os.file_ext('file.ext1.ext2.ext3') == '.ext3' @@ -640,48 +641,40 @@ fn test_rmdir_not_exist() ! { } fn test_dir() { - $if windows { - assert os.dir('\\') == '\\' - assert os.dir('C:\\a\\b\\c') == 'C:\\a\\b' - assert os.dir('C:\\a\\b\\') == 'C:\\a\\b' - assert os.dir('C:/a/b/c') == 'C:\\a\\b' - assert os.dir('C:/a/b/') == 'C:\\a\\b' - } $else { - assert os.dir('/') == '/' - assert os.dir('/abc') == '/' - assert os.dir('/var/tmp/foo') == '/var/tmp' - assert os.dir('/var/tmp/') == '/var/tmp' - assert os.dir('C:\\a\\b\\c') == 'C:/a/b' - assert os.dir('C:\\a\\b\\') == 'C:/a/b' - } + assert os.dir('') == '.' + assert os.dir('\\') == '\\' + assert os.dir('C:\\a\\b\\c') == 'C:\\a\\b' + assert os.dir('C:\\a\\b\\') == 'C:\\a\\b' + assert os.dir('C:/a/b/c') == 'C:/a/b' + assert os.dir('C:/a/b/') == 'C:/a/b' + assert os.dir('/') == '/' + assert os.dir('/abc') == '/' + assert os.dir('/var/tmp/foo') == '/var/tmp' + assert os.dir('/var/tmp/') == '/var/tmp' assert os.dir('os') == '.' } fn test_base() { - $if windows { - assert os.base('v\\vlib\\os') == 'os' - assert os.base('v\\vlib\\os\\') == 'os' - assert os.base('v/vlib/os') == 'os' - assert os.base('v/vlib/os/') == 'os' - } $else { - assert os.base('v/vlib/os') == 'os' - assert os.base('v/vlib/os/') == 'os' - assert os.base('v\\vlib\\os') == 'os' - assert os.base('v\\vlib\\os\\') == 'os' - } + assert os.base('') == '.' + assert os.base('v\\vlib\\os') == 'os' + assert os.base('v\\vlib\\os\\') == 'os' + assert os.base('v/vlib/os') == 'os' + assert os.base('v/vlib/os/') == 'os' + assert os.base('v/vlib/os') == 'os' + assert os.base('v/vlib/os/') == 'os' + assert os.base('v\\vlib\\os') == 'os' + assert os.base('v\\vlib\\os\\') == 'os' assert os.base('filename') == 'filename' } fn test_file_name() { - $if windows { - assert os.file_name('v\\vlib\\os\\os.v') == 'os.v' - assert os.file_name('v\\vlib\\os\\') == '' - assert os.file_name('v\\vlib\\os') == 'os' - } $else { - assert os.file_name('v/vlib/os/os.v') == 'os.v' - assert os.file_name('v/vlib/os/') == '' - assert os.file_name('v/vlib/os') == 'os' - } + assert os.file_name('') == '' + assert os.file_name('v\\vlib\\os\\os.v') == 'os.v' + assert os.file_name('v\\vlib\\os\\') == '' + assert os.file_name('v\\vlib\\os') == 'os' + assert os.file_name('v/vlib/os/os.v') == 'os.v' + assert os.file_name('v/vlib/os/') == '' + assert os.file_name('v/vlib/os') == 'os' assert os.file_name('filename') == 'filename' } @@ -691,7 +684,7 @@ fn test_split_path() { mut ext := '' dir, filename, ext = os.split_path('') - assert [dir, filename, ext] == ['', '', ''] + assert [dir, filename, ext] == ['.', '', ''] dir, filename, ext = os.split_path('a') assert [dir, filename, ext] == ['.', 'a', '']