vim-patch:9.1.0569: fnamemodify() treats ".." and "../" differently (#29673)

Problem:  fnamemodify() treats ".." and "../" differently.
Solution: Expand ".." properly like how "/.." is treated in 8.2.3388.
          (zeertzjq)

closes: vim/vim#15218

1ee7420460
(cherry picked from commit 028dd3c5c4)
This commit is contained in:
zeertzjq
2024-07-12 14:30:49 +08:00
committed by github-actions[bot]
parent bddbbd874c
commit ceb82a9396
5 changed files with 47 additions and 22 deletions

View File

@@ -2384,9 +2384,13 @@ static int path_to_absolute(const char *fname, char *buf, size_t len, int force)
p = strrchr(fname, '\\'); p = strrchr(fname, '\\');
} }
#endif #endif
if (p == NULL && strcmp(fname, "..") == 0) {
// Handle ".." without path separators.
p = fname + 2;
}
if (p != NULL) { if (p != NULL) {
if (strcmp(p + 1, "..") == 0) { if (vim_ispathsep_nocolon(*p) && strcmp(p + 1, "..") == 0) {
// for "/path/dir/.." include the "/.." // For "/path/dir/.." include the "/..".
p += 3; p += 3;
} }
assert(p >= fname); assert(p >= fname);

View File

@@ -107,6 +107,9 @@ func Test_findfile()
let l = findfile('bar', ';../', -1) let l = findfile('bar', ';../', -1)
call assert_equal(1, len(l)) call assert_equal(1, len(l))
call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
let l = findfile('bar', ';..', -1)
call assert_equal(1, len(l))
call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2/', -1) let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2/', -1)
call assert_equal(1, len(l)) call assert_equal(1, len(l))
@@ -117,6 +120,9 @@ func Test_findfile()
let l = findfile('bar', ';../../', -1) let l = findfile('bar', ';../../', -1)
call assert_equal(1, len(l)) call assert_equal(1, len(l))
call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
let l = findfile('bar', ';../..', -1)
call assert_equal(1, len(l))
call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
let l = findfile('bar', ';' . save_dir . '/Xfinddir1/', -1) let l = findfile('bar', ';' . save_dir . '/Xfinddir1/', -1)
call assert_equal(2, len(l)) call assert_equal(2, len(l))
@@ -130,6 +136,10 @@ func Test_findfile()
call assert_equal(2, len(l)) call assert_equal(2, len(l))
call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
call assert_match('.*/Xfinddir1/bar', l[1]) call assert_match('.*/Xfinddir1/bar', l[1])
let l = findfile('bar', ';../../..', -1)
call assert_equal(2, len(l))
call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
call assert_match('.*/Xfinddir1/bar', l[1])
" Test combined downwards and upwards search from Xdir2/. " Test combined downwards and upwards search from Xdir2/.
cd ../.. cd ../..

View File

@@ -14,6 +14,8 @@ func Test_fnamemodify()
call assert_equal($HOME .. "/foo" , fnamemodify('~/foo', ':p')) call assert_equal($HOME .. "/foo" , fnamemodify('~/foo', ':p'))
call assert_equal(fnamemodify('.', ':p:h:h:h') .. '/', fnamemodify($HOME .. '/../', ':p')) call assert_equal(fnamemodify('.', ':p:h:h:h') .. '/', fnamemodify($HOME .. '/../', ':p'))
call assert_equal(fnamemodify('.', ':p:h:h:h') .. '/', fnamemodify($HOME .. '/..', ':p')) call assert_equal(fnamemodify('.', ':p:h:h:h') .. '/', fnamemodify($HOME .. '/..', ':p'))
call assert_equal(fnamemodify('.', ':p:h:h') .. '/', fnamemodify('../', ':p'))
call assert_equal(fnamemodify('.', ':p:h:h') .. '/', fnamemodify('..', ':p'))
call assert_equal('test.out', fnamemodify('test.out', ':.')) call assert_equal('test.out', fnamemodify('test.out', ':.'))
call assert_equal('a', fnamemodify('../testdir/a', ':.')) call assert_equal('a', fnamemodify('../testdir/a', ':.'))
call assert_equal('~/testdir/test.out', fnamemodify('test.out', ':~')) call assert_equal('~/testdir/test.out', fnamemodify('test.out', ':~'))

View File

@@ -143,15 +143,15 @@ func Test_tagfiles_stopdir()
call writefile([], 'Xtagsdir1/Xtags', 'D') call writefile([], 'Xtagsdir1/Xtags', 'D')
cd Xtagsdir1/ cd Xtagsdir1/
let &tags = './Xtags;' .. fnamemodify('./..', ':p') let &tags = './Xtags;' .. fnamemodify('..', ':p')
call assert_equal(1, len(tagfiles())) call assert_equal(1, len(tagfiles()))
cd Xtagsdir2/ cd Xtagsdir2/
let &tags = './Xtags;' .. fnamemodify('./..', ':p') let &tags = './Xtags;' .. fnamemodify('..', ':p')
call assert_equal(1, len(tagfiles())) call assert_equal(1, len(tagfiles()))
cd Xtagsdir3/ cd Xtagsdir3/
let &tags = './Xtags;' .. fnamemodify('./..', ':p') let &tags = './Xtags;' .. fnamemodify('..', ':p')
call assert_equal(0, len(tagfiles())) call assert_equal(0, len(tagfiles()))
let &tags = './Xtags;../' let &tags = './Xtags;../'
@@ -163,6 +163,15 @@ func Test_tagfiles_stopdir()
cd .. cd ..
call assert_equal(1, len(tagfiles())) call assert_equal(1, len(tagfiles()))
let &tags = './Xtags;..'
call assert_equal(1, len(tagfiles()))
cd Xtagsdir2/
call assert_equal(1, len(tagfiles()))
cd Xtagsdir3/
call assert_equal(0, len(tagfiles()))
set tags& set tags&
call chdir(save_cwd) call chdir(save_cwd)
endfunc endfunc

View File

@@ -468,8 +468,11 @@ describe('path.c', function()
eq(OK, result) eq(OK, result)
end) end)
itp('concatenates directory name if it does not contain a slash', function() itp('produces absolute path for .. without a slash', function()
local expected = uv.cwd() .. '/..' local old_dir = uv.cwd()
uv.chdir('..')
local expected = uv.cwd()
uv.chdir(old_dir)
local filename = '..' local filename = '..'
local buflen = get_buf_len(expected, filename) local buflen = get_buf_len(expected, filename)
local do_expand = 1 local do_expand = 1
@@ -478,9 +481,7 @@ describe('path.c', function()
eq(OK, result) eq(OK, result)
end) end)
itp( itp('produces absolute path if possible and if path contains a slash', function()
'enters given directory (instead of just concatenating the strings) if possible and if path contains a slash',
function()
local old_dir = uv.cwd() local old_dir = uv.cwd()
uv.chdir('..') uv.chdir('..')
local expected = uv.cwd() .. '/test.file' local expected = uv.cwd() .. '/test.file'
@@ -491,8 +492,7 @@ describe('path.c', function()
local buf, result = vim_FullName(filename, buflen, do_expand) local buf, result = vim_FullName(filename, buflen, do_expand)
eq(expected, ffi.string(buf)) eq(expected, ffi.string(buf))
eq(OK, result) eq(OK, result)
end end)
)
itp('just copies the path if it is already absolute and force=0', function() itp('just copies the path if it is already absolute and force=0', function()
local absolute_path = '/absolute/path' local absolute_path = '/absolute/path'