public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Provide filesystem::path overloads for file streams (LWG 2676, partial)
@ 2017-10-27 12:44 Jonathan Wakely
  2017-10-27 13:04 ` Jonathan Wakely
  0 siblings, 1 reply; 2+ messages in thread
From: Jonathan Wakely @ 2017-10-27 12:44 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1915 bytes --]

This implements part of LWG 2676. I haven't added the new members
taking wide character strings, because they're only needed on Windows,
where the Filesystem library doesn't work yet. I'll send a follow-up
patch about those overloads.

I've implemented these new functions as templates, which means they
work with both std::filesystem::path and
std::experimental::filesystem::path. There's another benefit, which is
that we don't need to include <filesystem> in <fstream>, and we don't
need to export new symbols from libstdc++.so for these functions
(we have explicit instantation definitions in the library).

This isn't entirely conforming, because a type that is convertible to
filesystem::path will not match these new function templates. We can
revisit it once the <filesystem> symbols are added to libstdc++.so but
this should be OK for now.

	* include/std/fstream (basic_filebuf::_If_path): New SFINAE helper.
	(basic_filebuf::open<Path>(const Path&, const ios_base::openmode&))
	(basic_ifstream<Path>(const Path&, const ios_base::openmode&))
	(basic_ifstream::open<Path>(const Path&, const ios_base::openmode&))
	(basic_ofstream<Path>(const Path&, const ios_base::openmode&))
	(basic_ofstream::open<Path>(const Path&, const ios_base::openmode&))
	(basic_fstream<Path>(const Path&, const ios_base::openmode&))
	(basic_fstream::open<Path>(const Path&, const ios_base::openmode&)):
	New constructors and member functions.
	* testsuite/27_io/basic_filebuf/open/char/path.cc: New test.
	* testsuite/27_io/basic_fstream/cons/char/path.cc: New test.
	* testsuite/27_io/basic_fstream/open/char/path.cc: New test.
	* testsuite/27_io/basic_ifstream/cons/char/path.cc: New test.
	* testsuite/27_io/basic_ifstream/open/char/path.cc: New test.
	* testsuite/27_io/basic_ofstream/cons/char/path.cc: New test.
	* testsuite/27_io/basic_ofstream/open/char/path.cc: New test.

Tested powerpc64le-linux, committed to trunk.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 18676 bytes --]

commit 67bafe2c8409f91c2de758e37830b2d57dedbf02
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Oct 24 19:08:15 2017 +0100

    Provide filesystem::path overloads for file streams (LWG 2676, partial)
    
            * include/std/fstream (basic_filebuf::_If_path): New SFINAE helper.
            (basic_filebuf::open<Path>(const Path&, const ios_base::openmode&))
            (basic_ifstream<Path>(const Path&, const ios_base::openmode&))
            (basic_ifstream::open<Path>(const Path&, const ios_base::openmode&))
            (basic_ofstream<Path>(const Path&, const ios_base::openmode&))
            (basic_ofstream::open<Path>(const Path&, const ios_base::openmode&))
            (basic_fstream<Path>(const Path&, const ios_base::openmode&))
            (basic_fstream::open<Path>(const Path&, const ios_base::openmode&)):
            New constructors and member functions.
            * testsuite/27_io/basic_filebuf/open/char/path.cc: New test.
            * testsuite/27_io/basic_fstream/cons/char/path.cc: New test.
            * testsuite/27_io/basic_fstream/open/char/path.cc: New test.
            * testsuite/27_io/basic_ifstream/cons/char/path.cc: New test.
            * testsuite/27_io/basic_ifstream/open/char/path.cc: New test.
            * testsuite/27_io/basic_ofstream/cons/char/path.cc: New test.
            * testsuite/27_io/basic_ofstream/open/char/path.cc: New test.

diff --git a/libstdc++-v3/include/std/fstream b/libstdc++-v3/include/std/fstream
index 52830945fe2..3205f81fb47 100644
--- a/libstdc++-v3/include/std/fstream
+++ b/libstdc++-v3/include/std/fstream
@@ -216,6 +216,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  }
       }
 
+#if __cplusplus >= 201703L
+      template<typename _Path, typename _Result = _Path, typename _Path2
+	       = decltype(std::declval<_Path&>().make_preferred().native())>
+	using _If_path = enable_if_t<is_same_v<_Path, _Path2>, _Result>;
+#endif // C++17
+
     public:
       // Constructors/destructor:
       /**
@@ -306,7 +312,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __filebuf_type*
       open(const std::string& __s, ios_base::openmode __mode)
       { return open(__s.c_str(), __mode); }
-#endif
+
+#if __cplusplus >= 201703L
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file, as a filesystem::path.
+       *  @param  __mode  The open mode flags.
+       *  @return  @c this on success, NULL on failure
+       */
+      template<typename _Path>
+	_If_path<_Path, __filebuf_type*>
+	open(const _Path& __s, ios_base::openmode __mode)
+	{ return open(__s.c_str(), __mode); }
+#endif // C++17
+#endif // C++11
 
       /**
        *  @brief  Closes the currently associated file.
@@ -516,13 +535,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	this->open(__s, __mode);
       }
 
+#if __cplusplus >= 201703L
+      /**
+       *  @param  Create an input file stream.
+       *  @param  __s  filesystem::path specifying the filename.
+       *  @param  __mode  Open file in specified mode (see std::ios_base).
+       *
+       *  @c ios_base::in is automatically included in @a __mode.
+       */
+      template<typename _Path, typename = _Require<
+	  is_constructible<__filebuf_type, const _Path&, ios_base::openmode>>>
+	basic_ifstream(const _Path& __s,
+		       ios_base::openmode __mode = ios_base::in)
+	: basic_ifstream(__s.c_str(), __mode)
+	{ }
+#endif // C++17
+
       basic_ifstream(const basic_ifstream&) = delete;
 
       basic_ifstream(basic_ifstream&& __rhs)
       : __istream_type(std::move(__rhs)),
       _M_filebuf(std::move(__rhs._M_filebuf))
       { __istream_type::set_rdbuf(&_M_filebuf); }
-#endif
+#endif // C++11
 
       /**
        *  @brief  The destructor does nothing.
@@ -621,7 +656,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  // 409. Closing an fstream should clear error state
 	  this->clear();
       }
-#endif
+
+#if __cplusplus >= 201703L
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file, as a filesystem::path.
+       *  @param  __mode  The open mode flags.
+       *
+       *  Calls @c std::basic_filebuf::open(__s,__mode|in).  If that function
+       *  fails, @c failbit is set in the stream's error state.
+       */
+      template<typename _Path>
+	auto
+	open(const _Path& __s, ios_base::openmode __mode = ios_base::in)
+	-> decltype(_M_filebuf.open(__s, __mode))
+	{ open(__s.c_str(), __mode); }
+#endif // C++17
+#endif // C++11
 
       /**
        *  @brief  Close the file.
@@ -720,6 +771,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	this->open(__s, __mode);
       }
 
+#if __cplusplus >= 201703L
+      /**
+       *  @param  Create an output file stream.
+       *  @param  __s  filesystem::path specifying the filename.
+       *  @param  __mode  Open file in specified mode (see std::ios_base).
+       *
+       *  @c ios_base::out | @c ios_base::trunc is automatically included in
+       *  @a __mode.
+       */
+      template<typename _Path, typename = _Require<
+	  is_constructible<__filebuf_type, const _Path&, ios_base::openmode>>>
+	basic_ofstream(const _Path& __s, ios_base::openmode __mode
+		       = ios_base::out|ios_base::trunc)
+	: basic_ofstream(__s.c_str(), __mode)
+	{ }
+#endif // C++17
+
       basic_ofstream(const basic_ofstream&) = delete;
 
       basic_ofstream(basic_ofstream&& __rhs)
@@ -827,7 +895,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  // 409. Closing an fstream should clear error state
 	  this->clear();
       }
-#endif
+
+#if __cplusplus >= 201703L
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file, as a filesystem::path.
+       *  @param  __mode  The open mode flags.
+       *
+       *  Calls @c std::basic_filebuf::open(__s,__mode|out).  If that
+       *  function fails, @c failbit is set in the stream's error state.
+       */
+      template<typename _Path>
+	auto
+	open(const _Path& __s, ios_base::openmode __mode = ios_base::out)
+	-> decltype(_M_filebuf.open(__s, __mode))
+	{ open(__s.c_str(), __mode); }
+#endif // C++17
+#endif // C++11
 
       /**
        *  @brief  Close the file.
@@ -922,6 +1006,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	this->open(__s, __mode);
       }
 
+#if __cplusplus >= 201703L
+      /**
+       *  @param  Create an input/output file stream.
+       *  @param  __s  filesystem::path specifying the filename.
+       *  @param  __mode  Open file in specified mode (see std::ios_base).
+       */
+      template<typename _Path, typename = _Require<
+	  is_constructible<__filebuf_type, const _Path&, ios_base::openmode>>>
+	basic_fstream(const _Path& __s,
+		      ios_base::openmode __mode = ios_base::in | ios_base::out)
+	: basic_fstream(__s.c_str(), __mode)
+	{ }
+#endif // C++17
+
       basic_fstream(const basic_fstream&) = delete;
 
       basic_fstream(basic_fstream&& __rhs)
@@ -1029,7 +1127,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  // 409. Closing an fstream should clear error state
 	  this->clear();
       }
-#endif
+
+#if __cplusplus >= 201703L
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file, as a filesystem::path.
+       *  @param  __mode  The open mode flags.
+       *
+       *  Calls @c std::basic_filebuf::open(__s,__mode).  If that
+       *  function fails, @c failbit is set in the stream's error state.
+       */
+      template<typename _Path>
+	auto
+	open(const _Path& __s,
+	     ios_base::openmode __mode = ios_base::in | ios_base::out)
+	-> decltype(_M_filebuf.open(__s, __mode))
+	{ open(__s.c_str(), __mode); }
+#endif // C++17
+#endif // C++11
 
       /**
        *  @brief  Close the file.
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/open/char/path.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/open/char/path.cc
new file mode 100644
index 00000000000..56fffde5f9b
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/open/char/path.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 2017 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-fileio "" }
+// { dg-require-filesystem-ts "" }
+
+#include <fstream>
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+const std::filesystem::path filename = "filebuf_members-1.tst";
+
+void
+test01()
+{
+  std::filebuf fb;
+  fb.open(filename, std::ios::in);
+  VERIFY( fb.is_open() );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_fstream/cons/char/path.cc b/libstdc++-v3/testsuite/27_io/basic_fstream/cons/char/path.cc
new file mode 100644
index 00000000000..4442c28c56b
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_fstream/cons/char/path.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 2017 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-fileio "" }
+// { dg-require-filesystem-ts "" }
+
+#include <fstream>
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+const std::filesystem::path filename = "ofstream_members-1.tst";
+
+void
+test01()
+{
+  std::fstream f(filename);
+  VERIFY( f.is_open() );
+}
+
+void
+test02()
+{
+  std::fstream f(filename, std::ios::out);
+  VERIFY( f.is_open() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_fstream/open/char/path.cc b/libstdc++-v3/testsuite/27_io/basic_fstream/open/char/path.cc
new file mode 100644
index 00000000000..8d0127be2b8
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_fstream/open/char/path.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2017 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-fileio "" }
+// { dg-require-filesystem-ts "" }
+
+#include <fstream>
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+const std::filesystem::path filename = "ofstream_members-1.tst";
+
+void
+test01()
+{
+  std::fstream f;
+  f.open(filename);
+  VERIFY( f.is_open() );
+}
+
+void
+test02()
+{
+  std::fstream f;
+  f.open(filename, std::ios::in|std::ios::out);
+  VERIFY( f.is_open() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_ifstream/cons/char/path.cc b/libstdc++-v3/testsuite/27_io/basic_ifstream/cons/char/path.cc
new file mode 100644
index 00000000000..24286f5eeaf
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_ifstream/cons/char/path.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 2017 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-fileio "" }
+// { dg-require-filesystem-ts "" }
+
+#include <fstream>
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+const std::filesystem::path filename = "ifstream_members-1.tst";
+
+void
+test01()
+{
+  std::ifstream f(filename);
+  VERIFY( f.is_open() );
+}
+
+void
+test02()
+{
+  std::ifstream f(filename, std::ios::in);
+  VERIFY( f.is_open() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_ifstream/open/char/path.cc b/libstdc++-v3/testsuite/27_io/basic_ifstream/open/char/path.cc
new file mode 100644
index 00000000000..192e0fe9e85
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_ifstream/open/char/path.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2017 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-fileio "" }
+// { dg-require-filesystem-ts "" }
+
+#include <fstream>
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+const std::filesystem::path filename = "ifstream_members-1.tst";
+
+void
+test01()
+{
+  std::ifstream f;
+  f.open(filename);
+  VERIFY( f.is_open() );
+}
+
+void
+test02()
+{
+  std::ifstream f;
+  f.open(filename, std::ios::in);
+  VERIFY( f.is_open() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_ofstream/cons/char/path.cc b/libstdc++-v3/testsuite/27_io/basic_ofstream/cons/char/path.cc
new file mode 100644
index 00000000000..c6b6b237dfd
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_ofstream/cons/char/path.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 2017 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-fileio "" }
+// { dg-require-filesystem-ts "" }
+
+#include <fstream>
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+const std::filesystem::path filename = "ofstream_members-1.tst";
+
+void
+test01()
+{
+  std::ofstream f(filename);
+  VERIFY( f.is_open() );
+}
+
+void
+test02()
+{
+  std::ofstream f(filename, std::ios::out);
+  VERIFY( f.is_open() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_ofstream/open/char/path.cc b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/char/path.cc
new file mode 100644
index 00000000000..a3fc0c7ff68
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/char/path.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2017 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-fileio "" }
+// { dg-require-filesystem-ts "" }
+
+#include <fstream>
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+const std::filesystem::path filename = "ofstream_members-1.tst";
+
+void
+test01()
+{
+  std::ofstream f;
+  f.open(filename);
+  VERIFY( f.is_open() );
+}
+
+void
+test02()
+{
+  std::ofstream f;
+  f.open(filename, std::ios::out);
+  VERIFY( f.is_open() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] Provide filesystem::path overloads for file streams (LWG 2676, partial)
  2017-10-27 12:44 [PATCH] Provide filesystem::path overloads for file streams (LWG 2676, partial) Jonathan Wakely
@ 2017-10-27 13:04 ` Jonathan Wakely
  0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2017-10-27 13:04 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 985 bytes --]

