From 10002ccce90ea914de7fbf90d876f3f987d7b527 Mon Sep 17 00:00:00 2001 From: Henrik Holst <6200749+hholst80@users.noreply.github.com> Date: Sun, 5 May 2024 00:45:55 +0200 Subject: [PATCH] vlib.os: fix join-path Closes #20231 --- vlib/os/os.v | 55 +++++++++++++++++++++------------------------ vlib/os/os_test.c.v | 3 ++- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/vlib/os/os.v b/vlib/os/os.v index 25e6044d618dae..327a97b81b62f7 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -570,54 +570,49 @@ pub fn is_file(path string) bool { // them with a platform-specific path_separator. Empty elements are ignored. @[manualfree] pub fn join_path(base string, dirs ...string) string { - // TODO: fix freeing of `dirs` when the passed arguments are variadic, - // but do not free the arr, when `os.join_path(base, ...arr)` is called. - mut sb := strings.new_builder(base.len + dirs.len * 50) + mut sb := strings.new_builder(256) defer { unsafe { sb.free() } } - sbase := base.trim_right('\\/') - defer { - unsafe { sbase.free() } + mut i := 0 + if base != '' { + sb.write_string(base) + } else { + for i < dirs.len { + d := dirs[i] + if d != '' { + sb.write_string(d) + break + } + i++ + } } - sb.write_string(sbase) - for d in dirs { + for i < dirs.len { + d := dirs[i] if d != '' { sb.write_string(path_separator) sb.write_string(d) } + i++ } - mut res := sb.str() - if sbase == '' { - res = res.trim_left(path_separator) - } - if res.contains('/./') { - // Fix `join_path("/foo/bar", "./file.txt")` => `/foo/bar/./file.txt` - res = res.replace('/./', '/') - } + res := sb.str() return res } // join_path_single appends the `elem` after `base`, separated with a // platform-specific path_separator. Empty elements are ignored. -@[manualfree] pub fn join_path_single(base string, elem string) string { // TODO: deprecate this and make it `return os.join_path(base, elem)`, // when freeing variadic args vs ...arr is solved in the compiler - mut sb := strings.new_builder(base.len + elem.len + 1) - defer { - unsafe { sb.free() } - } - sbase := base.trim_right('\\/') - defer { - unsafe { sbase.free() } - } - if base != '' { - sb.write_string(sbase) - sb.write_string(path_separator) + if base != '' && elem != '' { + return '${base}${path_separator}${elem}' + } else if base != '' { + return base + } else if elem != '' { + return elem + } else { + return '' } - sb.write_string(elem) - return sb.str() } // walk_ext returns a recursive list of all files in `path` ending with `ext`. diff --git a/vlib/os/os_test.c.v b/vlib/os/os_test.c.v index 135f1bc733c819..8852501334b448 100644 --- a/vlib/os/os_test.c.v +++ b/vlib/os/os_test.c.v @@ -621,9 +621,10 @@ fn test_join() { assert os.join_path('v', '', 'dir') == 'v\\dir' } $else { assert os.join_path('v', 'vlib', 'os') == 'v/vlib/os' - assert os.join_path('/foo/bar', './file.txt') == '/foo/bar/file.txt' + assert os.join_path('/foo/bar', './file.txt') == '/foo/bar/./file.txt' assert os.join_path('', 'f1', 'f2') == 'f1/f2' assert os.join_path('v', '', 'dir') == 'v/dir' + assert os.join_path('/', 'test') == '/test' } }