1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4 
5    This file is part of GtkRadiant.
6 
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.
11 
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.
16 
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
20  */
21 
22 #if !defined ( INCLUDED_STRINGIO_H )
23 #define INCLUDED_STRINGIO_H
24 
25 #include <stdlib.h>
26 #include <cctype>
27 
28 #include "generic/vector.h"
29 #include "iscriplib.h"
30 #include "string/string.h"
31 #include "generic/callback.h"
32 
string_read_float(const char * string)33 inline float string_read_float( const char* string ){
34 	return static_cast<float>( atof( string ) );
35 }
36 
string_read_int(const char * string)37 inline int string_read_int( const char* string ){
38 	return atoi( string );
39 }
40 
char_is_whitespace(char c)41 inline bool char_is_whitespace( char c ){
42 	return c == ' ' || c == '\t';
43 }
44 
string_remove_whitespace(const char * string)45 inline const char* string_remove_whitespace( const char* string ){
46 	for (;; )
47 	{
48 		if ( !char_is_whitespace( *string ) ) {
49 			break;
50 		}
51 		++string;
52 	}
53 	return string;
54 }
55 
string_remove_zeros(const char * string)56 inline const char* string_remove_zeros( const char* string ){
57 	for (;; )
58 	{
59 		char c = *string;
60 		if ( c != '0' ) {
61 			break;
62 		}
63 		++string;
64 	}
65 	return string;
66 }
67 
string_remove_sign(const char * string)68 inline const char* string_remove_sign( const char* string ){
69 	if ( *string == '-' || *string == '+' ) { // signed zero - acceptable
70 		return ++string;
71 	}
72 	return string;
73 }
74 
string_is_unsigned_zero(const char * string)75 inline bool string_is_unsigned_zero( const char* string ){
76 	for (; *string != '\0'; ++string )
77 	{
78 		if ( *string != '0' ) {
79 			return false;
80 		}
81 	}
82 	return true;
83 }
84 
string_is_signed_zero(const char * string)85 inline bool string_is_signed_zero( const char* string ){
86 	return string_is_unsigned_zero( string_remove_sign( string ) );
87 }
88 
89 //[whitespaces][+|-][nnnnn][.nnnnn][e|E[+|-]nnnn]
90 //(where whitespaces are any tab or space character and nnnnn may be any number of digits)
string_is_float_zero(const char * string)91 inline bool string_is_float_zero( const char* string ){
92 	string = string_remove_whitespace( string );
93 	if ( string_empty( string ) ) {
94 		return false;
95 	}
96 
97 	string = string_remove_sign( string );
98 	if ( string_empty( string ) ) {
99 		// no whole number or fraction part
100 		return false;
101 	}
102 
103 	// whole-number part
104 	string = string_remove_zeros( string );
105 	if ( string_empty( string ) ) {
106 		// no fraction or exponent
107 		return true;
108 	}
109 	if ( *string == '.' ) {
110 		// fraction part
111 		if ( *string++ != '0' ) {
112 			// invalid fraction
113 			return false;
114 		}
115 		string = string_remove_zeros( ++string );
116 		if ( string_empty( string ) ) {
117 			// no exponent
118 			return true;
119 		}
120 	}
121 	if ( *string == 'e' || *string == 'E' ) {
122 		// exponent part
123 		string = string_remove_sign( ++string );
124 		if ( *string++ != '0' ) {
125 			// invalid exponent
126 			return false;
127 		}
128 		string = string_remove_zeros( ++string );
129 		if ( string_empty( string ) ) {
130 			// no trailing whitespace
131 			return true;
132 		}
133 	}
134 	string = string_remove_whitespace( string );
135 	return string_empty( string );
136 }
137 
buffer_parse_floating_literal(const char * & buffer)138 inline double buffer_parse_floating_literal( const char*& buffer ){
139 	return strtod( buffer, const_cast<char**>( &buffer ) );
140 }
141 
buffer_parse_signed_decimal_integer_literal(const char * & buffer)142 inline int buffer_parse_signed_decimal_integer_literal( const char*& buffer ){
143 	return strtol( buffer, const_cast<char**>( &buffer ), 10 );
144 }
145 
buffer_parse_unsigned_decimal_integer_literal(const char * & buffer)146 inline int buffer_parse_unsigned_decimal_integer_literal( const char*& buffer ){
147 	return strtoul( buffer, const_cast<char**>( &buffer ), 10 );
148 }
149 
150 // [+|-][nnnnn][.nnnnn][e|E[+|-]nnnnn]
string_parse_float(const char * string,float & f)151 inline bool string_parse_float( const char* string, float& f ){
152 	if ( string_empty( string ) ) {
153 		return false;
154 	}
155 	f = float(buffer_parse_floating_literal( string ) );
156 	return string_empty( string );
157 }
158 
159 // format same as float
string_parse_double(const char * string,double & f)160 inline bool string_parse_double( const char* string, double& f ){
161 	if ( string_empty( string ) ) {
162 		return false;
163 	}
164 	f = buffer_parse_floating_literal( string );
165 	return string_empty( string );
166 }
167 
168 // <float><space><float><space><float>
169 template<typename Element>
string_parse_vector3(const char * string,BasicVector3<Element> & v)170 inline bool string_parse_vector3( const char* string, BasicVector3<Element>& v ){
171 	if ( string_empty( string ) || *string == ' ' ) {
172 		return false;
173 	}
174 	v[0] = float(buffer_parse_floating_literal( string ) );
175 	if ( *string++ != ' ' ) {
176 		return false;
177 	}
178 	v[1] = float(buffer_parse_floating_literal( string ) );
179 	if ( *string++ != ' ' ) {
180 		return false;
181 	}
182 	v[2] = float(buffer_parse_floating_literal( string ) );
183 	return string_empty( string );
184 }
185 
186 template<typename Float>
string_parse_vector(const char * string,Float * first,Float * last)187 inline bool string_parse_vector( const char* string, Float* first, Float* last ){
188 	if ( first != last && ( string_empty( string ) || *string == ' ' ) ) {
189 		return false;
190 	}
191 	for (;; )
192 	{
193 		*first = float(buffer_parse_floating_literal( string ) );
194 		if ( ++first == last ) {
195 			return string_empty( string );
196 		}
197 		if ( *string++ != ' ' ) {
198 			return false;
199 		}
200 	}
201 }
202 
203 // decimal signed integer
string_parse_int(const char * string,int & i)204 inline bool string_parse_int( const char* string, int& i ){
205 	if ( string_empty( string ) ) {
206 		return false;
207 	}
208 	i = buffer_parse_signed_decimal_integer_literal( string );
209 	return string_empty( string );
210 }
211 
212 // decimal unsigned integer
string_parse_size(const char * string,std::size_t & i)213 inline bool string_parse_size( const char* string, std::size_t& i ){
214 	if ( string_empty( string ) ) {
215 		return false;
216 	}
217 	i = buffer_parse_unsigned_decimal_integer_literal( string );
218 	return string_empty( string );
219 }
220 
221 
222 #define RETURN_FALSE_IF_FAIL( expression ) if ( !expression ) {return false; }else
223 
Tokeniser_unexpectedError(Tokeniser & tokeniser,const char * token,const char * expected)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";
226 }
227 
228 
Tokeniser_getFloat(Tokeniser & tokeniser,float & f)229 inline bool Tokeniser_getFloat( Tokeniser& tokeniser, float& f ){
230 	const char* token = tokeniser.getToken();
231 	if ( token != 0 && string_parse_float( token, f ) ) {
232 		return true;
233 	}
234 	Tokeniser_unexpectedError( tokeniser, token, "#number" );
235 	return false;
236 }
237 
Tokeniser_getDouble(Tokeniser & tokeniser,double & f)238 inline bool Tokeniser_getDouble( Tokeniser& tokeniser, double& f ){
239 	const char* token = tokeniser.getToken();
240 	if ( token != 0 && string_parse_double( token, f ) ) {
241 		return true;
242 	}
243 	Tokeniser_unexpectedError( tokeniser, token, "#number" );
244 	return false;
245 }
246 
Tokeniser_getInteger(Tokeniser & tokeniser,int & i)247 inline bool Tokeniser_getInteger( Tokeniser& tokeniser, int& i ){
248 	const char* token = tokeniser.getToken();
249 	if ( token != 0 && string_parse_int( token, i ) ) {
250 		return true;
251 	}
252 	Tokeniser_unexpectedError( tokeniser, token, "#integer" );
253 	return false;
254 }
255 
Tokeniser_getSize(Tokeniser & tokeniser,std::size_t & i)256 inline bool Tokeniser_getSize( Tokeniser& tokeniser, std::size_t& i ){
257 	const char* token = tokeniser.getToken();
258 	if ( token != 0 && string_parse_size( token, i ) ) {
259 		return true;
260 	}
261 	Tokeniser_unexpectedError( tokeniser, token, "#unsigned-integer" );
262 	return false;
263 }
264 
Tokeniser_parseToken(Tokeniser & tokeniser,const char * expected)265 inline bool Tokeniser_parseToken( Tokeniser& tokeniser, const char* expected ){
266 	const char* token = tokeniser.getToken();
267 	if ( token != 0 && string_equal( token, expected ) ) {
268 		return true;
269 	}
270 	Tokeniser_unexpectedError( tokeniser, token, expected );
271 	return false;
272 }
273 
Tokeniser_nextTokenIsDigit(Tokeniser & tokeniser)274 inline bool Tokeniser_nextTokenIsDigit( Tokeniser& tokeniser ){
275 	const char* token = tokeniser.getToken();
276 	if ( token == 0 ) {
277 		return false;
278 	}
279 	char c = *token;
280 	tokeniser.ungetToken();
281 	return std::isdigit( c ) != 0;
282 }
283 
284 template<typename TextOutputStreamType>
ostream_write(TextOutputStreamType & outputStream,const Vector3 & v)285 inline TextOutputStreamType& ostream_write( TextOutputStreamType& outputStream, const Vector3& v ){
286 	return outputStream << '(' << v.x() << ' ' << v.y() << ' ' << v.z() << ')';
287 }
288 
289 
290 
291 
CopiedString_importString(CopiedString & self,const char * string)292 inline void CopiedString_importString( CopiedString& self, const char* string ){
293 	self = string;
294 }
295 typedef ReferenceCaller1<CopiedString, const char*, CopiedString_importString> CopiedStringImportStringCaller;
CopiedString_exportString(const CopiedString & self,const StringImportCallback & importer)296 inline void CopiedString_exportString( const CopiedString& self, const StringImportCallback& importer ){
297 	importer( self.c_str() );
298 }
299 typedef ConstReferenceCaller1<CopiedString, const StringImportCallback&, CopiedString_exportString> CopiedStringExportStringCaller;
300 
Bool_importString(bool & self,const char * string)301 inline void Bool_importString( bool& self, const char* string ){
302 	self = string_equal( string, "true" );
303 }
304 typedef ReferenceCaller1<bool, const char*, Bool_importString> BoolImportStringCaller;
Bool_exportString(const bool & self,const StringImportCallback & importer)305 inline void Bool_exportString( const bool& self, const StringImportCallback& importer ){
306 	importer( self ? "true" : "false" );
307 }
308 typedef ConstReferenceCaller1<bool, const StringImportCallback&, Bool_exportString> BoolExportStringCaller;
309 
Int_importString(int & self,const char * string)310 inline void Int_importString( int& self, const char* string ){
311 	if ( !string_parse_int( string, self ) ) {
312 		self = 0;
313 	}
314 }
315 typedef ReferenceCaller1<int, const char*, Int_importString> IntImportStringCaller;
Int_exportString(const int & self,const StringImportCallback & importer)316 inline void Int_exportString( const int& self, const StringImportCallback& importer ){
317 	char buffer[16];
318 	sprintf( buffer, "%d", self );
319 	importer( buffer );
320 }
321 typedef ConstReferenceCaller1<int, const StringImportCallback&, Int_exportString> IntExportStringCaller;
322 
Size_importString(std::size_t & self,const char * string)323 inline void Size_importString( std::size_t& self, const char* string ){
324 	int i;
325 	if ( string_parse_int( string, i ) && i >= 0 ) {
326 		self = i;
327 	}
328 	else
329 	{
330 		self = 0;
331 	}
332 }
333 typedef ReferenceCaller1<std::size_t, const char*, Size_importString> SizeImportStringCaller;
Size_exportString(const std::size_t & self,const StringImportCallback & importer)334 inline void Size_exportString( const std::size_t& self, const StringImportCallback& importer ){
335 	char buffer[16];
336 	sprintf( buffer, "%u", Unsigned( self ) );
337 	importer( buffer );
338 }
339 typedef ConstReferenceCaller1<std::size_t, const StringImportCallback&, Size_exportString> SizeExportStringCaller;
340 
Float_importString(float & self,const char * string)341 inline void Float_importString( float& self, const char* string ){
342 	if ( !string_parse_float( string, self ) ) {
343 		self = 0;
344 	}
345 }
346 typedef ReferenceCaller1<float, const char*, Float_importString> FloatImportStringCaller;
Float_exportString(const float & self,const StringImportCallback & importer)347 inline void Float_exportString( const float& self, const StringImportCallback& importer ){
348 	char buffer[16];
349 	sprintf( buffer, "%g", self );
350 	importer( buffer );
351 }
352 typedef ConstReferenceCaller1<float, const StringImportCallback&, Float_exportString> FloatExportStringCaller;
353 
Vector3_importString(Vector3 & self,const char * string)354 inline void Vector3_importString( Vector3& self, const char* string ){
355 	if ( !string_parse_vector3( string, self ) ) {
356 		self = Vector3( 0, 0, 0 );
357 	}
358 }
359 typedef ReferenceCaller1<Vector3, const char*, Vector3_importString> Vector3ImportStringCaller;
Vector3_exportString(const Vector3 & self,const StringImportCallback & importer)360 inline void Vector3_exportString( const Vector3& self, const StringImportCallback& importer ){
361 	char buffer[64];
362 	sprintf( buffer, "%g %g %g", self[0], self[1], self[2] );
363 	importer( buffer );
364 }
365 typedef ConstReferenceCaller1<Vector3, const StringImportCallback&, Vector3_exportString> Vector3ExportStringCaller;
366 
367 
368 
369 template<typename FirstArgument, typename Caller, typename FirstConversion>
370 class ImportConvert1
371 {
372 public:
thunk(void * environment,FirstArgument firstArgument)373 static void thunk( void* environment, FirstArgument firstArgument ){
374 	Caller::thunk( environment, FirstConversion( firstArgument ) );
375 }
376 };
377 
378 
379 class BoolFromString
380 {
381 bool m_value;
382 public:
BoolFromString(const char * string)383 BoolFromString( const char* string ){
384 	Bool_importString( m_value, string );
385 }
386 operator bool() const
387 {
388 	return m_value;
389 }
390 };
391 
Bool_toString(const StringImportCallback & self,bool value)392 inline void Bool_toString( const StringImportCallback& self, bool value ){
393 	Bool_exportString( value, self );
394 }
395 typedef ConstReferenceCaller1<StringImportCallback, bool, Bool_toString> BoolToString;
396 
397 
398 template<typename Caller>
makeBoolStringImportCallback(const Caller & caller)399 inline StringImportCallback makeBoolStringImportCallback( const Caller& caller ){
400 	return StringImportCallback( caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type, Caller, BoolFromString>::thunk );
401 }
402 
403 template<typename Caller>
makeBoolStringExportCallback(const Caller & caller)404 inline StringExportCallback makeBoolStringExportCallback( const Caller& caller ){
405 	return StringExportCallback( caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type, Caller, BoolToString>::thunk );
406 }
407 
408 
409 class IntFromString
410 {
411 int m_value;
412 public:
IntFromString(const char * string)413 IntFromString( const char* string ){
414 	Int_importString( m_value, string );
415 }
416 operator int() const
417 {
418 	return m_value;
419 }
420 };
421 
Int_toString(const StringImportCallback & self,int value)422 inline void Int_toString( const StringImportCallback& self, int value ){
423 	Int_exportString( value, self );
424 }
425 typedef ConstReferenceCaller1<StringImportCallback, int, Int_toString> IntToString;
426 
427 
428 template<typename Caller>
makeIntStringImportCallback(const Caller & caller)429 inline StringImportCallback makeIntStringImportCallback( const Caller& caller ){
430 	return StringImportCallback( caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type, Caller, IntFromString>::thunk );
431 }
432 
433 template<typename Caller>
makeIntStringExportCallback(const Caller & caller)434 inline StringExportCallback makeIntStringExportCallback( const Caller& caller ){
435 	return StringExportCallback( caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type, Caller, IntToString>::thunk );
436 }
437 
438 
439 
440 class SizeFromString
441 {
442 std::size_t m_value;
443 public:
SizeFromString(const char * string)444 SizeFromString( const char* string ){
445 	Size_importString( m_value, string );
446 }
size_t()447 operator std::size_t() const
448 {
449 	return m_value;
450 }
451 };
452 
Size_toString(const StringImportCallback & self,std::size_t value)453 inline void Size_toString( const StringImportCallback& self, std::size_t value ){
454 	Size_exportString( value, self );
455 }
456 typedef ConstReferenceCaller1<StringImportCallback, std::size_t, Size_toString> SizeToString;
457 
458 
459 template<typename Caller>
makeSizeStringImportCallback(const Caller & caller)460 inline StringImportCallback makeSizeStringImportCallback( const Caller& caller ){
461 	return StringImportCallback( caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type, Caller, SizeFromString>::thunk );
462 }
463 
464 template<typename Caller>
makeSizeStringExportCallback(const Caller & caller)465 inline StringExportCallback makeSizeStringExportCallback( const Caller& caller ){
466 	return StringExportCallback( caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type, Caller, SizeToString>::thunk );
467 }
468 
469 #endif
470