On 27/10/17 13:43 +0100, Jonathan Wakely wrote:
>This implements part of LWG 2676. I haven't added the new members
>taking wide character strings, because they're only needed on Windows,
>where the Filesystem library doesn't work yet. I'll send a follow-up
>patch about those overloads.

This patch should add the wide character overloads, for systems that
support _wfopen for opening a FILE from a wchar_t string (i.e. MinGW
and MinGW-w64). This is the missing part of LWG 2676.

These are not templates, so would require new symbols to be exported
from the library (but only for Windows). As is done with std::string
for now, I've just disabled the explicit instantiation declarations
for C++17, so the functions get implicitly instantiated as needed.

I'm not committing this, because I haven't tested it, and I get angry
people complaining why I try to support Windows in good faith. So this
is provided with no testing and not committed. Windows users can do
their own testing.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 10054 bytes --]

commit f6a912da2ebcfd1eaedb8fb894421f3accf9cb06
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Oct 24 19:11:06 2017 +0100

    create fstreams from wide strings

diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc b/libstdc++-v3/config/io/basic_file_stdio.cc
index eeb1e5e94b6..2114698a3b8 100644
--- a/libstdc++-v3/config/io/basic_file_stdio.cc
+++ b/libstdc++-v3/config/io/basic_file_stdio.cc
@@ -249,6 +249,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     return __ret;
   }
 
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+  __basic_file<char>*
+  __basic_file<char>::open(const wchar_t* __name, ios_base::openmode __mode)
+  {
+    __basic_file* __ret = NULL;
+    const char* __c_mode = fopen_mode(__mode);
+    if (__c_mode && !this->is_open())
+      {
+	wchar_t __wc_mode[4] = { };
+	int __i = 0;
+	do
+	  {
+	    switch(__c_mode[__i]) {
+	    case 'a': __wc_mode[__i] = L'a'; break;
+	    case 'b': __wc_mode[__i] = L'b'; break;
+	    case 'r': __wc_mode[__i] = L'r'; break;
+	    case 'w': __wc_mode[__i] = L'w'; break;
+	    case '+': __wc_mode[__i] = L'+'; break;
+	    default: return __ret;
+	    }
+	  }
+	while (__c_mode[++__i]);
+
+	if ((_M_cfile = _wfopen(__name, __wc_mode)))
+	  {
+	    _M_cfile_created = true;
+	    __ret = this;
+	  }
+      }
+    return __ret;
+  }
+#endif
+
   bool
   __basic_file<char>::is_open() const throw ()
   { return _M_cfile != 0; }
