Rename and refactor mch_FullName.

* Rename mch_FullName to mch_full_name to match the style guide.
* Add mch_full_dir_name, which saves the absolute path of a given
directory relative to cwd into a given buffer.
* Add function append_path, which glues together two given paths with a
slash.
* Adapt moonscript coding style to the tests.
This commit is contained in:
Thomas Wienecke
2014-03-03 15:28:28 +01:00
committed by Thiago de Arruda
parent 7e8c8cf5a1
commit 92a0374d7b
12 changed files with 267 additions and 126 deletions

View File

@@ -2418,7 +2418,7 @@ void buflist_altfpos(win_T *win)
/* /*
* Return TRUE if 'ffname' is not the same file as current file. * Return TRUE if 'ffname' is not the same file as current file.
* Fname must have a full path (expanded by mch_FullName()). * Fname must have a full path (expanded by mch_full_name()).
*/ */
int otherfile(char_u *ffname) int otherfile(char_u *ffname)
{ {

View File

@@ -12467,7 +12467,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv)
q[-1] = NUL; q[-1] = NUL;
q = gettail(p); q = gettail(p);
} }
if (q > p && !mch_isFullName(buf)) { if (q > p && !mch_is_full_name(buf)) {
/* symlink is relative to directory of argument */ /* symlink is relative to directory of argument */
cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1)); cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
if (cpy != NULL) { if (cpy != NULL) {

View File

@@ -3944,7 +3944,7 @@ expand_shellcmd (
flags |= EW_FILE | EW_EXEC; flags |= EW_FILE | EW_EXEC;
/* For an absolute name we don't use $PATH. */ /* For an absolute name we don't use $PATH. */
if (mch_isFullName(pat)) if (mch_is_full_name(pat))
path = (char_u *)" "; path = (char_u *)" ";
else if ((pat[0] == '.' && (vim_ispathsep(pat[1]) else if ((pat[0] == '.' && (vim_ispathsep(pat[1])
|| (pat[1] == '.' && vim_ispathsep(pat[2]))))) || (pat[1] == '.' && vim_ispathsep(pat[2])))))

View File

@@ -4769,7 +4769,7 @@ void shorten_fnames(int force)
&& !path_with_url(buf->b_fname) && !path_with_url(buf->b_fname)
&& (force && (force
|| buf->b_sfname == NULL || buf->b_sfname == NULL
|| mch_isFullName(buf->b_sfname))) { || mch_is_full_name(buf->b_sfname))) {
vim_free(buf->b_sfname); vim_free(buf->b_sfname);
buf->b_sfname = NULL; buf->b_sfname = NULL;
p = shorten_fname(buf->b_ffname, dirname); p = shorten_fname(buf->b_ffname, dirname);

View File

@@ -3381,7 +3381,7 @@ int resolve_symlink(char_u *fname, char_u *buf)
* portion of the filename (if any) and the path the symlink * portion of the filename (if any) and the path the symlink
* points to. * points to.
*/ */
if (mch_isFullName(buf)) if (mch_is_full_name(buf))
STRCPY(tmp, buf); STRCPY(tmp, buf);
else { else {
char_u *tail; char_u *tail;

View File

@@ -7945,7 +7945,7 @@ static void expand_path_option(char_u *curdir, garray_T *gap)
else if (path_with_url(buf)) else if (path_with_url(buf))
/* URL can't be used here */ /* URL can't be used here */
continue; continue;
else if (!mch_isFullName(buf)) { else if (!mch_is_full_name(buf)) {
/* Expand relative path to their full path equivalent */ /* Expand relative path to their full path equivalent */
len = (int)STRLEN(curdir); len = (int)STRLEN(curdir);
if (len + (int)STRLEN(buf) + 3 > MAXPATHL) if (len + (int)STRLEN(buf) + 3 > MAXPATHL)
@@ -8086,7 +8086,7 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
break; break;
} }
if (mch_isFullName(path)) { if (mch_is_full_name(path)) {
/* /*
* Last resort: shorten relative to curdir if possible. * Last resort: shorten relative to curdir if possible.
* 'possible' means: * 'possible' means:
@@ -8375,7 +8375,7 @@ gen_expand_wildcards (
*/ */
if (mch_has_exp_wildcard(p)) { if (mch_has_exp_wildcard(p)) {
if ((flags & EW_PATH) if ((flags & EW_PATH)
&& !mch_isFullName(p) && !mch_is_full_name(p)
&& !(p[0] == '.' && !(p[0] == '.'
&& (vim_ispathsep(p[1]) && (vim_ispathsep(p[1])
|| (p[1] == '.' && vim_ispathsep(p[2])))) || (p[1] == '.' && vim_ispathsep(p[2]))))

View File

@@ -1,4 +1,4 @@
/* vi:set ts=8 sts=4 sw=4: /* vi:set ts=2 sts=2 sw=2:
* *
* VIM - Vi IMproved by Bram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
* *
@@ -33,96 +33,129 @@ int mch_chdir(char *path) {
int mch_dirname(char_u *buf, int len) int mch_dirname(char_u *buf, int len)
{ {
int errno; int errno;
if ((errno = uv_cwd((char *)buf, len)) != 0) { if ((errno = uv_cwd((char *) buf, len)) != 0) {
STRCPY(buf, uv_strerror(errno)); STRCPY(buf, uv_strerror(errno));
return FAIL; return FAIL;
} }
return OK; return OK;
} }
/*
* Get the absolute name of the given relative directory.
*
* parameter directory: Directory name, relative to current directory.
* return FAIL for failure, OK for success
*/
int mch_full_dir_name(char *directory, char *buffer, int len)
{
int retval = OK;
if(0 == STRLEN(directory)) {
return mch_dirname((char_u *) buffer, len);
}
char old_dir[MAXPATHL];
/* Get current directory name. */
if (FAIL == mch_dirname((char_u *) old_dir, MAXPATHL)) {
return FAIL;
}
/* We have to get back to the current dir at the end, check if that works. */
if (0 != mch_chdir(old_dir)) {
return FAIL;
}
if (0 != mch_chdir(directory)) {
retval = FAIL;
}
if ((FAIL == retval) || (FAIL == mch_dirname((char_u *) buffer, len))) {
retval = FAIL;
}
if (0 != mch_chdir(old_dir)) {
/* That shouldn't happen, since we've tested if it works. */
retval = FAIL;
EMSG(_(e_prev_dir));
}
return retval;
}
/*
* Append to_append to path with a slash in between.
*/
int append_path(char *path, char *to_append, int max_len)
{
int current_length = STRLEN(path);
int to_append_length = STRLEN(to_append);
/* Do not append empty strings. */
if (0 == to_append_length)
return OK;
/* Do not append a dot. */
if (STRCMP(to_append, ".") == 0)
return OK;
/* Glue both paths with a slash. */
if (current_length > 0 && path[current_length-1] != '/') {
current_length += 1; /* Count the trailing slash. */
if (current_length > max_len)
return FAIL;
STRCAT(path, "/");
}
/* +1 for the NUL at the end. */
if (current_length + to_append_length +1 > max_len) {
return FAIL;
}
STRCAT(path, to_append);
return OK;
}
/* /*
* Get absolute file name into "buf[len]". * Get absolute file name into "buf[len]".
* *
* parameter force: Also expand when the given path in fname is already
* absolute.
*
* return FAIL for failure, OK for success * return FAIL for failure, OK for success
*/ */
int mch_FullName( int mch_full_name(char_u *fname, char_u *buf, int len, int force)
char_u *fname,
char_u *buf,
int len,
int force /* also expand when already absolute path */
)
{ {
int l; char_u *p;
char_u olddir[MAXPATHL]; *buf = NUL;
char_u *p;
int retval = OK;
char relative_directory[len];
char *end_of_path = (char *) fname;
/* expand it if forced or not an absolute path */ /* expand it if forced or not an absolute path */
if (force || !mch_isFullName(fname)) { if (force || !mch_is_full_name(fname)) {
/*
* If the file name has a path, change to that directory for a moment,
* and then do the getwd() (and get back to where we were).
* This will get the correct path name with "../" things.
*/
if ((p = vim_strrchr(fname, '/')) != NULL) { if ((p = vim_strrchr(fname, '/')) != NULL) {
/* Only change directory when we are sure we can return to where STRNCPY(relative_directory, fname, p-fname);
* we are now. After doing "su" chdir(".") might not work. */ relative_directory[p-fname] = NUL;
if ((mch_dirname(olddir, MAXPATHL) == FAIL end_of_path = (char *) (p + 1);
|| mch_chdir((char *)olddir) != 0)) { } else {
p = NULL; /* can't get current dir: don't chdir */ relative_directory[0] = NUL;
retval = FAIL; end_of_path = (char *) fname;
} else {
/* The directory is copied into buf[], to be able to remove
* the file name without changing it (could be a string in
* read-only memory) */
if (p - fname >= len)
retval = FAIL;
else {
vim_strncpy(buf, fname, p - fname);
if (mch_chdir((char *)buf))
retval = FAIL;
else
fname = p + 1;
*buf = NUL;
}
}
}
if (mch_dirname(buf, len) == FAIL) {
retval = FAIL;
*buf = NUL;
}
if (p != NULL) {
l = mch_chdir((char *)olddir);
if (l != 0)
EMSG(_(e_prev_dir));
} }
l = STRLEN(buf); if (FAIL == mch_full_dir_name(relative_directory, (char *) buf, len)) {
if (l >= len - 1) return FAIL;
retval = FAIL; /* no space for trailing "/" */ }
else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
&& STRCMP(fname, ".") != 0)
STRCAT(buf, "/");
} }
return append_path((char *) buf, (char *) end_of_path, len);
/* Catch file names which are too long. */
if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
return FAIL;
/* Do not append ".", "/dir/." is equal to "/dir". */
if (STRCMP(fname, ".") != 0)
STRCAT(buf, fname);
return OK;
} }
/* /*
* Return TRUE if "fname" does not depend on the current directory. * Return TRUE if "fname" does not depend on the current directory.
*/ */
int mch_isFullName(char_u *fname) int mch_is_full_name(char_u *fname)
{ {
return *fname == '/' || *fname == '~'; return *fname == '/' || *fname == '~';
} }

View File

@@ -6,7 +6,7 @@
long_u mch_total_mem(int special); long_u mch_total_mem(int special);
int mch_chdir(char *path); int mch_chdir(char *path);
int mch_dirname(char_u *buf, int len); int mch_dirname(char_u *buf, int len);
int mch_FullName (char_u *fname, char_u *buf, int len, int force); int mch_full_name (char_u *fname, char_u *buf, int len, int force);
int mch_isFullName (char_u *fname); int mch_is_full_name (char_u *fname);
#endif #endif

View File

@@ -1364,7 +1364,7 @@ int mch_can_exe(char_u *name)
int retval; int retval;
/* If it's an absolute or relative path don't need to use $PATH. */ /* If it's an absolute or relative path don't need to use $PATH. */
if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/' if (mch_is_full_name(name) || (name[0] == '.' && (name[1] == '/'
|| (name[1] == '.' && || (name[1] == '.' &&
name[2] == '/')))) name[2] == '/'))))
return executable_file(name); return executable_file(name);

View File

@@ -4187,7 +4187,7 @@ static void syn_cmd_include(exarg_T *eap, int syncing)
*/ */
eap->argt |= (XFILE | NOSPC); eap->argt |= (XFILE | NOSPC);
separate_nextcmd(eap); separate_nextcmd(eap);
if (*eap->arg == '<' || *eap->arg == '$' || mch_isFullName(eap->arg)) { if (*eap->arg == '<' || *eap->arg == '$' || mch_is_full_name(eap->arg)) {
/* For an absolute path, "$VIM/..." or "<sfile>.." we ":source" the /* For an absolute path, "$VIM/..." or "<sfile>.." we ":source" the
* file. Need to expand the file name first. In other cases * file. Need to expand the file name first. In other cases
* ":runtime!" is used. */ * ":runtime!" is used. */

View File

@@ -5065,7 +5065,7 @@ int path_with_url(char_u *fname)
*/ */
int vim_isAbsName(char_u *name) int vim_isAbsName(char_u *name)
{ {
return path_with_url(name) != 0 || mch_isFullName(name); return path_with_url(name) != 0 || mch_is_full_name(name);
} }
/* /*
@@ -5090,7 +5090,7 @@ vim_FullName (
url = path_with_url(fname); url = path_with_url(fname);
if (!url) if (!url)
retval = mch_FullName(fname, buf, len, force); retval = mch_full_name(fname, buf, len, force);
if (url || retval == FAIL) { if (url || retval == FAIL) {
/* something failed; use the file name (truncate when too long) */ /* something failed; use the file name (truncate when too long) */
vim_strncpy(buf, fname, len - 1); vim_strncpy(buf, fname, len - 1);

View File

@@ -5,87 +5,195 @@ fs = cimport './src/fs.h'
cstr = ffi.typeof 'char[?]' cstr = ffi.typeof 'char[?]'
describe 'fs function', -> describe 'fs function', ->
export OK = 1
export FAIL = 0
describe 'mch_dirname', -> describe 'mch_dirname', ->
ffi.cdef 'int mch_dirname(char *buf, int len);' ffi.cdef 'int mch_dirname(char *buf, int len);'
mch_dirname = (buf, len) -> mch_dirname = (buf, len) ->
fs.mch_dirname buf, len fs.mch_dirname buf, len
OK = 1
FAIL = 0
before_each -> before_each ->
export len = string.len(lfs.currentdir()) + 1 export len = (string.len lfs.currentdir!) + 1
export buf = cstr len, ''
it 'returns OK and writes current directory into the buffer if it is buffer it 'returns OK and writes current directory into the buffer if it is large
is large enough', -> enough', ->
buf = ffi.new 'char[?]', len
eq OK, (mch_dirname buf, len) eq OK, (mch_dirname buf, len)
eq lfs.currentdir(), ffi.string(buf) eq lfs.currentdir!, (ffi.string buf)
-- What kind of other failing cases are possible? -- What kind of other failing cases are possible?
it 'returns FAIL if the buffer is too small', -> it 'returns FAIL if the buffer is too small', ->
buf = ffi.new 'char[?]', 0 buf = cstr (len-1), ''
eq FAIL, (mch_dirname buf, 0) eq FAIL, (mch_dirname buf, (len-1))
describe 'mch_FullName', -> describe 'mch_full_dir_name', ->
ffi.cdef 'int mch_FullName(char *fname, char *buf, int len, int force);' ffi.cdef 'int mch_full_dir_name(char *directory, char *buffer, int len);'
mch_FullName = (filename, buffer, length, force) -> mch_full_dir_name = (directory, buffer, len) ->
filename = cstr(string.len(filename) + 1, filename) directory = cstr (string.len directory), directory
fs.mch_FullName(filename, buffer, length, force) fs.mch_full_dir_name(directory, buffer, len)
OK = 1
FAIL = 0
before_each -> before_each ->
-- Create empty string buffer which will contain the resulting path -- Create empty string buffer which will contain the resulting path.
export len = string.len(lfs.currentdir()) + 11 export len = (string.len lfs.currentdir!) + 22
export buffer = cstr(len, '') export buffer = cstr len, ''
it 'failes if given filename contains non-existing directory', -> it 'returns the absolute directory name of a given relative one', ->
result = mch_FullName('nonexistingdir/test.file', buffer, len, 1) result = mch_full_dir_name '..', buffer, len
eq OK, result
old_dir = lfs.currentdir!
lfs.chdir '..'
expected = lfs.currentdir!
lfs.chdir old_dir
eq expected, (ffi.string buffer)
it 'returns the current directory name if the given string is empty', ->
eq OK, (mch_full_dir_name '', buffer, len)
eq lfs.currentdir!, (ffi.string buffer)
it 'fails if the given directory does not exist', ->
eq FAIL, mch_full_dir_name('does_not_exist', buffer, len)
it 'works with a normal relative dir', ->
lfs.mkdir('empty-test-directory')
result = mch_full_dir_name('empty-test-directory', buffer, len)
lfs.rmdir('empty-test-directory')
eq lfs.currentdir! .. '/empty-test-directory', ffi.string(buffer)
eq OK, result
describe 'mch_full_name', ->
ffi.cdef 'int mch_full_name(char *fname, char *buf, int len, int force);'
mch_full_name = (filename, buffer, length, force) ->
filename = cstr (string.len filename) + 1, filename
fs.mch_full_name filename, buffer, length, force
before_each ->
-- Create empty string buffer which will contain the resulting path.
export len = (string.len lfs.currentdir!) + 33
export buffer = cstr len, ''
-- Create a directory and an empty file inside in order to know some
-- existing relative path.
lfs.mkdir('empty-test-directory')
lfs.touch('empty-test-directory/empty.file')
after_each ->
lfs.rmdir('empty-test-directory')
it 'fails if given filename contains non-existing directory', ->
force_expansion = 1
result = mch_full_name 'non_existing_dir/test.file', buffer, len, force_expansion
eq FAIL, result eq FAIL, result
it 'concatenates given filename if it does not contain a slash', -> it 'concatenates given filename if it does not contain a slash', ->
result = mch_FullName('test.file', buffer, len, 1) force_expansion = 1
result = mch_full_name 'test.file', buffer, len, force_expansion
expected = lfs.currentdir! .. '/test.file'
eq expected, (ffi.string buffer)
eq OK, result eq OK, result
expected = lfs.currentdir() .. '/test.file'
eq expected, ffi.string(buffer)
it 'concatenates given filename if it is a directory but does not contain a it 'concatenates given filename if it is a directory but does not contain a
slash', -> slash', ->
result = mch_FullName('..', buffer, len, 1) force_expansion = 1
result = mch_full_name '..', buffer, len, force_expansion
expected = lfs.currentdir! .. '/..'
eq expected, (ffi.string buffer)
eq OK, result eq OK, result
expected = lfs.currentdir() .. '/..'
eq expected, ffi.string(buffer)
-- Is it possible for every developer to enter '..' directory while running -- Is it possible for every developer to enter '..' directory while running
-- the unit tests? Which other directory would be better? -- the unit tests? Which other directory would be better?
it 'enters given directory if possible and if path contains a slash', -> it 'enters given directory (instead of just concatenating the strings) if
result = mch_FullName('../test.file', buffer, 200, 1) possible and if path contains a slash', ->
force_expansion = 1
result = mch_full_name '../test.file', buffer, len, force_expansion
old_dir = lfs.currentdir!
lfs.chdir '..'
expected = lfs.currentdir! .. '/test.file'
lfs.chdir old_dir
eq expected, (ffi.string buffer)
eq OK, result eq OK, result
old_dir = lfs.currentdir()
lfs.chdir('..')
expected = lfs.currentdir() .. '/test.file'
lfs.chdir(old_dir)
eq expected, ffi.string(buffer)
describe 'mch_isFullName', -> it 'just copies the path if it is already absolute and force=0', ->
ffi.cdef 'int mch_isFullName(char *fname);' force_expansion = 0
absolute_path = '/absolute/path'
result = mch_full_name absolute_path, buffer, len, force_expansion
eq absolute_path, (ffi.string buffer)
eq OK, result
mch_isFullName = (filename) -> it 'fails when the path is relative to HOME', ->
filename = cstr(string.len(filename) + 1, filename) force_expansion = 1
fs.mch_isFullName(filename) absolute_path = '~/home.file'
result = mch_full_name absolute_path, buffer, len, force_expansion
eq FAIL, result
TRUE = 1 it 'works with some "normal" relative path with directories', ->
FALSE = 0 force_expansion = 1
result = mch_full_name 'empty-test-directory/empty.file', buffer, len, force_expansion
eq OK, result
eq lfs.currentdir! .. '/empty-test-directory/empty.file', (ffi.string buffer)
it 'does not modify the given filename', ->
force_expansion = 1
filename = cstr 100, 'empty-test-directory/empty.file'
result = fs.mch_full_name filename, buffer, len, force_expansion
eq lfs.currentdir! .. '/empty-test-directory/empty.file', (ffi.string buffer)
eq 'empty-test-directory/empty.file', (ffi.string filename)
eq OK, result
describe 'append_path', ->
ffi.cdef 'int append_path(char *path, char *to_append, int max_len);'
it 'joins given paths with a slash', ->
path = cstr 100, 'path1'
to_append = cstr 6, 'path2'
eq OK, (fs.append_path path, to_append, 100)
eq "path1/path2", (ffi.string path)
it 'joins given paths without adding an unnecessary slash', ->
path = cstr 100, 'path1/'
to_append = cstr 6, 'path2'
eq OK, fs.append_path path, to_append, 100
eq "path1/path2", (ffi.string path)
it 'fails if there is not enough space left for to_append', ->
path = cstr 11, 'path1/'
to_append = cstr 6, 'path2'
eq FAIL, (fs.append_path path, to_append, 11)
it 'does not append a slash if to_append is empty', ->
path = cstr 6, 'path1'
to_append = cstr 1, ''
eq OK, (fs.append_path path, to_append, 6)
eq 'path1', (ffi.string path)
it 'does not append unnecessary dots', ->
path = cstr 6, 'path1'
to_append = cstr 2, '.'
eq OK, (fs.append_path path, to_append, 6)
eq 'path1', (ffi.string path)
it 'copies to_append to path, if path is empty', ->
path = cstr 7, ''
to_append = cstr 7, '/path2'
eq OK, (fs.append_path path, to_append, 7)
eq '/path2', (ffi.string path)
describe 'mch_is_full_name', ->
ffi.cdef 'int mch_is_full_name(char *fname);'
mch_is_full_name = (filename) ->
filename = cstr (string.len filename) + 1, filename
fs.mch_is_full_name filename
it 'returns true if filename starts with a slash', -> it 'returns true if filename starts with a slash', ->
eq TRUE, mch_isFullName('/some/directory/') eq OK, mch_is_full_name '/some/directory/'
it 'returns true if filename starts with a tilde', -> it 'returns true if filename starts with a tilde', ->
eq TRUE, mch_isFullName('~/in/my/home~/directory') eq OK, mch_is_full_name '~/in/my/home~/directory'
it 'returns false if filename starts not with slash nor tilde', -> it 'returns false if filename starts not with slash nor tilde', ->
eq FALSE, mch_isFullName('not/in/my/home~/directory') eq FAIL, mch_is_full_name 'not/in/my/home~/directory'