2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if !defined( INCLUDED_STREAM_TEXTSTREAM_H )
23 #define INCLUDED_STREAM_TEXTSTREAM_H
26 /// \brief Text-output-formatting.
28 #include "itextstream.h"
37 #include "generic/arrayrange.h"
39 namespace TextOutputDetail
41 inline char* write_unsigned_nonzero_decimal_backward( char* ptr, unsigned int decimal ){
42 for (; decimal != 0; decimal /= 10 )
44 *--ptr = char('0' + int(decimal % 10) );
49 #if defined ( _WIN64 ) || defined ( __LP64__ )
50 inline char* write_size_t_nonzero_decimal_backward( char* ptr, size_t decimal ){
51 for (; decimal != 0; decimal /= 10 )
53 *--ptr = char('0' + (size_t)( decimal % 10 ) );
59 inline char* write_signed_nonzero_decimal_backward( char* ptr, int decimal, bool show_positive ){
60 const bool negative = decimal < 0 ;
61 ptr = write_unsigned_nonzero_decimal_backward( ptr, negative ? -decimal : decimal );
65 else if ( show_positive ) {
71 inline char* write_unsigned_nonzero_decimal_backward( char* ptr, unsigned int decimal, bool show_positive ){
72 ptr = write_unsigned_nonzero_decimal_backward( ptr, decimal );
73 if ( show_positive ) {
79 #if defined ( _WIN64 ) || defined ( __LP64__ )
80 inline char* write_size_t_nonzero_decimal_backward( char* ptr, size_t decimal, bool show_positive ){
81 ptr = write_size_t_nonzero_decimal_backward( ptr, decimal );
82 if ( show_positive ) {
89 inline char* write_signed_decimal_backward( char* ptr, int decimal, bool show_positive ){
95 ptr = write_signed_nonzero_decimal_backward( ptr, decimal, show_positive );
100 inline char* write_unsigned_decimal_backward( char* ptr, unsigned int decimal, bool show_positive ){
101 if ( decimal == 0 ) {
106 ptr = write_unsigned_nonzero_decimal_backward( ptr, decimal, show_positive );
111 #if defined ( _WIN64 ) || defined ( __LP64__ )
112 inline char* write_size_t_decimal_backward( char* ptr, size_t decimal, bool show_positive ){
113 if ( decimal == 0 ) {
118 ptr = write_size_t_nonzero_decimal_backward( ptr, decimal, show_positive );
127 #define snprintf _snprintf
130 /// \brief Writes a single character \p c to \p ostream.
131 template<typename TextOutputStreamType>
132 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, char c ){
133 ostream.write( &c, 1 );
137 /// \brief Writes a double-precision floating point value \p d to \p ostream.
138 /// The value will be formatted either as decimal with trailing zeros removed, or with scientific 'e' notation, whichever is shorter.
139 template<typename TextOutputStreamType>
140 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const double d ){
141 const std::size_t bufferSize = 16;
142 char buf[bufferSize];
143 ostream.write( buf, snprintf( buf, bufferSize, "%g", d ) );
147 /// \brief Writes a single-precision floating point value \p f to \p ostream.
148 /// The value will be formatted either as decimal with trailing zeros removed, or with scientific 'e' notation, whichever is shorter.
149 template<typename TextOutputStreamType>
150 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const float f ){
151 return ostream_write( ostream, static_cast<double>( f ) );
154 /// \brief Writes a signed integer \p i to \p ostream in decimal form.
155 /// A '-' sign will be added if the value is negative.
156 template<typename TextOutputStreamType>
157 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const int i ){
158 const std::size_t bufferSize = 16;
160 char buf[bufferSize];
161 char* begin = TextOutputDetail::write_signed_decimal_backward( buf + bufferSize, i, false );
162 ostream.write( begin, ( buf + bufferSize ) - begin );
164 char buf[bufferSize];
165 ostream.write( buf, snprintf( buf, bufferSize, "%i", i ) );
170 typedef unsigned int Unsigned;
172 /// \brief Writes an unsigned integer \p i to \p ostream in decimal form.
173 template<typename TextOutputStreamType>
174 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const Unsigned i ){
175 const std::size_t bufferSize = 16;
177 char buf[bufferSize];
178 char* begin = TextOutputDetail::write_unsigned_decimal_backward( buf + bufferSize, i, false );
179 ostream.write( begin, ( buf + bufferSize ) - begin );
181 char buf[bufferSize];
182 ostream.write( buf, snprintf( buf, bufferSize, "%u", i ) );
187 #if defined ( _WIN64 ) || defined ( __LP64__ )
189 /// \brief Writes a size_t \p i to \p ostream in decimal form.
190 template<typename TextOutputStreamType>
191 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const size_t i ){
192 // max is 18446744073709551615, buffer of 32 chars should always be enough
193 const std::size_t bufferSize = 32;
195 char buf[bufferSize];
196 char* begin = TextOutputDetail::write_size_t_decimal_backward( buf + bufferSize, i, false );
197 ostream.write( begin, ( buf + bufferSize ) - begin );
199 char buf[bufferSize];
200 ostream.write( buf, snprintf( buf, bufferSize, "%u", i ) );
207 /// \brief Writes a null-terminated \p string to \p ostream.
208 template<typename TextOutputStreamType>
209 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const char* string ){
210 ostream.write( string, strlen( string ) );
218 HexChar( char value ) : m_value( value ){
222 /// \brief Writes a single character \p c to \p ostream in hexadecimal form.
223 template<typename TextOutputStreamType>
224 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const HexChar& c ){
225 const std::size_t bufferSize = 16;
226 char buf[bufferSize];
227 ostream.write( buf, snprintf( buf, bufferSize, "%X", c.m_value & 0xFF ) );
237 FloatFormat( double f, int width, int precision )
238 : m_f( f ), m_width( width ), m_precision( precision ){
242 /// \brief Writes a floating point value to \p ostream with a specific width and precision.
243 template<typename TextOutputStreamType>
244 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const FloatFormat& formatted ){
245 const std::size_t bufferSize = 32;
246 char buf[bufferSize];
247 ostream.write( buf, snprintf( buf, bufferSize, "%*.*lf", formatted.m_width, formatted.m_precision, formatted.m_f ) );
251 // never displays exponent, prints up to 10 decimal places
256 Decimal( double f ) : m_f( f ){
260 /// \brief Writes a floating point value to \p ostream in decimal form with trailing zeros removed.
261 template<typename TextOutputStreamType>
262 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const Decimal& decimal ){
263 const int bufferSize = 22;
264 char buf[bufferSize];
265 std::size_t length = snprintf( buf, bufferSize, "%10.10lf", decimal.m_f );
266 const char* first = buf;
267 for (; *first == ' '; ++first )
270 const char* last = buf + length - 1;
271 for (; *last == '0'; --last )
274 if ( *last == '.' ) {
277 ostream.write( first, last - first + 1 );
282 /// \brief Writes a \p range of characters to \p ostream.
283 template<typename TextOutputStreamType>
284 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const StringRange& range ){
285 ostream.write( range.first, range.last - range.first );
289 template<typename Type>
294 Quoted( const Type& type )
299 template<typename Type>
300 inline Quoted<Type> makeQuoted( const Type& type ){
301 return Quoted<Type>( type );
304 /// \brief Writes any type to \p ostream with a quotation mark character before and after it.
305 template<typename TextOutputStreamType, typename Type>
306 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const Quoted<Type>& quoted ){
307 return ostream << '"' << quoted.m_type << '"';
314 const char* m_string;
315 LowerCase( const char* string ) : m_string( string ){
319 /// \brief Writes a string to \p ostream converted to lower-case.
320 template<typename TextOutputStreamType>
321 inline TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const LowerCase& lower ){
322 for ( const char* p = lower.m_string; *p != '\0'; ++p )
324 ostream << static_cast<char>( std::tolower( *p ) );
330 /// \brief A wrapper for a TextInputStream optimised for reading a single character at a time.
331 template<typename TextInputStreamType, int SIZE = 1024>
332 class SingleCharacterInputStream
334 TextInputStreamType& m_inputStream;
340 m_end = m_buffer + m_inputStream.read( m_buffer, SIZE );
342 return m_cur != m_end;
346 SingleCharacterInputStream( TextInputStreamType& inputStream ) : m_inputStream( inputStream ), m_cur( m_buffer ), m_end( m_buffer ){
348 bool readChar( char& c ){
349 if ( m_cur == m_end && !fillBuffer() ) {
358 /// \brief A wrapper for a TextOutputStream, optimised for writing a single character at a time.
359 class SingleCharacterOutputStream : public TextOutputStream
361 enum unnamed0 { m_bufsize = 1024 };
362 TextOutputStream& m_ostream;
363 char m_buffer[m_bufsize];
367 const char* end() const {
374 m_ostream.write( m_buffer, m_pos - m_buffer );
378 SingleCharacterOutputStream( TextOutputStream& ostream ) : m_ostream( ostream ), m_pos( m_buffer ), m_end( m_buffer + m_bufsize ){
380 ~SingleCharacterOutputStream(){
383 void write( const char c ){
384 if ( m_pos == end() ) {
389 std::size_t write( const char* buffer, std::size_t length ){
390 const char*const end = buffer + length;
391 for ( const char* p = buffer; p != end; ++p )
399 /// \brief A wrapper for a TextOutputStream, optimised for writing a few characters at a time.
400 template<typename TextOutputStreamType, int SIZE = 1024>
401 class BufferedTextOutputStream : public TextOutputStream
403 TextOutputStreamType outputStream;
408 BufferedTextOutputStream( TextOutputStreamType& outputStream ) : outputStream( outputStream ), m_cur( m_buffer ){
410 ~BufferedTextOutputStream(){
411 outputStream.write( m_buffer, m_cur - m_buffer );
413 std::size_t write( const char* buffer, std::size_t length ){
414 std::size_t remaining = length;
417 std::size_t n = std::min( remaining, std::size_t( ( m_buffer + SIZE ) - m_cur ) );
418 m_cur = std::copy( buffer, buffer + n, m_cur );
420 if ( remaining == 0 ) {
423 outputStream.write( m_buffer, SIZE );