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_STRINGIO_H )
23 #define INCLUDED_STRINGIO_H
28 #include "generic/vector.h"
29 #include "iscriplib.h"
30 #include "string/string.h"
31 #include "generic/callback.h"
33 inline float string_read_float( const char* string ){
34 return static_cast<float>( atof( string ) );
37 inline int string_read_int( const char* string ){
38 return atoi( string );
41 inline bool char_is_whitespace( char c ){
42 return c == ' ' || c == '\t';
45 inline const char* string_remove_whitespace( const char* string ){
48 if ( !char_is_whitespace( *string ) ) {
56 inline const char* string_remove_zeros( const char* string ){
68 inline const char* string_remove_sign( const char* string ){
69 if ( *string == '-' || *string == '+' ) { // signed zero - acceptable
75 inline bool string_is_unsigned_zero( const char* string ){
76 for (; *string != '\0'; ++string )
78 if ( *string != '0' ) {
85 inline bool string_is_signed_zero( const char* string ){
86 return string_is_unsigned_zero( string_remove_sign( string ) );
89 //[whitespaces][+|-][nnnnn][.nnnnn][e|E[+|-]nnnn]
90 //(where whitespaces are any tab or space character and nnnnn may be any number of digits)
91 inline bool string_is_float_zero( const char* string ){
92 string = string_remove_whitespace( string );
93 if ( string_empty( string ) ) {
97 string = string_remove_sign( string );
98 if ( string_empty( string ) ) {
99 // no whole number or fraction part
104 string = string_remove_zeros( string );
105 if ( string_empty( string ) ) {
106 // no fraction or exponent
109 if ( *string == '.' ) {
111 if ( *string++ != '0' ) {
115 string = string_remove_zeros( ++string );
116 if ( string_empty( string ) ) {
121 if ( *string == 'e' || *string == 'E' ) {
123 string = string_remove_sign( ++string );
124 if ( *string++ != '0' ) {
128 string = string_remove_zeros( ++string );
129 if ( string_empty( string ) ) {
130 // no trailing whitespace
134 string = string_remove_whitespace( string );
135 return string_empty( string );
138 inline double buffer_parse_floating_literal( const char*& buffer ){
139 return strtod( buffer, const_cast<char**>( &buffer ) );
142 inline int buffer_parse_signed_decimal_integer_literal( const char*& buffer ){
143 return strtol( buffer, const_cast<char**>( &buffer ), 10 );
146 inline int buffer_parse_unsigned_decimal_integer_literal( const char*& buffer ){
147 return strtoul( buffer, const_cast<char**>( &buffer ), 10 );
150 // [+|-][nnnnn][.nnnnn][e|E[+|-]nnnnn]
151 inline bool string_parse_float( const char* string, float& f ){
152 if ( string_empty( string ) ) {
155 f = float(buffer_parse_floating_literal( string ) );
156 return string_empty( string );
159 // format same as float
160 inline bool string_parse_double( const char* string, double& f ){
161 if ( string_empty( string ) ) {
164 f = buffer_parse_floating_literal( string );
165 return string_empty( string );
168 // <float><space><float><space><float>
169 template<typename Element>
170 inline bool string_parse_vector3( const char* string, BasicVector3<Element>& v ){
171 if ( string_empty( string ) || *string == ' ' ) {
174 v[0] = float(buffer_parse_floating_literal( string ) );
175 if ( *string++ != ' ' ) {
178 v[1] = float(buffer_parse_floating_literal( string ) );
179 if ( *string++ != ' ' ) {
182 v[2] = float(buffer_parse_floating_literal( string ) );
183 return string_empty( string );
186 template<typename Float>
187 inline bool string_parse_vector( const char* string, Float* first, Float* last ){
188 if ( first != last && ( string_empty( string ) || *string == ' ' ) ) {
193 *first = float(buffer_parse_floating_literal( string ) );
194 if ( ++first == last ) {
195 return string_empty( string );
197 if ( *string++ != ' ' ) {
203 // decimal signed integer
204 inline bool string_parse_int( const char* string, int& i ){
205 if ( string_empty( string ) ) {
208 i = buffer_parse_signed_decimal_integer_literal( string );
209 return string_empty( string );
212 // decimal unsigned integer
213 inline bool string_parse_size( const char* string, std::size_t& i ){
214 if ( string_empty( string ) ) {
217 i = buffer_parse_unsigned_decimal_integer_literal( string );
218 return string_empty( string );
222 #define RETURN_FALSE_IF_FAIL( expression ) if ( !expression ) {return false; }else
224 inline void Tokeniser_unexpectedError( Tokeniser& tokeniser, const char* token, const char* expected ){
225 globalErrorStream() << Unsigned( tokeniser.getLine() ) << ":" << Unsigned( tokeniser.getColumn() ) << ": parse error at '" << ( token != 0 ? token : "#EOF" ) << "': expected '" << expected << "'\n";
229 inline bool Tokeniser_getFloat( Tokeniser& tokeniser, float& f ){
230 const char* token = tokeniser.getToken();
231 if ( token != 0 && string_parse_float( token, f ) ) {
234 //fallback for 1.#IND 1.#INF 1.#QNAN cases, happening sometimes after rotating & often scaling with tex lock in BP mode
235 else if ( token != 0 && strstr( token, ".#" ) ) {
236 globalErrorStream() << "Warning: " << Unsigned( tokeniser.getLine() ) << ":" << Unsigned( tokeniser.getColumn() ) << ": expected parse problem at '" << token << "': wanted '#number'\nProcessing anyway\n";
237 // *strstr( token, ".#" ) = '\0';
240 Tokeniser_unexpectedError( tokeniser, token, "#number" );
244 inline bool Tokeniser_getDouble( Tokeniser& tokeniser, double& f ){
245 const char* token = tokeniser.getToken();
246 if ( token != 0 && string_parse_double( token, f ) ) {
249 Tokeniser_unexpectedError( tokeniser, token, "#number" );
253 inline bool Tokeniser_getInteger( Tokeniser& tokeniser, int& i ){
254 const char* token = tokeniser.getToken();
255 if ( token != 0 && string_parse_int( token, i ) ) {
258 Tokeniser_unexpectedError( tokeniser, token, "#integer" );
262 inline bool Tokeniser_getSize( Tokeniser& tokeniser, std::size_t& i ){
263 const char* token = tokeniser.getToken();
264 if ( token != 0 && string_parse_size( token, i ) ) {
267 Tokeniser_unexpectedError( tokeniser, token, "#unsigned-integer" );
271 inline bool Tokeniser_parseToken( Tokeniser& tokeniser, const char* expected ){
272 const char* token = tokeniser.getToken();
273 if ( token != 0 && string_equal( token, expected ) ) {
276 Tokeniser_unexpectedError( tokeniser, token, expected );
280 inline bool Tokeniser_nextTokenIsDigit( Tokeniser& tokeniser ){
281 const char* token = tokeniser.getToken();
286 tokeniser.ungetToken();
287 return std::isdigit( c ) != 0;
290 template<typename TextOutputStreamType>
291 inline TextOutputStreamType& ostream_write( TextOutputStreamType& outputStream, const Vector3& v ){
292 return outputStream << '(' << v.x() << ' ' << v.y() << ' ' << v.z() << ')';
298 inline void CopiedString_importString( CopiedString& self, const char* string ){
301 typedef ReferenceCaller1<CopiedString, const char*, CopiedString_importString> CopiedStringImportStringCaller;
302 inline void CopiedString_exportString( const CopiedString& self, const StringImportCallback& importer ){
303 importer( self.c_str() );
305 typedef ConstReferenceCaller1<CopiedString, const StringImportCallback&, CopiedString_exportString> CopiedStringExportStringCaller;
307 inline void Bool_importString( bool& self, const char* string ){
308 self = string_equal( string, "true" );
310 typedef ReferenceCaller1<bool, const char*, Bool_importString> BoolImportStringCaller;
311 inline void Bool_exportString( const bool& self, const StringImportCallback& importer ){
312 importer( self ? "true" : "false" );
314 typedef ConstReferenceCaller1<bool, const StringImportCallback&, Bool_exportString> BoolExportStringCaller;
316 inline void Int_importString( int& self, const char* string ){
317 if ( !string_parse_int( string, self ) ) {
321 typedef ReferenceCaller1<int, const char*, Int_importString> IntImportStringCaller;
322 inline void Int_exportString( const int& self, const StringImportCallback& importer ){
324 sprintf( buffer, "%d", self );
327 typedef ConstReferenceCaller1<int, const StringImportCallback&, Int_exportString> IntExportStringCaller;
329 inline void Size_importString( std::size_t& self, const char* string ){
331 if ( string_parse_int( string, i ) && i >= 0 ) {
339 typedef ReferenceCaller1<std::size_t, const char*, Size_importString> SizeImportStringCaller;
340 inline void Size_exportString( const std::size_t& self, const StringImportCallback& importer ){
342 sprintf( buffer, "%u", Unsigned( self ) );
345 typedef ConstReferenceCaller1<std::size_t, const StringImportCallback&, Size_exportString> SizeExportStringCaller;
347 inline void Float_importString( float& self, const char* string ){
348 if ( !string_parse_float( string, self ) ) {
352 typedef ReferenceCaller1<float, const char*, Float_importString> FloatImportStringCaller;
353 inline void Float_exportString( const float& self, const StringImportCallback& importer ){
355 sprintf( buffer, "%g", self );
358 typedef ConstReferenceCaller1<float, const StringImportCallback&, Float_exportString> FloatExportStringCaller;
360 inline void Vector3_importString( Vector3& self, const char* string ){
361 if ( !string_parse_vector3( string, self ) ) {
362 self = Vector3( 0, 0, 0 );
365 typedef ReferenceCaller1<Vector3, const char*, Vector3_importString> Vector3ImportStringCaller;
366 inline void Vector3_exportString( const Vector3& self, const StringImportCallback& importer ){
368 sprintf( buffer, "%g %g %g", self[0], self[1], self[2] );
371 typedef ConstReferenceCaller1<Vector3, const StringImportCallback&, Vector3_exportString> Vector3ExportStringCaller;
375 template<typename FirstArgument, typename Caller, typename FirstConversion>
379 static void thunk( void* environment, FirstArgument firstArgument ){
380 Caller::thunk( environment, FirstConversion( firstArgument ) );
389 BoolFromString( const char* string ){
390 Bool_importString( m_value, string );
392 operator bool() const
398 inline void Bool_toString( const StringImportCallback& self, bool value ){
399 Bool_exportString( value, self );
401 typedef ConstReferenceCaller1<StringImportCallback, bool, Bool_toString> BoolToString;
404 template<typename Caller>
405 inline StringImportCallback makeBoolStringImportCallback( const Caller& caller ){
406 return StringImportCallback( caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type, Caller, BoolFromString>::thunk );
409 template<typename Caller>
410 inline StringExportCallback makeBoolStringExportCallback( const Caller& caller ){
411 return StringExportCallback( caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type, Caller, BoolToString>::thunk );
419 IntFromString( const char* string ){
420 Int_importString( m_value, string );
428 inline void Int_toString( const StringImportCallback& self, int value ){
429 Int_exportString( value, self );
431 typedef ConstReferenceCaller1<StringImportCallback, int, Int_toString> IntToString;
434 template<typename Caller>
435 inline StringImportCallback makeIntStringImportCallback( const Caller& caller ){
436 return StringImportCallback( caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type, Caller, IntFromString>::thunk );
439 template<typename Caller>
440 inline StringExportCallback makeIntStringExportCallback( const Caller& caller ){
441 return StringExportCallback( caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type, Caller, IntToString>::thunk );
450 SizeFromString( const char* string ){
451 Size_importString( m_value, string );
453 operator std::size_t() const
459 inline void Size_toString( const StringImportCallback& self, std::size_t value ){
460 Size_exportString( value, self );
462 typedef ConstReferenceCaller1<StringImportCallback, std::size_t, Size_toString> SizeToString;
465 template<typename Caller>
466 inline StringImportCallback makeSizeStringImportCallback( const Caller& caller ){
467 return StringImportCallback( caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type, Caller, SizeFromString>::thunk );
470 template<typename Caller>
471 inline StringExportCallback makeSizeStringExportCallback( const Caller& caller ){
472 return StringExportCallback( caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type, Caller, SizeToString>::thunk );