blob: 9a90cf0a8ea36513df8ffbc60cb371b8b95ffa84 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Tutorial</TITLE>
<LINK REL="stylesheet" HREF="../../../../boost.css">
<LINK REL="stylesheet" HREF="../theme/iostreams.css">
</HEAD>
<BODY>
<!-- Begin Banner -->
<H1 CLASS="title">Tutorial</H1>
<HR CLASS="banner">
<!-- End Banner -->
<!-- Begin Nav -->
<DIV CLASS='nav'>
<A HREF='filter_usage.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/prev.png'></A>
<A HREF='tutorial.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/up.png'></A>
<A HREF='line_wrapping_filters.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/next.png'></A>
</DIV>
<!-- End Nav -->
<A NAME="shell_comments"></A>
<H2>2.2.3. Shell Comments Filters</H2>
<P>
Suppose you want to write a filter to remove shell-style comments. The basic algorithm is as follows: you examine characters one at a time, forwarding them unchanged, until you encounter a comment character, typically <CODE>'#'</CODE>. When you find a comment character, you examine and ignore characters until you encounter a newline character, at which point the algorithm begins again. Note that this algorithm consists of two subalgorithms: one algorithm for reading ordinary text, and one for reading comments.
</P>
<P>
In the next three sections, I'll express this algorithm as a <A HREF="../classes/stdio_filter.html"><CODE>stdio_filter</CODE></A>, an <A HREF="../concepts/input_filter.html">InputFilter</A> and an <A HREF="../concepts/output_filter.html">OutputFilter</A>. The source code can be found in the header <A HREF="../../example/shell_comments_filter.hpp"><CODE>&lt;libs/iostreams/example/shell_comments_filter.hpp&gt;</CODE></A>. These examples were inspired by James Kanze's <CODE>UncommentExtractor.hh</CODE> (<I>see</I> <A CLASS="bib_ref" HREF="../bibliography.html#kanze">[Kanze]</A>).
</P>
<A NAME="shell_comments_stdio_filter"></A>
<H4><CODE>shell_comments_stdio_filter</CODE></H4>
<P>You can express a shell comments Filter as a <A HREF="../classes/stdio_filter.html"><CODE>stdio_filter</CODE></A> as follows:</P>
<PRE class="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS="literal">&lt;cstdio&gt;</SPAN> <SPAN CLASS="comment">// EOF</SPAN>
<SPAN CLASS="preprocessor">#include</SPAN> <SPAN CLASS="literal">&lt;iostream&gt;</SPAN> <SPAN CLASS="comment">// cin, cout</SPAN>
<SPAN CLASS="preprocessor">#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/filter/stdio.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/filter/stdio.hpp&gt;</SPAN></A>
<SPAN CLASS="keyword">class</SPAN> shell_comments_stdio_filter : <SPAN CLASS="keyword"><SPAN CLASS="keyword"><SPAN CLASS="keyword">public</SPAN></SPAN></SPAN> stdio_filter {
<SPAN CLASS="keyword">public</SPAN>:
explicit shell_comments_stdio_filter(<SPAN CLASS="keyword">char</SPAN> comment_char = <SPAN CLASS="literal">'#'</SPAN>)
: comment_char_(comment_char)
{ }
<SPAN CLASS="keyword">private</SPAN>:
<SPAN CLASS="keyword">void</SPAN> do_filter()
{
<SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> skip = <SPAN CLASS="keyword">false</SPAN>;
<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c;
<SPAN CLASS="keyword">while</SPAN> ((c = std::cin.get()) != <SPAN CLASS="numeric_literal">EOF</SPAN>) {
skip = c == comment_char_ ?
<SPAN CLASS="keyword">true</SPAN> :
c == <SPAN CLASS="literal">'\n'</SPAN> ?
<SPAN CLASS="keyword">false</SPAN> :
skip;
<SPAN CLASS="keyword">if</SPAN> (!skip)
std::cout.put(c);
}
}
<SPAN CLASS="keyword">char</SPAN> comment_char_;
};
} } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>
<P>
The implementation of the <CODE>virtual</CODE> function <CODE>do_filter</CODE> is straightforward: The local variable <CODE>skip</CODE> keeps track of whether you are currently processing a comment; the <CODE>while</CODE> loop reads a character <CODE>c</CODE> from <CODE>std::cin</CODE>, updates <CODE>skip</CODE> and writes <CODE>c</CODE> to <CODE>std::cout</CODE> unless <CODE>skip</CODE> is <CODE>true</CODE>.
</P>
<P>Filters which derive from <CODE>stdio_filter</CODE> are <A HREF="../concepts/dual_use_filter.html">DualUseFilters</A>, which mean they can be used either for output or for input, but not both simultaneously. Therefore <CODE>unix2dos_stdio_filter</CODE> can be used in place of <A HREF="#shell_comments_input_filter"><CODE>shell_comments_input_filter</CODE></A> and <A HREF="#shell_comments_output_filter"><CODE>shell_comments_output_filter</CODE></A>, below.
<A NAME="shell_comments_input_filter"></A>
<H4><CODE>shell_comments_input_filter</CODE></H4>
<P>Next you will express a shell comments Filter as an <A HREF="../concepts/input_filter.html">InputFilter</A>. A typical narrow-character InputFilter looks like this:</P>
<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/categories.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/categories.hpp&gt;</SPAN></A> <SPAN CLASS='comment'>// input_filter_tag</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/char_traits.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/char_traits.hpp&gt;</SPAN></A> <SPAN CLASS='comment'>// EOF, WOULD_BLOCK</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/operations.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/operations.hpp&gt;</SPAN></A> <SPAN CLASS='comment'>// get, read, putback</SPAN>
<SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams;
<SPAN CLASS='keyword'>class</SPAN> my_input_filter {
<SPAN CLASS='keyword'>public</SPAN>:
<SPAN CLASS='keyword'>typedef</SPAN> <SPAN CLASS='keyword'>char</SPAN> char_type;
<SPAN CLASS='keyword'>typedef</SPAN> input_filter_tag category;
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
<SPAN CLASS='keyword'>int</SPAN> get(Source& src)
{
<SPAN CLASS='comment'>// Attempt to produce one character of filtered</SPAN>
<SPAN CLASS='comment'>// data, reading from src as necessary. If successful,</SPAN>
<SPAN CLASS='comment'>// return the character; otherwise return EOF to</SPAN>
<SPAN CLASS='comment'>// indicate end-of-stream, or WOULD_BLOCK</SPAN>
}
<SPAN CLASS='comment'>/* Other members */</SPAN>
};</PRE>
<P>The function <CODE>get</CODE> attempts to produce a single character of filtered output. It accesses the unfiltered character sequence though the provided <A HREF="../concepts/source.html">Source</A> <CODE>src</CODE>, using the fundamental i/o operations <A HREF="../functions/get.html"><CODE>get</CODE></A>, <A HREF="../functions/read.html"><CODE>read</CODE></A> and <A HREF="../functions/putback.html"><CODE>putback</CODE></A>. If a character is produced, <CODE>get</CODE> returns it. Otherwise <CODE>get</CODE> returns one of the status codes <CODE>EOF</CODE> or <CODE>WOULD_BLOCK</CODE>. <CODE>EOF</CODE>, which indicates end-of-stream, is a macro defined in the standard header <CODE>&lt;cstdio&gt;</CODE>. <CODE>WOULD_BLOCK</CODE>, which indicates that input is temporarily unavailable, is a constant defined in the namespace <CODE>boost::iostreams</CODE>, in the header <A HREF="../../../../boost/iostreams/char_traits.hpp"><CODE>&lt;boost/iostreams/char_traits.hpp&gt;</CODE></A></P>
<P> You could also write the above example as follows:</P>
<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/concepts.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/concepts.hpp&gt;</SPAN></A> <SPAN CLASS='comment'>// input_filter</SPAN>
<SPAN CLASS='keyword'>class</SPAN> my_input_filter : <SPAN CLASS='keyword'>public</SPAN> input_filter {
<SPAN CLASS='keyword'>public</SPAN>:
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
<SPAN CLASS='keyword'>int</SPAN> get(Source& src);
<SPAN CLASS='comment'>/* Other members */</SPAN>
};</PRE>
<P>Here <A HREF="../classes/filter.html#synopsis"><CODE>input_filter</CODE></A> is a convenience base class which provides the member types <CODE>char_type</CODE> and <CODE>category</CODE>, as well as no-op implementations of member functions <CODE>close</CODE> and <CODE>imbue</CODE>. I will discuss <CODE>close</CODE> shortly.
<P>You're now ready to express a shell Comments Filter as an <A HREF="../concepts/input_filter.html">InputFilter</A>:</P>
<PRE class="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/char_traits.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/char_traits.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// EOF, WOULD_BLOCK</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/concepts.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/concepts.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// input_filter</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/operations.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/operations.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// get</SPAN>
<SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
<SPAN CLASS="keyword">class</SPAN> shell_comments_input_filter : <SPAN CLASS="keyword"><SPAN CLASS="keyword"><SPAN CLASS="keyword">public</SPAN></SPAN></SPAN> input_filter {
<SPAN CLASS="keyword">public</SPAN>:
explicit shell_comments_input_filter(<SPAN CLASS="keyword">char</SPAN> comment_char = <SPAN CLASS="literal">'#'</SPAN>)
: comment_char_(comment_char), skip_(<SPAN CLASS="keyword">false</SPAN>)
{ }
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> get(Source& src)
{
<SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c;
<SPAN CLASS="keyword">while</SPAN> (<SPAN CLASS="keyword">true</SPAN>) {
<SPAN CLASS="keyword">if</SPAN> ((c = boost::iostreams::get(src)) == <SPAN CLASS="numeric_literal">EOF</SPAN> || c == WOULD_BLOCK)
break;
skip_ = c == comment_char_ ?
<SPAN CLASS="keyword">true</SPAN> :
c == <SPAN CLASS="literal">'\n'</SPAN> ?
<SPAN CLASS="keyword">false</SPAN> :
skip_;
<SPAN CLASS="keyword">if</SPAN> (!skip_)
break;
}
<SPAN CLASS="keyword">return</SPAN> c;
}
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
<SPAN CLASS="keyword">void</SPAN> close(Source&) { skip_ = <SPAN CLASS="keyword">false</SPAN>; }
<SPAN CLASS="keyword">private</SPAN>:
<SPAN CLASS="keyword">char</SPAN> comment_char_;
<SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> skip_;
};
} } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>
<P>
Here the member variable <CODE>skip_</CODE> plays the same role as the local variable <CODE>skip</CODE> <CODE>shell_comments_stdio_filter::do_filter</CODE>. The implementation of <CODE>get</CODE> is very similar to that of <CODE>shell_comments_stdio_filter::do_filter</CODE>: the <CODE>while</CODE> loop reads a character <CODE>c</CODE>, updates <CODE>skip_</CODE> and returns <CODE>c</CODE> unless <CODE>skip_</CODE> is <CODE>true</CODE>. The main difference is that you have to handle the special value <CODE>WOULD_BLOCK</CODE>, which indicates that no input is currently available.
</P>
<P>
So you see that implementing an <A HREF="../concepts/input_filter.html"><CODE>InputFilter</CODE></A> from scratch is a bit more involved than deriving from <A HREF="../classes/stdio_filter.html"><CODE>stdio_filter</CODE></A>. When writing an <CODE>InputFilter</CODE> you must be prepared to be interrupted at any point in the middle of the algorithm; when this happens, you must record enough information about the current state of the algorithm to allow you to pick up later exactly where you left off. The same is true for <A HREF="../concepts/output_filter.html"><CODE>OutputFilters</CODE></A>. In fact, many Inputfilters and OutputFilters can be seen as finite state machines; I will formalize this idea later. <I>See</I> <A HREF="finite_state_filters.html">Finite State Filters</A>.
</P>
<P>
There's still one problem with <CODE>shell_comments_input_filter</CODE>: its instances can only be used once. That's because someone might close a stream while the <CODE>skip_</CODE> flag is set. If the stream were later reopened &#8212; with a fresh sequence of unfiltered data &#8212; the first line of text would be filtered out, regardless of whether it were commented.
</P>
<P>
The way to fix this is to make your Filter <A HREF="../concepts/closable.html">Closable</A>. To do this, you must implement a member function <CODE>close</CODE>. You must also give your filter a <A HREF="../guide/traits.html#category_tags">category tag</A> convertible to <A HREF="../guide/traits.html#category_tags"><CODE>closable_tag</CODE></A>, to tell the Iostream library that your filter implements <CODE>close</CODE>.
</P>
<P>The improved Filter looks like this:</P>
<PRE CLASS="broken_ie"><SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
<SPAN CLASS="keyword">class</SPAN> shell_comments_input_filter : <SPAN CLASS='keyword'>public</SPAN> input_filter {
<SPAN CLASS="keyword">public</SPAN>:
shell_comments_input_filter();
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
<SPAN CLASS="keyword">int</SPAN> get(Source& src);
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
<SPAN CLASS="keyword">void</SPAN> close(Source&) { skip_ = <SPAN CLASS="keyword">false</SPAN>; }
<SPAN CLASS="keyword">private</SPAN>:
<SPAN CLASS="keyword">bool</SPAN> skip_;
};
} } } <SPAN CLASS='comment'>// End namespace boost::iostreams:example</SPAN></PRE>
<P>
Here I've derived from the helper class <A HREF="../classes/filter.html#synopsis"><CODE>input_filter</CODE></A>, which provides a member type <CODE>char_type</CODE> equal to <CODE>char</CODE> and a category tag convertible to <A HREF="../guide/traits.html#category_tags"><CODE>input_filter_tag</CODE></A> and to <A HREF="../guide/traits.html#category_tags"><CODE>closable_tag</CODE></A>. The implementation of <CODE>close</CODE> simply clears the <CODE>skip_</CODE> flag so that the Filter will be ready to be used again.
</P>
<A NAME="shell_comments_output_filter"></A>
<H4><CODE>shell_comments_output_filter</CODE></H4>
<P>
Next, let's express a shell comments Filter as an <A HREF="../concepts/output_filter.html">OutputFilter</A>. A typical narrow-character OutputFilter looks like this:
</P>
<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/categories.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/categories.hpp&gt;</SPAN></A>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/operations.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/operations.hpp&gt;</SPAN></A> <SPAN CLASS='comment'>// put, write</SPAN>
<SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams;
<SPAN CLASS='keyword'>class</SPAN> my_output_filter {
<SPAN CLASS='keyword'>public</SPAN>:
<SPAN CLASS='keyword'>typedef</SPAN> <SPAN CLASS='keyword'>char</SPAN> char_type;
<SPAN CLASS='keyword'>typedef</SPAN> output_filter_tag category;
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
<SPAN CLASS='keyword'>bool</SPAN> put(Sink& dest, <SPAN CLASS='keyword'>int</SPAN> c)
{
<SPAN CLASS='comment'>// Attempt to consume the given character of unfilitered</SPAN>
<SPAN CLASS='comment'>// data, writing filtered data to dest as appropriate. </SPAN>
<SPAN CLASS='comment'>// Return true if the character was successfully consumed.</SPAN>
}
<SPAN CLASS='comment'>/* Other members */</SPAN>
};</PRE>
<P>
The function <CODE>put</CODE> attempts to filter the single character <CODE>c</CODE>, writing filtered output to the <A HREF="../concepts/sink.html">Sink</A> <CODE>dest</CODE>. It accesses <CODE>dest</CODE> using the fundamental i/o operations <A HREF="../functions/put.html"><CODE>put</CODE></A> and <A HREF="../functions/write.html"><CODE>write</CODE></A>. Both of these functions may fail: <CODE>iostreams::put</CODE> can return <CODE>false</CODE>, and <CODE>iostreams::write</CODE> can consume fewer characters than requested. If this occurs, the member function <CODE>put</CODE> is allowed to return <CODE>false</CODE>, indicating that <CODE>c</CODE> could not be consumed. Otherwise, it must consume <CODE>c</CODE> and return <CODE>true</CODE>.
</P>
<P> You could also write the above example as follows:</P>
<PRE CLASS="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="HEADER" HREF="../../../../boost/iostreams/concepts.hpp"><SPAN CLASS='literal'>&lt;boost/iostreams/concepts.hpp&gt;</SPAN></A> <SPAN CLASS='comment'>// output_filter</SPAN>
<SPAN CLASS='keyword'>class</SPAN> my_output_filter : <SPAN CLASS='keyword'>public</SPAN> output_filter {
<SPAN CLASS='keyword'>public</SPAN>:
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
<SPAN CLASS='keyword'>bool</SPAN> put(Sink& dest, <SPAN CLASS='keyword'>int</SPAN> c);
<SPAN CLASS='comment'>/* Other members */</SPAN>
};</PRE>
<P>Here <A HREF="../classes/filter.html#synopsis"><CODE>output_filter</CODE></A> is a convenience base class which provides the member types <CODE>char_type</CODE> and <CODE>category</CODE>, as well as no-op implementations of member functions <CODE>close</CODE> and <CODE>imbue</CODE>.</P>
<P>You're now ready to express a shell comments Filter as an <A HREF="../concepts/output_filter.html">OutputFilter</A>:</P>
<PRE class="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/concepts.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/concepts.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// output_filter</SPAN>
<SPAN CLASS='preprocessor'>#include</SPAN> <A CLASS="header" HREF="../../../../boost/iostreams/operations.hpp"><SPAN CLASS="literal">&lt;boost/iostreams/operations.hpp&gt;</SPAN></A> <SPAN CLASS="comment">// put</SPAN>
<SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
<SPAN CLASS="keyword">class</SPAN> shell_comments_output_filter : <SPAN CLASS="keyword"><SPAN CLASS="keyword"><SPAN CLASS="keyword">public</SPAN></SPAN></SPAN> output_filter {
<SPAN CLASS="keyword">public</SPAN>:
<SPAN CLASS='keyword'>explicit</SPAN> shell_comments_output_filter(<SPAN CLASS="keyword">char</SPAN> comment_char = <SPAN CLASS='literal'>'#'</SPAN>)
: comment_char_(comment_char), skip_(<SPAN CLASS="keyword">false</SPAN>)
{ }
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
<SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> put(Sink& dest, <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c)
{
skip_ = c == comment_char_ ?
<SPAN CLASS="keyword">true</SPAN> :
c == <SPAN CLASS="literal">'\n'</SPAN> ?
<SPAN CLASS="keyword">false</SPAN> :
skip_;
<SPAN CLASS="keyword">if</SPAN> (skip_)
<SPAN CLASS="keyword">return</SPAN> <SPAN CLASS="keyword">true</SPAN>;
<SPAN CLASS="keyword">return</SPAN> iostreams::put(dest, c);
}
<SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
<SPAN CLASS="keyword">void</SPAN> close(Source&) { skip_ = <SPAN CLASS="keyword">false</SPAN>; }
<SPAN CLASS="keyword">private</SPAN>:
<SPAN CLASS="keyword">char</SPAN> comment_char_;
<SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> skip_;
};
} } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>
<P>
The member function <CODE>put</CODE> first examines the given character <CODE>c</CODE> and updates the member variable <CODE>skip_</CODE>; next, unless <CODE>skip_</CODE> is <CODE>true</CODE>, it attempt to write c. The member function <CODE>close</CODE> simply clears the <CODE>skip_</CODE> flag so that the Filter will be ready to be used again.
</P>
<!-- Begin Nav -->
<DIV CLASS='nav'>
<A HREF='filter_usage.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/prev.png'></A>
<A HREF='tutorial.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/up.png'></A>
<A HREF='line_wrapping_filters.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/next.png'></A>
</DIV>
<!-- End Nav -->
<!-- Begin Footer -->
<HR>
<P CLASS="copyright">Revised 02 Feb 2008</P>
<P CLASS="copyright">&copy; Copyright 2008 <a href="http://www.coderage.com/" target="_top">CodeRage, LLC</a><br/>&copy; Copyright 2004-2007 <a href="http://www.coderage.com/turkanis/" target="_top">Jonathan Turkanis</a></P>
<P CLASS="copyright">
Use, modification, and distribution are subject to the Boost Software License, Version 2.0. (See accompanying file <A HREF="../../../../LICENSE_1_0.txt">LICENSE_1_0.txt</A> or copy at <A HREF="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</A>)
</P>
<!-- End Footer -->
</BODY>