Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / iostreams / doc / tutorial / shell_comments_filters.html
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2 <HTML>
3 <HEAD>
4     <TITLE>Tutorial</TITLE>
5     <LINK REL="stylesheet" HREF="../../../../boost.css">
6     <LINK REL="stylesheet" HREF="../theme/iostreams.css">
7 </HEAD>
8 <BODY>
9
10 <!-- Begin Banner -->
11
12     <H1 CLASS="title">Tutorial</H1>
13     <HR CLASS="banner">
14
15 <!-- End Banner -->
16
17 <!-- Begin Nav -->
18
19 <DIV CLASS='nav'>
20     <A HREF='filter_usage.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/prev.png'></A>
21     <A HREF='tutorial.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/up.png'></A>
22     <A HREF='line_wrapping_filters.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/next.png'></A>
23 </DIV>
24
25 <!-- End Nav -->
26
27
28 <A NAME="shell_comments"></A>
29 <H2>2.2.3. Shell Comments Filters</H2>
30
31 <P>
32     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.
33 </P>
34
35 <P>
36     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>).
37 </P>
38
39 <A NAME="shell_comments_stdio_filter"></A>
40 <H4><CODE>shell_comments_stdio_filter</CODE></H4>
41
42 <P>You can express a shell comments Filter as a <A HREF="../classes/stdio_filter.html"><CODE>stdio_filter</CODE></A> as follows:</P>
43
44 <PRE class="broken_ie"><SPAN CLASS='preprocessor'>#include</SPAN> <SPAN CLASS="literal">&lt;cstdio&gt;</SPAN>    <SPAN CLASS="comment">// EOF</SPAN>
45 <SPAN CLASS="preprocessor">#include</SPAN> <SPAN CLASS="literal">&lt;iostream&gt;</SPAN>  <SPAN CLASS="comment">// cin, cout</SPAN>
46 <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>
47
48 <SPAN CLASS="keyword">class</SPAN> shell_comments_stdio_filter : <SPAN CLASS="keyword"><SPAN CLASS="keyword"><SPAN CLASS="keyword">public</SPAN></SPAN></SPAN> stdio_filter {
49 <SPAN CLASS="keyword">public</SPAN>:
50     explicit shell_comments_stdio_filter(<SPAN CLASS="keyword">char</SPAN> comment_char = <SPAN CLASS="literal">'#'</SPAN>)
51         : comment_char_(comment_char) 
52         { }
53 <SPAN CLASS="keyword">private</SPAN>:
54     <SPAN CLASS="keyword">void</SPAN> do_filter()
55     {
56         <SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN>  skip = <SPAN CLASS="keyword">false</SPAN>;
57         <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN>   c;
58         <SPAN CLASS="keyword">while</SPAN> ((c = std::cin.get()) != <SPAN CLASS="numeric_literal">EOF</SPAN>) {
59             skip = c == comment_char_ ?
60                 <SPAN CLASS="keyword">true</SPAN> :
61                 c == <SPAN CLASS="literal">'\n'</SPAN> ?
62                     <SPAN CLASS="keyword">false</SPAN> :
63                     skip;
64             <SPAN CLASS="keyword">if</SPAN> (!skip)
65                 std::cout.put(c);
66         }
67     }
68     <SPAN CLASS="keyword">char</SPAN> comment_char_;
69 };
70
71 } } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>
72
73 <P>
74     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>.
75 </P>
76
77 <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.
78
79 <A NAME="shell_comments_input_filter"></A>
80 <H4><CODE>shell_comments_input_filter</CODE></H4>
81
82 <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>
83
84 <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>
85 <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>
86 <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>
87
88 <SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams;
89
90 <SPAN CLASS='keyword'>class</SPAN> my_input_filter {
91 <SPAN CLASS='keyword'>public</SPAN>:
92     <SPAN CLASS='keyword'>typedef</SPAN> <SPAN CLASS='keyword'>char</SPAN>              char_type;
93     <SPAN CLASS='keyword'>typedef</SPAN> input_filter_tag  category;
94
95     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
96     <SPAN CLASS='keyword'>int</SPAN> get(Source&amp; src)
97     {
98         <SPAN CLASS='comment'>// Attempt to produce one character of filtered</SPAN>
99         <SPAN CLASS='comment'>// data, reading from src as necessary. If successful,</SPAN>
100         <SPAN CLASS='comment'>// return the character; otherwise return EOF to</SPAN>
101         <SPAN CLASS='comment'>// indicate end-of-stream, or WOULD_BLOCK</SPAN>
102     }
103
104     <SPAN CLASS='comment'>/* Other members */</SPAN>
105 };</PRE>
106
107 <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>
108
109 <P> You could also write the above example as follows:</P>
110
111 <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>
112
113 <SPAN CLASS='keyword'>class</SPAN> my_input_filter : <SPAN CLASS='keyword'>public</SPAN> input_filter {
114 <SPAN CLASS='keyword'>public</SPAN>:
115     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
116     <SPAN CLASS='keyword'>int</SPAN> get(Source&amp; src);
117
118     <SPAN CLASS='comment'>/* Other members */</SPAN>
119 };</PRE>
120
121 <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.
122
123 <P>You're now ready to express a shell Comments Filter as an <A HREF="../concepts/input_filter.html">InputFilter</A>:</P>
124
125 <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>
126 <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>
127 <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>
128
129 <SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
130
131 <SPAN CLASS="keyword">class</SPAN> shell_comments_input_filter : <SPAN CLASS="keyword"><SPAN CLASS="keyword"><SPAN CLASS="keyword">public</SPAN></SPAN></SPAN> input_filter {
132 <SPAN CLASS="keyword">public</SPAN>:
133     explicit shell_comments_input_filter(<SPAN CLASS="keyword">char</SPAN> comment_char = <SPAN CLASS="literal">'#'</SPAN>)
134         : comment_char_(comment_char), skip_(<SPAN CLASS="keyword">false</SPAN>)
135         { }
136
137     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
138     <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> get(Source&amp; src)
139     {
140         <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c;
141         <SPAN CLASS="keyword">while</SPAN> (<SPAN CLASS="keyword">true</SPAN>) {
142             <SPAN CLASS="keyword">if</SPAN> ((c = boost::iostreams::get(src)) == <SPAN CLASS="numeric_literal">EOF</SPAN> || c == WOULD_BLOCK)
143                 break;
144             skip_ = c == comment_char_ ?
145                 <SPAN CLASS="keyword">true</SPAN> :
146                 c == <SPAN CLASS="literal">'\n'</SPAN> ?
147                     <SPAN CLASS="keyword">false</SPAN> :
148                     skip_;
149             <SPAN CLASS="keyword">if</SPAN> (!skip_)
150                 break;
151         }
152         <SPAN CLASS="keyword">return</SPAN> c;
153     }
154
155     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
156     <SPAN CLASS="keyword">void</SPAN> close(Source&amp;) { skip_ = <SPAN CLASS="keyword">false</SPAN>; }
157 <SPAN CLASS="keyword">private</SPAN>:
158     <SPAN CLASS="keyword">char</SPAN> comment_char_;
159     <SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> skip_;
160 };
161
162 } } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>
163
164 <P>
165     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.
166 </P>
167 <P>
168     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>.
169 </P>
170 <P>
171     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.
172 </P>
173 <P>
174     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>.
175 </P>
176
177 <P>The improved Filter looks like this:</P>
178
179 <PRE CLASS="broken_ie"><SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
180
181 <SPAN CLASS="keyword">class</SPAN> shell_comments_input_filter : <SPAN CLASS='keyword'>public</SPAN> input_filter {
182 <SPAN CLASS="keyword">public</SPAN>:
183     shell_comments_input_filter();
184
185     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
186     <SPAN CLASS="keyword">int</SPAN> get(Source&amp; src);
187
188     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
189     <SPAN CLASS="keyword">void</SPAN> close(Source&amp;) { skip_ = <SPAN CLASS="keyword">false</SPAN>; }
190 <SPAN CLASS="keyword">private</SPAN>:
191     <SPAN CLASS="keyword">bool</SPAN> skip_;
192 };
193
194 } } } <SPAN CLASS='comment'>// End namespace boost::iostreams:example</SPAN></PRE>
195
196 <P>
197     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.
198 </P>
199
200 <A NAME="shell_comments_output_filter"></A>
201 <H4><CODE>shell_comments_output_filter</CODE></H4>
202
203 <P>
204     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:
205 </P>
206
207 <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>  
208 <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>
209
210 <SPAN CLASS='keyword'>namespace</SPAN> io = boost::iostreams;
211
212 <SPAN CLASS='keyword'>class</SPAN> my_output_filter {
213 <SPAN CLASS='keyword'>public</SPAN>:
214     <SPAN CLASS='keyword'>typedef</SPAN> <SPAN CLASS='keyword'>char</SPAN>               char_type;
215     <SPAN CLASS='keyword'>typedef</SPAN> output_filter_tag  category;
216
217     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
218     <SPAN CLASS='keyword'>bool</SPAN> put(Sink&amp; dest, <SPAN CLASS='keyword'>int</SPAN> c)
219     {
220         <SPAN CLASS='comment'>// Attempt to consume the given character of unfiltered</SPAN>
221         <SPAN CLASS='comment'>// data, writing filtered data to dest as appropriate. </SPAN>
222         <SPAN CLASS='comment'>// Return true if the character was successfully consumed.</SPAN>
223     }
224
225     <SPAN CLASS='comment'>/* Other members */</SPAN>
226 };</PRE>
227
228 <P>
229     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>.
230 </P>
231
232 <P> You could also write the above example as follows:</P>
233
234 <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>
235
236 <SPAN CLASS='keyword'>class</SPAN> my_output_filter : <SPAN CLASS='keyword'>public</SPAN> output_filter {
237 <SPAN CLASS='keyword'>public</SPAN>:
238     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
239     <SPAN CLASS='keyword'>bool</SPAN> put(Sink&amp; dest, <SPAN CLASS='keyword'>int</SPAN> c);
240
241     <SPAN CLASS='comment'>/* Other members */</SPAN>
242 };</PRE>
243
244 <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>
245
246 <P>You're now ready to express a shell comments Filter as an <A HREF="../concepts/output_filter.html">OutputFilter</A>:</P>
247
248 <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>
249 <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>
250
251 <SPAN CLASS='keyword'>namespace</SPAN> boost { <SPAN CLASS='keyword'>namespace</SPAN> iostreams { <SPAN CLASS='keyword'>namespace</SPAN> example {
252
253 <SPAN CLASS="keyword">class</SPAN> shell_comments_output_filter : <SPAN CLASS="keyword"><SPAN CLASS="keyword"><SPAN CLASS="keyword">public</SPAN></SPAN></SPAN> output_filter {
254 <SPAN CLASS="keyword">public</SPAN>:
255     <SPAN CLASS='keyword'>explicit</SPAN> shell_comments_output_filter(<SPAN CLASS="keyword">char</SPAN> comment_char = <SPAN CLASS='literal'>'#'</SPAN>)
256         : comment_char_(comment_char), skip_(<SPAN CLASS="keyword">false</SPAN>)
257         { }
258
259     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Sink&gt;
260     <SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> put(Sink&amp; dest, <SPAN CLASS="keyword"><SPAN CLASS="keyword">int</SPAN></SPAN> c)
261     {
262         skip_ = c == comment_char_ ?
263             <SPAN CLASS="keyword">true</SPAN> :
264             c == <SPAN CLASS="literal">'\n'</SPAN> ?
265                 <SPAN CLASS="keyword">false</SPAN> :
266                 skip_;
267
268         <SPAN CLASS="keyword">if</SPAN> (skip_)
269             <SPAN CLASS="keyword">return</SPAN> <SPAN CLASS="keyword">true</SPAN>;
270
271         <SPAN CLASS="keyword">return</SPAN> iostreams::put(dest, c);
272     }
273
274     <SPAN CLASS="keyword">template</SPAN>&lt;<SPAN CLASS="keyword">typename</SPAN> Source&gt;
275     <SPAN CLASS="keyword">void</SPAN> close(Source&amp;) { skip_ = <SPAN CLASS="keyword">false</SPAN>; }
276 <SPAN CLASS="keyword">private</SPAN>:
277     <SPAN CLASS="keyword">char</SPAN> comment_char_;
278     <SPAN CLASS="keyword"><SPAN CLASS="keyword">bool</SPAN></SPAN> skip_;
279 };
280
281 } } } <SPAN CLASS="comment">// End namespace boost::iostreams:example</SPAN></PRE>
282
283 <P>
284     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.
285 </P>
286
287 <!-- Begin Nav -->
288
289 <DIV CLASS='nav'>
290     <A HREF='filter_usage.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/prev.png'></A>
291     <A HREF='tutorial.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/up.png'></A>
292     <A HREF='line_wrapping_filters.html'><IMG BORDER=0 WIDTH=19 HEIGHT=19 SRC='../../../../doc/src/images/next.png'></A>
293 </DIV>
294
295 <!-- End Nav -->
296
297 <!-- Begin Footer -->
298
299 <HR>
300
301
302 <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>
303 <P CLASS="copyright"> 
304     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>)
305 </P>
306 <!-- End Footer -->
307
308 </BODY>