E-MailRelay
gfbuf.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gfbuf.h
19///
20
21#ifndef G_FBUF_H
22#define G_FBUF_H
23
24#include "gdef.h"
25#include <streambuf>
26#include <functional>
27#include <vector>
28
29namespace G
30{
31 template <typename T, int N=1024> class fbuf ;
32}
33
34//| \class G::fbuf
35/// A simple file streambuf using a file descriptor and three
36/// function pointers for read, write and close operations.
37/// The file descriptor type is templated to allow for non-integer
38/// file descriptors, such as std::FILE. Does not support seeking.
39///
40/// Eg:
41/// \code
42/// G::fbuf<int,1024> fbuf( ::open("temp.out",O_WRONLY) , ::read , ::write , ::close ) ;
43/// std::ostream stream( &fbuf ) ;
44/// if( fbuf.file() < 0 )
45/// stream.clear( std::ios_base::failbit ) ;
46/// stream << "hello, world!\n" ;
47/// \endcode
48///
49/// The implementation specialises std::streambuf, overriding
50/// overflow(), underflow() and sync() to operate the internal
51/// character buffer and file descriptor.
52///
53template <typename T, int N>
54class G::fbuf : public std::streambuf
55{
56public:
57 using read_fn_t = std::function<ssize_t(T,char*,std::size_t)> ;
58 using write_fn_t = std::function<ssize_t(T,const char*,std::size_t)> ;
59 using close_fn_t = std::function<void(T)> ;
60
61 explicit fbuf( read_fn_t , write_fn_t , close_fn_t ) ;
62 ///< Constructor. Use open() to initialise.
63
64 explicit fbuf( T file , read_fn_t , write_fn_t , close_fn_t ) ;
65 ///< Constructor passed an open file descriptor.
66
67 ~fbuf() override ;
68 ///< Destructor. Closes the file.
69
70 void open( T file ) ;
71 ///< Installs the given file descriptor.
72
73 T file() const ;
74 ///< Returns the current file descriptor.
75
76protected:
77 int overflow( int c ) override ;
78 ///< Called to put a character into the output buffer.
79
80 int underflow() override ;
81 ///< Called to pull a character out of the input buffer,
82 ///< and pre-fill the input buffer if necessary.
83
84 int sync() final override ;
85 ///< Called to sync the stream.
86
87public:
88 fbuf( const fbuf<T,N> & ) = delete ;
89 fbuf( fbuf<T,N> && ) = delete ;
90 fbuf<T,N> & operator=( const fbuf<T,N> & ) = delete ;
91 fbuf<T,N> & operator=( fbuf<T,N> && ) = delete ;
92
93private:
94 using traits_type = std::streambuf::traits_type ;
95 void close() ;
96
97private:
98 static constexpr int sync_ok = 0 ;
99 static constexpr int sync_fail = -1 ;
100 read_fn_t m_read_fn ;
101 write_fn_t m_write_fn ;
102 close_fn_t m_close_fn ;
103 std::vector<char> m_input ;
104 std::vector<char> m_output ;
105 bool m_file_open ;
106 T m_file ;
107} ;
108
109template <typename T,int N>
110G::fbuf<T,N>::fbuf( G::fbuf<T,N>::read_fn_t read , G::fbuf<T,N>::write_fn_t write , G::fbuf<T,N>::close_fn_t close ) :
111 m_read_fn(read) ,
112 m_write_fn(write) ,
113 m_close_fn(close) ,
114 m_input(static_cast<std::size_t>(N)) ,
115 m_output(static_cast<std::size_t>(N)) ,
116 m_file_open(false) ,
117 m_file()
118{
119}
120
121template <typename T,int N>
122G::fbuf<T,N>::fbuf( T file , G::fbuf<T,N>::read_fn_t read , G::fbuf<T,N>::write_fn_t write , G::fbuf<T,N>::close_fn_t close ) :
123 m_read_fn(read) ,
124 m_write_fn(write) ,
125 m_close_fn(close) ,
126 m_input(static_cast<std::size_t>(N)) ,
127 m_output(static_cast<std::size_t>(N)) ,
128 m_file_open(false) ,
129 m_file()
130{
131 open( file ) ;
132}
133
134namespace G
135{
136 template <typename T,int N>
138 {
139 close() ;
140 }
141}
142
143template <typename T,int N>
144void G::fbuf<T,N>::open( T file )
145{
146 close() ;
147
148 m_file = file ;
149 m_file_open = true ;
150
151 char * input_begin = &m_input[0] ;
152 setg( input_begin , input_begin , input_begin ) ;
153
154 char * output_begin = &m_output[0] ;
155 char * output_end = output_begin + m_output.size() ;
156 setp( output_begin , output_end-1 ) ;
157}
158
159template <typename T,int N>
161{
162 if( m_file_open )
163 {
164 sync() ;
165 m_close_fn( m_file ) ;
166 m_file_open = false ;
167 }
168}
169
170template <typename T,int N>
172{
173 if( !traits_type::eq_int_type( c , traits_type::eof() ) )
174 {
175 *pptr() = traits_type::to_char_type( c ) ;
176 pbump( 1 ) ;
177 }
178 return sync() == sync_fail ? traits_type::eof() : traits_type::not_eof(c) ;
179}
180
181template <typename T,int N>
183{
184 if( pbase() == pptr() )
185 {
186 return sync_ok ;
187 }
188 else
189 {
190 std::size_t size = pptr() - pbase() ;
191 ssize_t nwrite = m_write_fn( m_file , pbase() , size ) ;
192 if( nwrite <= 0 )
193 {
194 return sync_fail ;
195 }
196 else if( static_cast<std::size_t>(nwrite) < size )
197 {
198 std::copy( pbase()+nwrite , pptr() , pbase() ) ;
199 setp( pbase() , epptr() ) ; // reset pptr()
200 pbump( static_cast<int>(size-nwrite) ) ;
201 return sync_fail ;
202 }
203 else
204 {
205 setp( pbase() , epptr() ) ;
206 return sync_ok ;
207 }
208 }
209}
210
211template <typename T,int N>
213{
214 if( gptr() == egptr() )
215 {
216 char * input_begin = &m_input[0] ;
217 ssize_t nread = m_read_fn( m_file , input_begin , m_input.size() ) ;
218 if( nread <= 0 )
219 return traits_type::eof() ;
220 std::size_t nreadu = nread >= 0 ? static_cast<std::size_t>(nread) : std::size_t(0U) ;
221 setg( input_begin , input_begin , input_begin+nreadu ) ;
222 }
223 return traits_type::to_int_type( *gptr() ) ;
224}
225
226template <typename T,int N>
228{
229 return m_file ;
230}
231
232#endif
A simple file streambuf using a file descriptor and three function pointers for read,...
Definition: gfbuf.h:55
int underflow() override
Called to pull a character out of the input buffer, and pre-fill the input buffer if necessary.
Definition: gfbuf.h:212
void open(T file)
Installs the given file descriptor.
Definition: gfbuf.h:144
int sync() final override
Called to sync the stream.
Definition: gfbuf.h:182
int overflow(int c) override
Called to put a character into the output buffer.
Definition: gfbuf.h:171
fbuf(T file, read_fn_t, write_fn_t, close_fn_t)
Constructor passed an open file descriptor.
~fbuf() override
Destructor. Closes the file.
Definition: gfbuf.h:137
T file() const
Returns the current file descriptor.
Definition: gfbuf.h:227
fbuf(read_fn_t, write_fn_t, close_fn_t)
Constructor. Use open() to initialise.
Low-level classes.
Definition: garg.h:30
STL namespace.