forked from boostorg/io
Merge from trunk
[SVN r68159]
This commit is contained in:
161
doc/quoted_manip.html
Normal file
161
doc/quoted_manip.html
Normal file
@@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
||||
<title>Boost "quoted" I/O manipulator</title>
|
||||
<meta name="generator" content="Microsoft FrontPage 5.0" />
|
||||
<link rel="stylesheet" type="text/css" href="../../../doc/src/minimal.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0"
|
||||
style="border-collapse: collapse">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="277"><a href="../../../index.htm"><img
|
||||
src="../../../boost.png" alt="boost.png (6897 bytes)" align="middle"
|
||||
width="300" height="86" border="0" /></a></td>
|
||||
<td>
|
||||
<h1 align="center">"Quoted"
|
||||
I/O Manipulators<br>
|
||||
for Strings</h1>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="1" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td>
|
||||
<p align="center"><b>"Quoted"
|
||||
I/O Manipulators
|
||||
for Strings are not yet accepted into Boost as public components. Thus the
|
||||
header file is currently located in <boost/io/detail/quoted_manip.hpp></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>C++ Standard library stream I/O for strings that contain embedded spaces
|
||||
can produce unexpected results. For example,</p>
|
||||
<blockquote>
|
||||
<pre>std::stringstream ss;
|
||||
std::string original = "fooled you";
|
||||
std::string round_trip;
|
||||
|
||||
ss << original;
|
||||
ss >> round_trip;
|
||||
|
||||
std::cout << original; // outputs: fooled you
|
||||
std::cout << round_trip; // outputs: fooled
|
||||
|
||||
assert(original == round_trip); // assert will fire</pre>
|
||||
</blockquote>
|
||||
<p>The Boost <code>quoted</code> stream I/O manipulator places delimiters, defaulted
|
||||
to the double-quote (<code>"</code>), around strings on output, and strips off
|
||||
the delimiters on input. This ensures strings with embedded spaces round-trip as
|
||||
desired. For example,</p>
|
||||
<blockquote>
|
||||
<pre>std::stringstream ss;
|
||||
std::string original = "fooled you";
|
||||
std::string round_trip;
|
||||
|
||||
ss << quoted(original);
|
||||
ss >> quoted(round_trip);
|
||||
|
||||
std::cout << quoted(original); // outputs: "fooled you"
|
||||
std::cout << round_trip; // outputs: fooled you
|
||||
|
||||
assert(original == round_trip); // assert will not fire</pre>
|
||||
</blockquote>
|
||||
<p>If the string contains the delimiter character, on output that character will
|
||||
be preceded by an escape character, as will the escape character itself:</p>
|
||||
<blockquote>
|
||||
<pre>std::cout << quoted("'Jack & Jill'", '&', '\''); // outputs: '&'Jack && Jill&''</pre>
|
||||
</blockquote>
|
||||
<h2>Header <a href="../../../boost/io/detail/quoted_manip.hpp"><boost/io/quoted_manip.hpp></a> synopsis</h2>
|
||||
<pre>namespace boost
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
// manipulator for const std::basic_string&
|
||||
|
||||
template <class Char, class Traits, class Alloc>
|
||||
<b><i>unspecified-type1</i></b> quoted(const std::basic_string<Char, Traits, Alloc>& string, Char escape='\\', Char delim='\"');
|
||||
|
||||
// manipulator for const C-string*
|
||||
|
||||
template <class Char>
|
||||
<b><i>unspecified-type2</i></b> quoted(const Char* string, Char escape='\\', Char delim='\"');
|
||||
|
||||
// manipulator for non-const std::basic_string&
|
||||
|
||||
template <class Char, class Traits, class Alloc>
|
||||
<b><i>unspecified-type3</i></b> quoted(std::basic_string<Char, Traits, Alloc>& string, Char escape='\\', Char delim='\"');
|
||||
}
|
||||
}</pre>
|
||||
<p><i><b><code>unspecified_type1</code></b></i>, <i><b><code>unspecified_type2</code></b></i>,
|
||||
and <i><b><code>unspecified_type3</code></b></i> are implementation supplied
|
||||
types with implementation supplied <code>operator<<</code>:</p>
|
||||
<blockquote>
|
||||
<pre>template <class Char, class Traits>
|
||||
std::basic_ostream<Char, Traits>&
|
||||
operator<<(std::basic_ostream<Char, Traits>& os, const <i><b><code>unspecified_typeN</code></b></i>& proxy);</pre>
|
||||
<p><i>Effects:</i> Inserts characters into <code>os</code>:</p>
|
||||
<ul>
|
||||
<li><code>delim</code>.</li>
|
||||
<li>Each character in <code>string</code>. If the character to be output is
|
||||
equal to <code>escape</code> or <code>delim</code>, as determined by <code>
|
||||
operator==</code>, first output <code>escape</code>. </li>
|
||||
<li><code>delim</code>.</li>
|
||||
</ul>
|
||||
<p><i>Remarks:</i> <code>string</code>, <code>escape</code>, and <code>delim</code>
|
||||
have the type and value of the corresponding arguments of the call to the <code>
|
||||
quoted</code> function that constructed <code>proxy</code>.</p>
|
||||
<p><i>Returns:</i> <code>os</code>. </p>
|
||||
</blockquote>
|
||||
<p><i><b><code>unspecified_type3</code></b></i> is an implementation supplied
|
||||
type with an implementation supplied <code>operator>></code>:</p>
|
||||
<blockquote>
|
||||
<pre>template <class Char, class Traits>
|
||||
std::basic_istream<Char, Traits>&
|
||||
operator>>(std::basic_istream<Char, Traits>& is, const <i><b><code>unspecified_type3</code></b></i>& proxy);</pre>
|
||||
<p><i>Effects:</i> Extracts characters from <code>os</code>:</p>
|
||||
<ul>
|
||||
<li>If the first character extracted is equal to delim, as determined by
|
||||
<code>operator==</code>, then:<ul>
|
||||
<li>Turn off the <code>skipws</code> flag.</li>
|
||||
<li><code>string.clear()</code></li>
|
||||
<li>Until an unescaped <code>delim</code> character is reached or <code>
|
||||
is.not_good()</code>, extract
|
||||
characters from <code>os</code> and append them to <code>string</code>,
|
||||
except that if an <code>escape</code> is reached, ignore it and append the
|
||||
next character to <code>string</code>.</li>
|
||||
<li>Discard the final <code>delim</code> character.</li>
|
||||
<li>Restore the <code>skipws</code> flag to its original value.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Otherwise, <code>os >> string</code>.</li>
|
||||
</ul>
|
||||
<p><i>Remarks:</i> <code>string</code>, <code>escape</code>, and <code>delim</code>
|
||||
have the type and value of the corresponding arguments of the call to the <code>
|
||||
quoted</code> function that constructed <code>proxy</code>.</p>
|
||||
<p><i>Returns:</i> <code>is</code>. </p>
|
||||
</blockquote>
|
||||
<h2>Acknowledgements</h2>
|
||||
<p>The <code>quoted()</code> stream manipulator emerged from discussions on the
|
||||
Boost 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. </p>
|
||||
<hr>
|
||||
<p><EFBFBD> Copyright Beman Dawes, 2002, 2006, 2007, 2009, 2010</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. See
|
||||
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a></p>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B %Y" startspan -->20 June 2010<!--webbot bot="Timestamp" endspan i-checksum="17544" --></p>
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -125,15 +125,15 @@ namespace boost
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& is,
|
||||
const quoted_proxy<std::basic_string<Char, Traits, Alloc>&, Char>& proxy)
|
||||
{
|
||||
proxy.string.clear();
|
||||
Char c;
|
||||
is >> c;
|
||||
if (c != proxy.delim)
|
||||
{
|
||||
proxy.string = c;
|
||||
is.unget();
|
||||
is >> proxy.string;
|
||||
return is;
|
||||
}
|
||||
proxy.string.clear();
|
||||
{
|
||||
boost::io::ios_flags_saver ifs(is);
|
||||
is >> std::noskipws;
|
||||
|
@@ -21,4 +21,6 @@ test-suite "io"
|
||||
: # input files
|
||||
# : std::locale-support
|
||||
]
|
||||
|
||||
[ run quoted_manip_test.cpp ]
|
||||
;
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#include <boost/io/ios_state.hpp> // for boost::io::ios_flags_saver, etc.
|
||||
|
||||
#include <cstddef> // for std::size_t
|
||||
#include <iomanip> // for std::setw
|
||||
#include <boost/detail/iomanip.hpp> // for boost::detail::setw
|
||||
#include <ios> // for std::ios_base, std::streamsize, etc.
|
||||
#include <iostream> // for std::cout, etc.
|
||||
#include <istream> // for std::istream
|
||||
@@ -143,7 +143,7 @@ saver_tests_1
|
||||
{
|
||||
using std::locale;
|
||||
using std::ios_base;
|
||||
using std::setw;
|
||||
using boost::detail::setw;
|
||||
|
||||
boost::io::ios_flags_saver const ifls( output );
|
||||
boost::io::ios_precision_saver const iprs( output );
|
||||
@@ -168,8 +168,8 @@ saver_tests_1
|
||||
output.fill( '@' );
|
||||
output.precision( 9 );
|
||||
output << '\t' << test_string << '\n';
|
||||
output << '\t' << setw( 10 ) << test_num1 << '\n';
|
||||
output << '\t' << setw( 15 ) << test_num2 << '\n';
|
||||
output << '\t' << boost::detail::setw( 10 ) << test_num1 << '\n';
|
||||
output << '\t' << boost::detail::setw( 15 ) << test_num2 << '\n';
|
||||
output.imbue( loc );
|
||||
output << '\t' << test_bool << '\n';
|
||||
|
||||
|
@@ -13,7 +13,7 @@
|
||||
#include <boost/test/unit_test.hpp> // for main, BOOST_CHECK, etc.
|
||||
|
||||
#include <cstddef> // for NULL
|
||||
#include <iomanip> // for std::setiosflags, etc.
|
||||
#include <boost/detail/iomanip.hpp> // for boost::detail::setiosflags, etc.
|
||||
#include <ios> // for std::ios_base
|
||||
#include <iostream> // for std::cout, std::cerr, etc.
|
||||
#include <istream> // for std::iostream
|
||||
@@ -77,7 +77,7 @@ ios_flags_saver_unit_test
|
||||
BOOST_CHECK_EQUAL( (ios_base::showbase | ios_base::internal),
|
||||
ss.flags() );
|
||||
|
||||
ss << setiosflags( ios_base::unitbuf );
|
||||
ss << boost::detail::setiosflags( ios_base::unitbuf );
|
||||
BOOST_CHECK_EQUAL( (ios_base::showbase | ios_base::internal
|
||||
| ios_base::unitbuf), ss.flags() );
|
||||
}
|
||||
@@ -102,7 +102,7 @@ ios_precision_saver_unit_test
|
||||
|
||||
BOOST_CHECK_EQUAL( 6, ss.precision() );
|
||||
|
||||
ss << setprecision( 4 );
|
||||
ss << boost::detail::setprecision( 4 );
|
||||
BOOST_CHECK_EQUAL( 4, ss.precision() );
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ ios_precision_saver_unit_test
|
||||
|
||||
BOOST_CHECK_EQUAL( 8, ss.precision() );
|
||||
|
||||
ss << setprecision( 10 );
|
||||
ss << boost::detail::setprecision( 10 );
|
||||
BOOST_CHECK_EQUAL( 10, ss.precision() );
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ ios_width_saver_unit_test
|
||||
|
||||
BOOST_CHECK_EQUAL( 0, ss.width() );
|
||||
|
||||
ss << setw( 4 );
|
||||
ss << boost::detail::setw( 4 );
|
||||
BOOST_CHECK_EQUAL( 4, ss.width() );
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ ios_width_saver_unit_test
|
||||
|
||||
BOOST_CHECK_EQUAL( 8, ss.width() );
|
||||
|
||||
ss << setw( 10 );
|
||||
ss << boost::detail::setw( 10 );
|
||||
BOOST_CHECK_EQUAL( 10, ss.width() );
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ ios_base_all_saver_unit_test
|
||||
BOOST_CHECK_EQUAL( 6, ss.precision() );
|
||||
BOOST_CHECK_EQUAL( 0, ss.width() );
|
||||
|
||||
ss << hex << unitbuf << setprecision( 5 ) << setw( 7 );
|
||||
ss << hex << unitbuf << boost::detail::setprecision( 5 ) << boost::detail::setw( 7 );
|
||||
BOOST_CHECK_EQUAL( (ios_base::unitbuf | ios_base::hex
|
||||
| ios_base::skipws), ss.flags() );
|
||||
BOOST_CHECK_EQUAL( 5, ss.precision() );
|
||||
@@ -560,10 +560,10 @@ ios_all_saver_unit_test
|
||||
ss << oct << showpos << noskipws;
|
||||
BOOST_CHECK_EQUAL( (ios_base::showpos | ios_base::oct), ss.flags() );
|
||||
|
||||
ss << setprecision( 3 );
|
||||
ss << boost::detail::setprecision( 3 );
|
||||
BOOST_CHECK_EQUAL( 3, ss.precision() );
|
||||
|
||||
ss << setw( 9 );
|
||||
ss << boost::detail::setw( 9 );
|
||||
BOOST_CHECK_EQUAL( 9, ss.width() );
|
||||
|
||||
ss.setstate( ios_base::eofbit );
|
||||
@@ -586,7 +586,7 @@ ios_all_saver_unit_test
|
||||
ss.rdbuf( cerr.rdbuf() );
|
||||
BOOST_CHECK_EQUAL( cerr.rdbuf(), ss.rdbuf() );
|
||||
|
||||
ss << setfill( 'x' );
|
||||
ss << boost::detail::setfill( 'x' );
|
||||
BOOST_CHECK_EQUAL( 'x', ss.fill() );
|
||||
|
||||
ss.imbue( locale(locale::classic(), new backward_bool_names) );
|
||||
|
133
test/quoted_manip_test.cpp
Normal file
133
test/quoted_manip_test.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
// 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 <boost/io/detail/quoted_manip.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
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();
|
||||
}
|
Reference in New Issue
Block a user