📄 filesystem_traits.hpp
字号:
return (0 < len) && is_path_name_separator(dir[len - 1]);
}
static bool_type is_dots(char_type const* dir)
{
UNIXSTL_ASSERT(NULL != dir);
return dir[0] == '.' &&
( dir[1] == '\0' ||
( dir[1] == '.' &&
dir[2] == '\0'));
}
static bool_type is_path_rooted(char_type const* path)
{
UNIXSTL_ASSERT(NULL != path);
#ifdef _WIN32
// It might be a UNC path. This is handled by the second test below, but
// this is a bit clearer, and since this is a debug kind of thing, we're
// not worried about the cost
if( '\\' == path[0] &&
'\\' == path[1])
{
return true;
}
// If it's really on Windows, then we need to skip the drive, if present
if( isalpha(path[0]) &&
':' == path[1])
{
path += 2;
}
// If it's really on Windows, then we need to account for the fact that
// the slash might be backwards, but that's taken care of for us by
// is_path_name_separator()
#endif /* _WIN32 */
return is_path_name_separator(*path);
}
static bool_type is_path_absolute(char_type const* path)
{
UNIXSTL_ASSERT(NULL != path);
#ifdef _WIN32
// If it's really on Windows, then it can only be absolute if ...
//
// ... it's a UNC path, or ...
if(is_path_UNC(path))
{
return true;
}
// ... it's got drive + root slash, or
if( isalpha(path[0]) &&
':' == path[1] &&
is_path_name_separator(path[2]))
{
return true;
}
// ... it's got root forward slash
if('/' == path[0])
{
return true;
}
return false;
#else /* ? _WIN32 */
return is_path_rooted(path);
#endif /* _WIN32 */
}
static bool_type is_path_UNC(char_type const* path)
{
UNIXSTL_ASSERT(NULL != path);
#ifdef _WIN32
return ('\\' == path[0] && '\\' == path[1]);
#else /* ? _WIN32 */
STLSOFT_SUPPRESS_UNUSED(path);
return false;
#endif /* _WIN32 */
}
private:
static bool_type is_root_drive_(char_type const* path)
{
#ifdef _WIN32
if( isalpha(path[0]) &&
':' == path[1] &&
is_path_name_separator(path[2]) &&
'\0' == path[3])
{
return true;
}
#else /* ? _WIN32 */
STLSOFT_SUPPRESS_UNUSED(path);
#endif /* _WIN32 */
return false;
}
static bool_type is_root_UNC_(char_type const* path)
{
#ifdef _WIN32
if(is_path_UNC(path))
{
char_type const* sep = str_pbrk(path + 2, "\\/");
if( NULL == sep ||
'\0' == sep[1])
{
return true;
}
}
#else /* ? _WIN32 */
STLSOFT_SUPPRESS_UNUSED(path);
#endif /* _WIN32 */
return false;
}
static bool_type is_root_directory_(char_type const* path)
{
if( is_path_name_separator(path[0]) &&
'\0' == path[1])
{
return true;
}
return false;
}
public:
static bool_type is_root_designator(char_type const* path)
{
UNIXSTL_ASSERT(NULL != path);
return is_root_directory_(path) || is_root_drive_(path) || is_root_UNC_(path);
}
static bool_type is_path_name_separator(char_type ch)
{
#ifdef _WIN32
return '\\' == ch || '/' == ch;
#else /* ? _WIN32 */
return '/' == ch;
#endif /* _WIN32 */
}
static char_type path_separator()
{
return ':';
}
static char_type path_name_separator()
{
return '/';
}
static char_type const* pattern_all()
{
return "*";
}
static size_type path_max()
{
#if defined(PATH_MAX)
return 1 + PATH_MAX;
#else /* ? PATH_MAX */
return 1 + pathconf("/", _PC_PATH_MAX);
#endif /* PATH_MAX */
}
private:
static size_type get_full_path_name_impl2(char_type const* fileName, us_size_t len, char_type* buffer, size_type cchBuffer)
{
// The next thing to so is determine whether the path is absolute, in
// which case we'll just copy it into the buffer
if(is_path_rooted(fileName))
{
// Given path is absolute, so simply copy into buffer
if(NULL == buffer)
{
len = len;
}
else if(cchBuffer < len)
{
str_n_copy(&buffer[0], fileName, cchBuffer);
len = cchBuffer;
}
else
{
// Given buffer is large enough, so copy
str_copy(buffer, fileName);
}
}
else
{
// Given path is relative, so get the current directory, and then concatenate
buffer_type_ directory(1 + path_max());
if(0 == directory.size())
{
set_last_error(ENOMEM);
return 0;
}
else if(NULL != buffer &&
0 == cchBuffer)
{
return 0;
}
else
{
size_type lenDir = get_current_directory(&directory[0], directory.size());
if(0 == lenDir)
{
// The call failed, so indicate that to caller
len = 0;
}
else
{
if( 1 == len &&
'.' == fileName[0])
{
if(NULL == buffer)
{
len = lenDir;
}
else
{
if(cchBuffer < lenDir)
{
str_n_copy(&buffer[0], directory.data(), cchBuffer);
len = cchBuffer;
}
else
{
// Given buffer is large enough, so copy
str_copy(buffer, directory.data());
len = lenDir;
}
}
}
else
{
if(!has_dir_end(&directory[0] + (lenDir - 1)))
{
++lenDir;
}
ensure_dir_end(&directory[0]);
len += lenDir;
if(NULL != buffer)
{
str_n_copy(&buffer[0], directory.data(), cchBuffer);
if(cchBuffer > lenDir)
{
str_n_copy(&buffer[0] + lenDir, fileName, cchBuffer - lenDir);
}
if(cchBuffer < len)
{
len = cchBuffer;
}
}
}
}
}
}
return len;
}
static size_type get_full_path_name_impl(char_type const* fileName, us_size_t len, char_type* buffer, size_type cchBuffer)
{
UNIXSTL_ASSERT(len > 0);
if('\0' != fileName[len])
{
buffer_type_ fileName_(1 + (len - 1));
// May be being compiled absent exception support, so need to check the
// file path buffers. (This _could_ be done with a compile-time #ifdef,
// but it's best not, since some translators support exceptions but yet
// don't throw on mem exhaustion, and in any case a user could change
// ::new)
if(0 == fileName_.size())
{
set_last_error(ENOMEM);
return 0;
}
else
{
fileName_[len] = '\0';
return get_full_path_name_impl2(str_n_copy(&fileName_[0], fileName, len)
, len
, buffer
, cchBuffer);
}
}
else
{
return get_full_path_name_impl2(fileName, len, buffer, cchBuffer);
}
}
public:
static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type **ppFile)
{
UNIXSTL_ASSERT(NULL != ppFile);
size_type r = get_full_path_name(fileName, buffer, cchBuffer);
*ppFile = NULL;
if( NULL != buffer &&
0 != r &&
r <= cchBuffer)
{
size_type cchRequired = get_full_path_name(fileName, static_cast<char_type*>(NULL), 0);
if(r == cchRequired)
{
// Now search for the file separator
char_type *pFile = str_rchr(buffer, path_name_separator());
#if defined(_WIN32)
char_type *pFile2 = str_rchr(buffer, '\\');
if(NULL == pFile)
{
pFile = pFile2;
}
else if(NULL != pFile2)
{
if(pFile2 > pFile)
{
pFile = pFile2;
}
}
#endif /* _WIN32 */
if(NULL != (*ppFile = pFile))
{
(*ppFile)++;
}
}
}
return r;
}
static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
{
UNIXSTL_ASSERT(NULL != fileName);
UNIXSTL_ASSERT(0 == cchBuffer || NULL != buffer);
if('\0' == *fileName)
{
static const char s_dot[2] = { '.', '\0' };
fileName = s_dot;
}
#if 1
// Can't call realpath(), since that requires that the file exists
return get_full_path_name_impl(fileName, str_len(fileName), buffer, cchBuffer);
#else /* ? 0 */
buffer_type_ directory(1 + path_max());
if( 0 == directory.size() ||
NULL == ::realpath(fileName, &directory[0]))
{
return 0;
}
else
{
const size_type len = str_len(directory.data());
if(NULL == buffer)
{
return len;
}
else if(0 == cchBuffer)
{
return 0;
}
else
{
if(len < cchBuffer)
{
str_copy(&buffer[0], directory.data());
return len;
}
else
{
str_n_copy(&buffer[0], directory.data(), cchBuffer);
return cchBuffer;
}
}
}
#endif /* 0 */
}
static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
{
return get_full_path_name(fileName, buffer, cchBuffer);
}
static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
{
return get_full_path_name(fileName, cchBuffer, buffer);
}
// File-system enumeration
static DIR *open_dir(char_type const* dir)
{
return ::opendir(dir);
}
static struct dirent const* read_dir(DIR *h)
{
return ::readdir(h);
}
static void close_dir(DIR *h)
{
::closedir(h);
}
// File-system state
static bool_type set_current_directory(char_type const* dir)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -