1
0
forked from boostorg/io

Merge from trunk

[SVN r68159]
This commit is contained in:
Beman Dawes
2011-01-14 19:21:55 +00:00
parent 7e90f31161
commit f5f8d96157
6 changed files with 312 additions and 16 deletions

161
doc/quoted_manip.html Normal file
View 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 &quot;quoted&quot; 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">&quot;Quoted&quot;
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>&quot;Quoted&quot;
I/O Manipulators
for Strings are not yet accepted into Boost as public components. Thus the
header file is currently located in &lt;boost/io/detail/quoted_manip.hpp&gt;</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 = &quot;fooled you&quot;;
std::string round_trip;
ss &lt;&lt; original;
ss &gt;&gt; round_trip;
std::cout &lt;&lt; original; // outputs: fooled you
std::cout &lt;&lt; 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>&quot;</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 = &quot;fooled you&quot;;
std::string round_trip;
ss &lt;&lt; quoted(original);
ss &gt;&gt; quoted(round_trip);
std::cout &lt;&lt; quoted(original); // outputs: &quot;fooled you&quot;
std::cout &lt;&lt; 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 &lt;&lt; quoted(&quot;'Jack &amp; Jill'&quot;, '&amp;', '\''); // outputs: '&amp;'Jack &amp;&amp; Jill&amp;''</pre>
</blockquote>
<h2>Header <a href="../../../boost/io/detail/quoted_manip.hpp">&lt;boost/io/quoted_manip.hpp&gt;</a> synopsis</h2>
<pre>namespace boost
{
namespace io
{
// manipulator for const std::basic_string&amp;
template &lt;class Char, class Traits, class Alloc&gt;
<b><i>unspecified-type1</i></b> quoted(const std::basic_string&lt;Char, Traits, Alloc&gt;&amp; string, Char escape='\\', Char delim='\&quot;');
// manipulator for const C-string*
template &lt;class Char&gt;
<b><i>unspecified-type2</i></b> quoted(const Char* string, Char escape='\\', Char delim='\&quot;');
// manipulator for non-const std::basic_string&amp;
template &lt;class Char, class Traits, class Alloc&gt;
<b><i>unspecified-type3</i></b> quoted(std::basic_string&lt;Char, Traits, Alloc&gt;&amp; string, Char escape='\\', Char delim='\&quot;');
}
}</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&lt;&lt;</code>:</p>
<blockquote>
<pre>template &lt;class Char, class Traits&gt;
std::basic_ostream&lt;Char, Traits&gt;&amp;
operator&lt;&lt;(std::basic_ostream&lt;Char, Traits&gt;&amp; os, const <i><b><code>unspecified_typeN</code></b></i>&amp; 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&gt;&gt;</code>:</p>
<blockquote>
<pre>template &lt;class Char, class Traits&gt;
std::basic_istream&lt;Char, Traits&gt;&amp;
operator&gt;&gt;(std::basic_istream&lt;Char, Traits&gt;&amp; is, const <i><b><code>unspecified_type3</code></b></i>&amp; 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 &gt;&gt; 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>

View File

@@ -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;

View File

@@ -21,4 +21,6 @@ test-suite "io"
: # input files
# : std::locale-support
]
[ run quoted_manip_test.cpp ]
;

View File

@@ -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';

View File

@@ -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
View 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();
}