diff --git a/libstdc++-v3/config/io/basic_file_stdio.h b/libstdc++-v3/config/io/basic_file_stdio.h
index f959ea534cb..11dc47de809 100644
--- a/libstdc++-v3/config/io/basic_file_stdio.h
+++ b/libstdc++-v3/config/io/basic_file_stdio.h
@@ -84,6 +84,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __basic_file*
       open(const char* __name, ios_base::openmode __mode, int __prot = 0664);
 
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      __basic_file*
+      open(const wchar_t* __name, ios_base::openmode __mode);
+#endif
+
       __basic_file*
       sys_open(__c_file* __file, ios_base::openmode);
 
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 270dcbaf723..7ae3d4376aa 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -257,6 +257,7 @@ if $GLIBCXX_IS_NATIVE; then
 
   AC_CHECK_FUNCS(__cxa_thread_atexit_impl __cxa_thread_atexit)
   AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)
+  AC_CHECK_FUNCS(_wfopen)
 
   # For iconv support.
   AM_ICONV
diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc
index 12ea977b997..5b094a3f6e1 100644
--- a/libstdc++-v3/include/bits/fstream.tcc
+++ b/libstdc++-v3/include/bits/fstream.tcc
@@ -207,6 +207,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
+#if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+  template<typename _CharT, typename _Traits>
+    auto
+    basic_filebuf<_CharT, _Traits>::
+    open(const wchar_t* __s, ios_base::openmode __mode)
+    -> __filebuf_type*
+    {
+      __filebuf_type *__ret = 0;
+      if (!this->is_open())
+	{
+	  _M_file.open(__s, __mode);
+	  if (this->is_open())
+	    {
+	      _M_allocate_internal_buffer();
+	      _M_mode = __mode;
+
+	      // Setup initial buffer to 'uncommitted' mode.
+	      _M_reading = false;
+	      _M_writing = false;
+	      _M_set_buffer(-1);
+
+	      // Reset to initial state.
+	      _M_state_last = _M_state_cur = _M_state_beg;
+
+	      // 27.8.1.3,4
+	      if ((__mode & ios_base::ate)
+		  && this->seekoff(0, ios_base::end, __mode)
+		  == pos_type(off_type(-1)))
+		this->close();
+	      else
+		__ret = this;
+	    }
+	}
+      return __ret;
+    }
+#endif
+#endif // C++17
+
   template<typename _CharT, typename _Traits>
     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
     basic_filebuf<_CharT, _Traits>::
@@ -1048,6 +1087,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Inhibit implicit instantiations for required instantiations,
   // which are defined via explicit instantiations elsewhere.
 #if _GLIBCXX_EXTERN_TEMPLATE
+#if !(__cplusplus >= 201703L && _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T)
   extern template class basic_filebuf<char>;
   extern template class basic_ifstream<char>;
   extern template class basic_ofstream<char>;
@@ -1060,6 +1100,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   extern template class basic_fstream<wchar_t>;
 #endif
 #endif
+#endif
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
diff --git a/libstdc++-v3/include/std/fstream b/libstdc++-v3/include/std/fstream
index 3205f81fb47..5f928f44df3 100644
--- a/libstdc++-v3/include/std/fstream
+++ b/libstdc++-v3/include/std/fstream
@@ -314,6 +314,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return open(__s.c_str(), __mode); }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file, as a wide character string.
+       *  @param  __mode  The open mode flags.
+       *  @return  @c this on success, NULL on failure
+       */
+      __filebuf_type*
+      open(const wchar_t* __s, ios_base::openmode __mode);
+#endif
+
       /**
        *  @brief  Opens an external file.
        *  @param  __s  The name of the file, as a filesystem::path.
@@ -536,6 +547,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @param  Create an input file stream.
+       *  @param  __s  Wide string specifying the filename.
+       *  @param  __mode  Open file in specified mode (see std::ios_base).
+       *
+       *  @c ios_base::in is automatically included in @a __mode.
+       */
+      basic_ifstream(const wchar_t* __s,
+		     ios_base::openmode __mode = ios_base::in)
+      : __istream_type(), _M_filebuf()
+      {
+	this->init(&_M_filebuf);
+	this->open(__s, __mode);
+      }
+#endif
+
       /**
        *  @param  Create an input file stream.
        *  @param  __s  filesystem::path specifying the filename.
@@ -658,6 +686,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file, as a wide character string.
+       *  @param  __mode  The open mode flags.
+       *
+       *  Calls @c std::basic_filebuf::open(__s,__mode|in).  If that function
+       *  fails, @c failbit is set in the stream's error state.
+       */
+      void
+      open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in)
+      {
+	if (!_M_filebuf.open(__s, __mode | ios_base::in))
+	  this->setstate(ios_base::failbit);
+	else
+	  this->clear();
+      }
+#endif
+
       /**
        *  @brief  Opens an external file.
        *  @param  __s  The name of the file, as a filesystem::path.
@@ -772,6 +819,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @param  Create an output file stream.
+       *  @param  __s  Wide string specifying the filename.
+       *  @param  __mode  Open file in specified mode (see std::ios_base).
+       *
+       *  @c ios_base::out | @c ios_base::trunc is automatically included in
+       *  @a __mode.
+       */
+      basic_ofstream(const wchar_t* __s,
+		     ios_base::openmode __mode = ios_base::out|ios_base::trunc)
+      : __ostream_type(), _M_filebuf()
+      {
+	this->init(&_M_filebuf);
+	this->open(__s, __mode);
+      }
+#endif
+
       /**
        *  @param  Create an output file stream.
        *  @param  __s  filesystem::path specifying the filename.
@@ -897,6 +962,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file.
+       *  @param  __mode  The open mode flags.
+       *
+       *  Calls @c std::basic_filebuf::open(__s,__mode|out).  If that
+       *  function fails, @c failbit is set in the stream's error state.
+       */
+      void
+      open(const wchar_t* __s, ios_base::openmode __mode = ios_base::out)
+      {
+	if (!_M_filebuf.open(__s, __mode | ios_base::out))
+	  this->setstate(ios_base::failbit);
+	else
+	  this->clear();
+      }
+#endif
+
       /**
        *  @brief  Opens an external file.
        *  @param  __s  The name of the file, as a filesystem::path.
@@ -1007,6 +1091,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @param  Create an input/output file stream.
+       *  @param  __s  Wide string specifying the filename.
+       *  @param  __mode  Open file in specified mode (see std::ios_base).
+       */
+      basic_fstream(const wchar_t* __s,
+		    ios_base::openmode __mode = ios_base::in | ios_base::out)
+      : __iostream_type(0), _M_filebuf()
+      {
+	this->init(&_M_filebuf);
+	this->open(__s, __mode);
+      }
+#endif
+
       /**
        *  @param  Create an input/output file stream.
        *  @param  __s  filesystem::path specifying the filename.
@@ -1129,6 +1228,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file.
+       *  @param  __mode  The open mode flags.
+       *
+       *  Calls @c std::basic_filebuf::open(__s,__mode).  If that
+       *  function fails, @c failbit is set in the stream's error state.
+       */
+      void
+      open(const wchar_t* __s,
+	   ios_base::openmode __mode = ios_base::in | ios_base::out)
+      {
+	if (!_M_filebuf.open(__s, __mode))
+	  this->setstate(ios_base::failbit);
+	else
+	  this->clear();
+      }
+#endif
+
       /**
        *  @brief  Opens an external file.
        *  @param  __s  The name of the file, as a filesystem::path.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2017-10-27 13:00 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-27 12:44 [PATCH] Provide filesystem::path overloads for file streams (LWG 2676, partial) Jonathan Wakely
2017-10-27 13:04 ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).