1// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2// (C) Copyright 2005-2007 Jonathan Turkanis
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
5
6// See http://www.boost.org/libs/iostreams for documentation.
7
8// Adapted from an example of James Kanze, with suggestions from Rob Stewart.
9// See https://web.archive.org/web/20041222094942/http://www.gabi-soft.fr/codebase-en.html.
10
11#ifndef BOOST_IOSTREAMS_TAB_EXPANDING_FILTER_HPP_INCLUDED
12#define BOOST_IOSTREAMS_TAB_EXPANDING_FILTER_HPP_INCLUDED
13
14#include <cassert>
15#include <cstdio> // EOF.
16#include <iostream> // cin, cout.
17#include <boost/iostreams/concepts.hpp>
18#include <boost/iostreams/filter/stdio.hpp>
19#include <boost/iostreams/operations.hpp>
20
21namespace boost { namespace iostreams { namespace example {
22
23class tab_expanding_stdio_filter : public stdio_filter {
24public:
25 explicit tab_expanding_stdio_filter(int tab_size = 8)
26 : tab_size_(tab_size), col_no_(0)
27 {
28 assert(tab_size > 0);
29 }
30private:
31 void do_filter()
32 {
33 int c;
34 while ((c = std::cin.get()) != EOF) {
35 if (c == '\t') {
36 int spaces = tab_size_ - (col_no_ % tab_size_);
37 for (; spaces > 0; --spaces)
38 put_char(c: ' ');
39 } else {
40 put_char(c);
41 }
42 }
43 }
44 void do_close() { col_no_ = 0; }
45 void put_char(int c)
46 {
47 std::cout.put(c: c);
48 if (c == '\n') {
49 col_no_ = 0;
50 } else {
51 ++col_no_;
52 }
53 }
54 int tab_size_;
55 int col_no_;
56};
57
58class tab_expanding_input_filter : public input_filter {
59public:
60 explicit tab_expanding_input_filter(int tab_size = 8)
61 : tab_size_(tab_size), col_no_(0), spaces_(0)
62 {
63 assert(tab_size > 0);
64 }
65
66 template<typename Source>
67 int get(Source& src)
68 {
69 if (spaces_ > 0) {
70 --spaces_;
71 return get_char(c: ' ');
72 }
73
74 int c;
75 if ((c = iostreams::get(src)) == EOF || c == WOULD_BLOCK)
76 return c;
77
78 if (c != '\t')
79 return get_char(c);
80
81 // Found a tab. Call this filter recursively.
82 spaces_ = tab_size_ - (col_no_ % tab_size_);
83 return this->get(src);
84 }
85
86 template<typename Source>
87 void close(Source&)
88 {
89 col_no_ = 0;
90 spaces_ = 0;
91 }
92private:
93 int get_char(int c)
94 {
95 if (c == '\n') {
96 col_no_ = 0;
97 } else {
98 ++col_no_;
99 }
100 return c;
101 }
102 int tab_size_;
103 int col_no_;
104 int spaces_;
105};
106
107class tab_expanding_output_filter : public output_filter {
108public:
109 explicit tab_expanding_output_filter(int tab_size = 8)
110 : tab_size_(tab_size), col_no_(0), spaces_(0)
111 {
112 assert(tab_size > 0);
113 }
114
115 template<typename Sink>
116 bool put(Sink& dest, int c)
117 {
118 for (; spaces_ > 0; --spaces_)
119 if (!put_char(dest, ' '))
120 return false;
121
122 if (c == '\t') {
123 spaces_ = tab_size_ - (col_no_ % tab_size_) - 1;
124 return this->put(dest, ' ');
125 }
126
127 return put_char(dest, c);
128 }
129
130 template<typename Sink>
131 void close(Sink&)
132 {
133 col_no_ = 0;
134 spaces_ = 0;
135 }
136private:
137 template<typename Sink>
138 bool put_char(Sink& dest, int c)
139 {
140 if (!iostreams::put(dest, c))
141 return false;
142 if (c != '\n')
143 ++col_no_;
144 else
145 col_no_ = 0;
146 return true;
147 }
148 int tab_size_;
149 int col_no_;
150 int spaces_;
151};
152
153} } } // End namespaces example, iostreams, boost.
154
155#endif // #ifndef BOOST_IOSTREAMS_TAB_EXPANDING_FILTER_HPP_INCLUDED
156

source code of boost/libs/iostreams/example/tab_expanding_filter.hpp