Fix handling of an empty filename at end of a path
The C++17 std::filesystem::path grammar allows an empty filename as the last component (to signify a trailing slash). The existing code does not handle this consistently, sometimes an empty filename has type _Multi and sometimes it has type _Filename. This can result in a non-empty iterator range for an empty filename component. This change ensures that empty paths always have type _Filename and will yield an empty iterator range. * include/bits/fs_path.h (path::_M_type): Change default member initializer to _Filename. (path::begin): Create past-the-end iterator for empty path. * src/filesystem/std-path.cc (path::remove_filename()): Remove debugging check. (path::has_relative_path()): Return false for empty filenames. (path::_M_split_cmpts): Set _M_type to _Filename for empty paths. Fix offset of empty final component. * testsuite/27_io/filesystem/path/itr/components.cc: New. * testsuite/27_io/filesystem/path/itr/traversal.cc: Add new inputs. From-SVN: r260616
This commit is contained in:
parent
7aa1325013
commit
cf290ea325
|
@ -1,3 +1,16 @@
|
||||||
|
2018-05-23 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
|
* include/bits/fs_path.h (path::_M_type): Change default member
|
||||||
|
initializer to _Filename.
|
||||||
|
(path::begin): Create past-the-end iterator for empty path.
|
||||||
|
* src/filesystem/std-path.cc (path::remove_filename()): Remove
|
||||||
|
debugging check.
|
||||||
|
(path::has_relative_path()): Return false for empty filenames.
|
||||||
|
(path::_M_split_cmpts): Set _M_type to _Filename for empty paths.
|
||||||
|
Fix offset of empty final component.
|
||||||
|
* testsuite/27_io/filesystem/path/itr/components.cc: New.
|
||||||
|
* testsuite/27_io/filesystem/path/itr/traversal.cc: Add new inputs.
|
||||||
|
|
||||||
2018-05-21 Jonathan Wakely <jwakely@redhat.com>
|
2018-05-21 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
Add support for opening file streams from wide character strings.
|
Add support for opening file streams from wide character strings.
|
||||||
|
|
|
@ -497,7 +497,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
|
||||||
struct _Cmpt;
|
struct _Cmpt;
|
||||||
using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
|
using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
|
||||||
_List _M_cmpts; // empty unless _M_type == _Type::_Multi
|
_List _M_cmpts; // empty unless _M_type == _Type::_Multi
|
||||||
_Type _M_type = _Type::_Multi;
|
_Type _M_type = _Type::_Filename;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -1076,7 +1076,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
|
||||||
{
|
{
|
||||||
if (_M_type == _Type::_Multi)
|
if (_M_type == _Type::_Multi)
|
||||||
return iterator(this, _M_cmpts.begin());
|
return iterator(this, _M_cmpts.begin());
|
||||||
return iterator(this, false);
|
return iterator(this, empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline path::iterator
|
inline path::iterator
|
||||||
|
|
|
@ -63,8 +63,6 @@ path::remove_filename()
|
||||||
}
|
}
|
||||||
else if (_M_type == _Type::_Filename)
|
else if (_M_type == _Type::_Filename)
|
||||||
clear();
|
clear();
|
||||||
if (!empty() && _M_pathname.back() != '/')
|
|
||||||
throw 1;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +290,7 @@ path::has_root_path() const
|
||||||
bool
|
bool
|
||||||
path::has_relative_path() const
|
path::has_relative_path() const
|
||||||
{
|
{
|
||||||
if (_M_type == _Type::_Filename)
|
if (_M_type == _Type::_Filename && !_M_pathname.empty())
|
||||||
return true;
|
return true;
|
||||||
if (!_M_cmpts.empty())
|
if (!_M_cmpts.empty())
|
||||||
{
|
{
|
||||||
|
@ -301,7 +299,7 @@ path::has_relative_path() const
|
||||||
++__it;
|
++__it;
|
||||||
if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
|
if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
|
||||||
++__it;
|
++__it;
|
||||||
if (__it != _M_cmpts.end())
|
if (__it != _M_cmpts.end() && !__it->_M_pathname.empty())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -514,11 +512,13 @@ path::_M_find_extension() const
|
||||||
void
|
void
|
||||||
path::_M_split_cmpts()
|
path::_M_split_cmpts()
|
||||||
{
|
{
|
||||||
_M_type = _Type::_Multi;
|
|
||||||
_M_cmpts.clear();
|
_M_cmpts.clear();
|
||||||
|
|
||||||
if (_M_pathname.empty())
|
if (_M_pathname.empty())
|
||||||
return;
|
{
|
||||||
|
_M_type = _Type::_Filename;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_M_type = _Type::_Multi;
|
||||||
|
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
const size_t len = _M_pathname.size();
|
const size_t len = _M_pathname.size();
|
||||||
|
@ -593,8 +593,7 @@ path::_M_split_cmpts()
|
||||||
// An empty element, if trailing non-root directory-separator present.
|
// An empty element, if trailing non-root directory-separator present.
|
||||||
if (_M_cmpts.back()._M_type == _Type::_Filename)
|
if (_M_cmpts.back()._M_type == _Type::_Filename)
|
||||||
{
|
{
|
||||||
const auto& last = _M_cmpts.back();
|
pos = _M_pathname.size();
|
||||||
pos = last._M_pos + last._M_pathname.size();
|
|
||||||
_M_cmpts.emplace_back(string_type(), _Type::_Filename, pos);
|
_M_cmpts.emplace_back(string_type(), _Type::_Filename, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright (C) 2018 Free Software Foundation, Inc.
|
||||||
|
//
|
||||||
|
// This file is part of the GNU ISO C++ Library. This library is free
|
||||||
|
// software; you can redistribute it and/or modify it under the
|
||||||
|
// terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation; either version 3, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this library; see the file COPYING3. If not see
|
||||||
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// { dg-options "-std=gnu++17 -lstdc++fs" }
|
||||||
|
// { dg-do run { target c++17 } }
|
||||||
|
// { dg-require-filesystem-ts "" }
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <iterator>
|
||||||
|
#include <testsuite_hooks.h>
|
||||||
|
#include <testsuite_fs.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
test01()
|
||||||
|
{
|
||||||
|
for (std::filesystem::path p : __gnu_test::test_paths)
|
||||||
|
{
|
||||||
|
if (p.empty())
|
||||||
|
VERIFY(std::distance(p.begin(), p.end()) == 0);
|
||||||
|
else
|
||||||
|
VERIFY(std::distance(p.begin(), p.end()) != 0);
|
||||||
|
|
||||||
|
for (const std::filesystem::path& cmpt : p)
|
||||||
|
{
|
||||||
|
if (cmpt.empty())
|
||||||
|
VERIFY(std::distance(cmpt.begin(), cmpt.end()) == 0);
|
||||||
|
else
|
||||||
|
VERIFY(std::distance(cmpt.begin(), cmpt.end()) == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
test01();
|
||||||
|
}
|
|
@ -104,7 +104,7 @@ test02()
|
||||||
void
|
void
|
||||||
test03()
|
test03()
|
||||||
{
|
{
|
||||||
path paths[] = { "single", "multiple/elements" };
|
path paths[] = { "single", "multiple/elements", "trailing/slash/", "/." };
|
||||||
for (const path& p : paths)
|
for (const path& p : paths)
|
||||||
for (auto iter = p.begin(); iter != p.end(); ++iter)
|
for (auto iter = p.begin(); iter != p.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue