From 76ee3467734f84f30cdf9c2d593839962a475e9c Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Sat, 14 Dec 2019 20:11:54 -0500 Subject: [PATCH] Update and release the quoted manipulators --- doc/io.adoc | 5 +- doc/ios_state.adoc | 2 +- doc/ostream_joiner.adoc | 2 +- doc/quoted.adoc | 5 +- include/boost/io/detail/quoted_manip.hpp | 200 ++--------------------- include/boost/io/quoted.hpp | 152 +++++++++++++++++ meta/libraries.json | 2 +- test/Jamfile.v2 | 2 +- test/quoted_manip_test.cpp | 133 --------------- test/quoted_test.cpp | 110 +++++++++++++ 10 files changed, 286 insertions(+), 327 deletions(-) create mode 100644 include/boost/io/quoted.hpp delete mode 100644 test/quoted_manip_test.cpp create mode 100644 test/quoted_test.cpp diff --git a/doc/io.adoc b/doc/io.adoc index b8f0c2f..75478b6 100644 --- a/doc/io.adoc +++ b/doc/io.adoc @@ -13,13 +13,12 @@ Daryle Walker, Beman Dawes, Glen Joseph Fernandes :source-language: cpp :toc: left -The I/O sub-library of Boost helps segregate the large number of Boost headers. -This sub-library should contain various items to use with/for the standard I/O -library. +This library contains various utilities for the standard I/O library. :leveloffset: +1 include::ios_state.adoc[] +include::quoted.adoc[] include::ostream_joiner.adoc[] :leveloffset: -1 diff --git a/doc/ios_state.adoc b/doc/ios_state.adoc index dec2d41..1cff15a 100644 --- a/doc/ios_state.adoc +++ b/doc/ios_state.adoc @@ -6,7 +6,7 @@ Distributed under the Boost Software License, Version 1.0. (http://www.boost.org/LICENSE_1_0.txt) //// -# ios_state, +# IO State Savers, :toc: :toc-title: :idprefix: diff --git a/doc/ostream_joiner.adoc b/doc/ostream_joiner.adoc index 4a98cbf..beff8ab 100644 --- a/doc/ostream_joiner.adoc +++ b/doc/ostream_joiner.adoc @@ -6,7 +6,7 @@ Distributed under the Boost Software License, Version 1.0. (http://www.boost.org/LICENSE_1_0.txt) //// -# ostream_joiner, +# Delimited Iterators, :toc: :toc-title: :idprefix: diff --git a/doc/quoted.adoc b/doc/quoted.adoc index d82120c..5bc5639 100644 --- a/doc/quoted.adoc +++ b/doc/quoted.adoc @@ -6,7 +6,7 @@ Distributed under the Boost Software License, Version 1.0. (http://www.boost.org/LICENSE_1_0.txt) //// -# quoted, +# Quoted Manipulators, :toc: :toc-title: :idprefix: @@ -137,3 +137,6 @@ developers mailing list. Participants included Beman Dawes, Rob Stewart, Alexander Lamaison, Eric Niebler, Vicente Botet, Andrey Semashev, Phil Richards, and Rob Murray. Eric Niebler's suggestions provided the basis for the name and form of the templates. + +Beman Dawes started the implementation of `quoted()` as a private detail +header. Glen Fernandes updated the implementation and also made it public. diff --git a/include/boost/io/detail/quoted_manip.hpp b/include/boost/io/detail/quoted_manip.hpp index 502f422..55a1d48 100644 --- a/include/boost/io/detail/quoted_manip.hpp +++ b/include/boost/io/detail/quoted_manip.hpp @@ -1,190 +1,18 @@ -// boost/io/quoted_manip.hpp ---------------------------------------------------------// +/* +Copyright 2010 Beman Dawes -// Copyright Beman Dawes 2010 +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_IO_DETAIL_QUOTED_MANIP_HPP +#define BOOST_IO_DETAIL_QUOTED_MANIP_HPP -// Library home page http://www.boost.org/libs/io +/* +The new implemenation is public in +*/ +#include -//--------------------------------------------------------------------------------------// - -#ifndef BOOST_IO_QUOTED_MANIP -#define BOOST_IO_QUOTED_MANIP - -#include -#include -#include -#include -#include - -namespace boost -{ - namespace io - { - namespace detail { template struct quoted_proxy; } - - // ------------ public interface ------------------------------------------------// - - // manipulator for const std::basic_string& - template - detail::quoted_proxy const &, Char> - quoted(const std::basic_string& s, - Char escape='\\', Char delim='\"'); - - // manipulator for non-const std::basic_string& - template - detail::quoted_proxy &, Char> - quoted(std::basic_string& s, - Char escape='\\', Char delim='\"'); - - // manipulator for const C-string* - template - detail::quoted_proxy - quoted(const Char* s, Char escape='\\', Char delim='\"'); - - // ----------- implementation details -------------------------------------------// - - namespace detail - { - // proxy used as an argument pack - template - struct quoted_proxy - { - String string; - Char escape; - Char delim; - - quoted_proxy(String s_, Char escape_, Char delim_) - : string(s_), escape(escape_), delim(delim_) {} - private: - // String may be a const type, so disable the assignment operator - quoted_proxy& operator=(const quoted_proxy&); // = deleted - }; - - // abstract away difference between proxies with const or non-const basic_strings - template - std::basic_ostream& - basic_string_inserter_imp(std::basic_ostream& os, - std::basic_string const & string, Char escape, Char delim) - { - os << delim; - typename std::basic_string::const_iterator - end_it = string.end(); - for (typename std::basic_string::const_iterator - it = string.begin(); - it != end_it; - ++it ) - { - if (*it == delim || *it == escape) - os << escape; - os << *it; - } - os << delim; - return os; - } - - // inserter for const std::basic_string& proxies - template - inline - std::basic_ostream& operator<<(std::basic_ostream& os, - const quoted_proxy const &, Char>& proxy) - { - return basic_string_inserter_imp(os, proxy.string, proxy.escape, proxy.delim); - } - - // inserter for non-const std::basic_string& proxies - template - inline - std::basic_ostream& operator<<(std::basic_ostream& os, - const quoted_proxy&, Char>& proxy) - { - return basic_string_inserter_imp(os, proxy.string, proxy.escape, proxy.delim); - } - - // inserter for const C-string* proxies - template - std::basic_ostream& operator<<(std::basic_ostream& os, - const quoted_proxy& proxy) - { - os << proxy.delim; - for (const Char* it = proxy.string; - *it; - ++it ) - { - if (*it == proxy.delim || *it == proxy.escape) - os << proxy.escape; - os << *it; - } - os << proxy.delim; - return os; - } - - // extractor for non-const std::basic_string& proxies - template - std::basic_istream& operator>>(std::basic_istream& is, - const quoted_proxy&, Char>& proxy) - { - proxy.string.clear(); - Char c; - is >> c; - if (c != proxy.delim) - { - is.unget(); - is >> proxy.string; - return is; - } - { - boost::io::ios_flags_saver ifs(is); - is >> std::noskipws; - for (;;) - { - is >> c; - if (!is.good()) // cope with I/O errors or end-of-file - break; - if (c == proxy.escape) - { - is >> c; - if (!is.good()) // cope with I/O errors or end-of-file - break; - } - else if (c == proxy.delim) - break; - proxy.string += c; - } - } - return is; - } - - } // namespace detail - - // manipulator implementation for const std::basic_string& - template - inline detail::quoted_proxy const &, Char> - quoted(const std::basic_string& s, Char escape, Char delim) - { - return detail::quoted_proxy const &, Char> - (s, escape, delim); - } - - // manipulator implementation for non-const std::basic_string& - template - inline detail::quoted_proxy &, Char> - quoted(std::basic_string& s, Char escape, Char delim) - { - return detail::quoted_proxy&, Char> - (s, escape, delim); - } - - // manipulator implementation for const C-string* - template - inline detail::quoted_proxy - quoted(const Char* s, Char escape, Char delim) - { - return detail::quoted_proxy (s, escape, delim); - } - - } // namespace io -} // namespace boost - -#endif // BOOST_IO_QUOTED_MANIP +#endif diff --git a/include/boost/io/quoted.hpp b/include/boost/io/quoted.hpp new file mode 100644 index 0000000..44570e2 --- /dev/null +++ b/include/boost/io/quoted.hpp @@ -0,0 +1,152 @@ +/* +Copyright 2010 Beman Dawes + +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_IO_QUOTED_HPP +#define BOOST_IO_QUOTED_HPP + +#include +#include +#include +#include + +namespace boost { +namespace io { +namespace detail { + +template +class quoted_proxy { +public: + quoted_proxy(String string_, Char escape_, Char delim_) + : string(string_) + , escape(escape_) + , delim(delim_) { } + + String string; + Char escape; + Char delim; + +private: + quoted_proxy& operator=(const quoted_proxy&); +}; + +template +inline std::basic_ostream& +operator<<(std::basic_ostream& os, + const quoted_proxy& proxy) +{ + os << proxy.delim; + for (const Char* it = proxy.string; *it; ++it) { + if (*it == proxy.delim || *it == proxy.escape) { + os << proxy.escape; + } + os << *it; + } + os << proxy.delim; + return os; +} + +template +inline std::basic_ostream& +quoted_output(std::basic_ostream& os, + const std::basic_string& string, Char escape, + Char delim) +{ + os << delim; + typename std::basic_string::const_iterator end = string.end(); + for (typename std::basic_string::const_iterator it = string.begin(); it != end; ++it) { + if (*it == delim || *it == escape) { + os << escape; + } + os << *it; + } + os << delim; + return os; +} + +template +inline std::basic_ostream& +operator<<(std::basic_ostream& os, + const quoted_proxy&, + Char>& proxy) +{ + return boost::io::detail::quoted_output(os, proxy.string, proxy.escape, + proxy.delim); +} + +template +inline std::basic_ostream& +operator<<(std::basic_ostream& os, + const quoted_proxy&, Char>& proxy) +{ + return boost::io::detail::quoted_output(os, proxy.string, proxy.escape, + proxy.delim); +} + +template +inline std::basic_istream& +operator>>(std::basic_istream& is, + const quoted_proxy&, Char>& proxy) +{ + proxy.string.clear(); + Char ch; + if (!(is >> ch).good()) { + return is; + } + if (ch != proxy.delim) { + is.unget(); + is >> proxy.string; + return is; + } + { + boost::io::ios_flags_saver ifs(is); + std::noskipws(is); + while ((is >> ch).good() && ch != proxy.delim) { + if (ch == proxy.escape && !(is >> ch).good()) { + break; + } + proxy.string.push_back(ch); + } + } + return is; +} + +} /* detail */ + +template +inline detail::quoted_proxy&, + Char> +quoted(const std::basic_string& s, Char escape='\\', + Char delim='\"') +{ + return detail::quoted_proxy&, + Char>(s, escape, delim); +} + +template +inline detail::quoted_proxy&, Char> +quoted(std::basic_string& s, Char escape='\\', + Char delim='\"') +{ + return detail::quoted_proxy&, + Char>(s, escape, delim); +} + +template +inline detail::quoted_proxy +quoted(const Char* s, Char escape='\\', Char delim='\"') +{ + return detail::quoted_proxy(s, escape, delim); +} + +} /* io */ +} /* boost */ + +#endif diff --git a/meta/libraries.json b/meta/libraries.json index e7626d6..280c708 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -6,7 +6,7 @@ "Beman Dawes", "Glen Fernandes" ], - "description": "Utilities for using the standard I/O library.", + "description": "Utilities for the standard I/O library.", "documentation": "doc/html/io.html", "category": [ "IO" diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ed68f5a..1a15cbb 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -10,6 +10,6 @@ import testing ; run ios_state_unit_test.cpp ; run ios_state_test.cpp ; -run quoted_manip_test.cpp ; +run quoted_test.cpp ; run ostream_joiner_test.cpp ; run make_ostream_joiner_test.cpp ; diff --git a/test/quoted_manip_test.cpp b/test/quoted_manip_test.cpp deleted file mode 100644 index 80e6f78..0000000 --- a/test/quoted_manip_test.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// libs/io/test/quote_manip_test.cpp ----------------------------------------------- // - -// Copyright Beman Dawes 2010 - -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt - -// Library home page: http://www.boost.org/libs/io - -// ---------------------------------------------------------------------------------- // - -#include -#include -#include -#include - -using boost::io::quoted; -using std::string; -using std::wstring; - -int main() -{ - - std::wstringstream wss; - - string r; // test results - - const string s0("foo"); - { - std::stringstream ss; - ss << quoted(s0); - ss >> r; - BOOST_TEST(r == "\"foo\""); - } - { - std::stringstream ss; - ss << quoted(s0); - ss >> quoted(r); - BOOST_TEST(r == "foo"); - } - - const string s0s("foo bar"); - { - std::stringstream ss; - ss << quoted(s0s); - ss >> r; - BOOST_TEST(r == "\"foo"); - } - { - std::stringstream ss; - ss << quoted(s0s); - ss >> quoted(r); - BOOST_TEST(r == "foo bar"); - } - - const string s1("foo\\bar, \" *"); - { - std::stringstream ss; - ss << quoted(s1); - ss >> r; - BOOST_TEST(r == "\"foo\\\\bar,"); - } - { - std::stringstream ss; - ss << quoted("foo\\bar, \" *"); - ss >> r; - BOOST_TEST(r == "\"foo\\\\bar,"); - } - { - std::stringstream ss; - ss << quoted(s1); - ss >> quoted(r); - BOOST_TEST(r == s1); - } - { - std::stringstream ss; - ss << quoted(s1.c_str()); - ss >> quoted(r); - BOOST_TEST(r == s1); - } - - string s2("'Jack & Jill'"); - { - std::stringstream ss; - ss << quoted(s2, '&', '\''); - ss >> quoted(r, '&', '\''); - BOOST_TEST(r == s2); - } - - wstring ws1(L"foo$bar, \" *"); - wstring wr; // test results - { - std::wstringstream wss; - wss << quoted(ws1, L'$'); - wss >> quoted(wr, L'$'); - BOOST_TEST(wr == ws1); - } - - const string s3("const string"); - { - std::stringstream ss; - ss << quoted(s3); - ss >> quoted(r); - BOOST_TEST(r == s3); - } - { - // missing end delimiter test - std::stringstream ss; - ss << "\"abc"; // load ss with faulty quoting - ss >> quoted(r); // this loops if istream error/eof not detected - BOOST_TEST(r == "abc"); - } - { - // no initial delmiter test - std::stringstream ss; - ss << "abc"; - ss >> quoted(r); - BOOST_TEST(r == "abc"); - } - { - // no initial delmiter, space in ss - std::stringstream ss; - ss << "abc def"; - ss >> quoted(r); - BOOST_TEST(r == "abc"); - } - - // these should fail to compile because the arguments are const: - // ss >> quoted(s1); - // ss >> quoted("foo"); - - return boost::report_errors(); -} diff --git a/test/quoted_test.cpp b/test/quoted_test.cpp new file mode 100644 index 0000000..2ca0a25 --- /dev/null +++ b/test/quoted_test.cpp @@ -0,0 +1,110 @@ +/* +Copyright 2010 Beman Dawes + +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include +#include +#include + +int main() +{ + const std::string s0("foo"); + std::string r; + { + std::stringstream ss; + ss << boost::io::quoted(s0); + ss >> r; + BOOST_TEST(r == "\"foo\""); + } + { + std::stringstream ss; + ss << boost::io::quoted(s0); + ss >> boost::io::quoted(r); + BOOST_TEST(r == "foo"); + } + const std::string s0s("foo bar"); + { + std::stringstream ss; + ss << boost::io::quoted(s0s); + ss >> r; + BOOST_TEST(r == "\"foo"); + } + { + std::stringstream ss; + ss << boost::io::quoted(s0s); + ss >> boost::io::quoted(r); + BOOST_TEST(r == "foo bar"); + } + const std::string s1("foo\\bar, \" *"); + { + std::stringstream ss; + ss << boost::io::quoted(s1); + ss >> r; + BOOST_TEST(r == "\"foo\\\\bar,"); + } + { + std::stringstream ss; + ss << boost::io::quoted("foo\\bar, \" *"); + ss >> r; + BOOST_TEST(r == "\"foo\\\\bar,"); + } + { + std::stringstream ss; + ss << boost::io::quoted(s1); + ss >> boost::io::quoted(r); + BOOST_TEST(r == s1); + } + { + std::stringstream ss; + ss << boost::io::quoted(s1.c_str()); + ss >> boost::io::quoted(r); + BOOST_TEST(r == s1); + } + std::string s2("'Jack & Jill'"); + { + std::stringstream ss; + ss << boost::io::quoted(s2, '&', '\''); + ss >> boost::io::quoted(r, '&', '\''); + BOOST_TEST(r == s2); + } + const std::wstring ws1(L"foo$bar, \" *"); + std::wstring wr; + { + std::wstringstream wss; + wss << boost::io::quoted(ws1, L'$'); + wss >> boost::io::quoted(wr, L'$'); + BOOST_TEST(wr == ws1); + } + const std::string s3("const string"); + { + std::stringstream ss; + ss << boost::io::quoted(s3); + ss >> boost::io::quoted(r); + BOOST_TEST(r == s3); + } + { + std::stringstream ss; + ss << "\"abc"; + ss >> boost::io::quoted(r); + BOOST_TEST(r == "abc"); + } + { + std::stringstream ss; + ss << "abc"; + ss >> boost::io::quoted(r); + BOOST_TEST(r == "abc"); + } + { + std::stringstream ss; + ss << "abc def"; + ss >> boost::io::quoted(r); + BOOST_TEST(r == "abc"); + } + return boost::report_errors(); +}