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"
34 inline float string_read_float( const char* string ){
35 return static_cast<float>( atof( string ) );
38 inline int string_read_int( const char* string ){
39 return atoi( string );
42 inline bool char_is_whitespace( char c ){
43 return c == ' ' || c == '\t';
46 inline const char* string_remove_whitespace( const char* string ){
49 if ( !char_is_whitespace( *string ) ) {
57 inline const char* string_remove_zeros( const char* string ){
69 inline const char* string_remove_sign( const char* string ){
70 if ( *string == '-' || *string == '+' ) { // signed zero - acceptable
76 inline bool string_is_unsigned_zero( const char* string ){
77 for (; *string != '\0'; ++string )
79 if ( *string != '0' ) {
86 inline bool string_is_signed_zero( const char* string ){
87 return string_is_unsigned_zero( string_remove_sign( string ) );
90 //[whitespaces][+|-][nnnnn][.nnnnn][e|E[+|-]nnnn]
91 //(where whitespaces are any tab or space character and nnnnn may be any number of digits)
92 inline bool string_is_float_zero( const char* string ){
93 string = string_remove_whitespace( string );
94 if ( string_empty( string ) ) {
98 string = string_remove_sign( string );
99 if ( string_empty( string ) ) {
100 // no whole number or fraction part
105 string = string_remove_zeros( string );
106 if ( string_empty( string ) ) {
107 // no fraction or exponent
110 if ( *string == '.' ) {
112 if ( *string++ != '0' ) {
116 string = string_remove_zeros( ++string );
117 if ( string_empty( string ) ) {
122 if ( *string == 'e' || *string == 'E' ) {
124 string = string_remove_sign( ++string );
125 if ( *string++ != '0' ) {
129 string = string_remove_zeros( ++string );
130 if ( string_empty( string ) ) {
131 // no trailing whitespace
135 string = string_remove_whitespace( string );
136 return string_empty( string );
139 inline double buffer_parse_floating_literal( const char*& buffer ){
140 return strtod( buffer, const_cast<char**>( &buffer ) );
143 inline int buffer_parse_signed_decimal_integer_literal( const char*& buffer ){
144 return strtol( buffer, const_cast<char**>( &buffer ), 10 );
147 inline int buffer_parse_unsigned_decimal_integer_literal( const char*& buffer ){
148 return strtoul( buffer, const_cast<char**>( &buffer ), 10 );
151 // [+|-][nnnnn][.nnnnn][e|E[+|-]nnnnn]
152 inline bool string_parse_float( const char* string, float& f ){
153 if ( string_empty( string ) ) {
156 f = float(buffer_parse_floating_literal( string ) );
157 return string_empty( string );
160 // format same as float
161 inline bool string_parse_double( const char* string, double& f ){
162 if ( string_empty( string ) ) {
165 f = buffer_parse_floating_literal( string );
166 return string_empty( string );
169 // <float><space><float><space><float>
170 template<typename Element>
171 inline bool string_parse_vector3( const char* string, BasicVector3<Element>& v ){
172 if ( string_empty( string ) || *string == ' ' ) {
175 v[0] = float(buffer_parse_floating_literal( string ) );
176 if ( *string++ != ' ' ) {
179 v[1] = float(buffer_parse_floating_literal( string ) );
180 if ( *string++ != ' ' ) {
183 v[2] = float(buffer_parse_floating_literal( string ) );
184 return string_empty( string );
187 template<typename Float>
188 inline bool string_parse_vector( const char* string, Float* first, Float* last ){
189 if ( first != last && ( string_empty( string ) || *string == ' ' ) ) {
194 *first = float(buffer_parse_floating_literal( string ) );
195 if ( ++first == last ) {
196 return string_empty( string );
198 if ( *string++ != ' ' ) {
204 // decimal signed integer
205 inline bool string_parse_int( const char* string, int& i ){
206 if ( string_empty( string ) ) {
209 i = buffer_parse_signed_decimal_integer_literal( string );
210 return string_empty( string );
213 // decimal unsigned integer
214 inline bool string_parse_size( const char* string, std::size_t& i ){
215 if ( string_empty( string ) ) {
218 i = buffer_parse_unsigned_decimal_integer_literal( string );
219 return string_empty( string );
223 #define RETURN_FALSE_IF_FAIL(expression) do { if (!(expression)) return false; } while (0)
225 inline void Tokeniser_unexpectedError( Tokeniser& tokeniser, const char* token, const char* expected ){
226 globalErrorStream() << Unsigned( tokeniser.getLine() ) << ":" << Unsigned( tokeniser.getColumn() ) << ": parse error at '" << ( token != 0 ? token : "#EOF" ) << "': expected '" << expected << "'\n";
230 inline bool Tokeniser_getFloat( Tokeniser& tokeniser, float& f ){
231 const char* token = tokeniser.getToken();
232 if ( token != 0 && string_parse_float( token, f ) ) {
235 Tokeniser_unexpectedError( tokeniser, token, "#number" );
239 inline bool Tokeniser_getDouble( Tokeniser& tokeniser, double& f ){
240 const char* token = tokeniser.getToken();
241 if ( token != 0 && string_parse_double( token, f ) ) {
244 Tokeniser_unexpectedError( tokeniser, token, "#number" );
248 inline bool Tokeniser_getInteger( Tokeniser& tokeniser, int& i ){
249 const char* token = tokeniser.getToken();
250 if ( token != 0 && string_parse_int( token, i ) ) {
253 Tokeniser_unexpectedError( tokeniser, token, "#integer" );
257 inline bool Tokeniser_getSize( Tokeniser& tokeniser, std::size_t& i ){
258 const char* token = tokeniser.getToken();
259 if ( token != 0 && string_parse_size( token, i ) ) {
262 Tokeniser_unexpectedError( tokeniser, token, "#unsigned-integer" );
266 inline bool Tokeniser_parseToken( Tokeniser& tokeniser, const char* expected ){
267 const char* token = tokeniser.getToken();
268 if ( token != 0 && string_equal( token, expected ) ) {
271 Tokeniser_unexpectedError( tokeniser, token, expected );
275 inline bool Tokeniser_nextTokenIsDigit( Tokeniser& tokeniser ){
276 const char* token = tokeniser.getToken();
281 tokeniser.ungetToken();
282 return std::isdigit( c ) != 0;
285 template<typename TextOutputStreamType>
286 inline TextOutputStreamType& ostream_write( TextOutputStreamType& outputStream, const Vector3& v ){
287 return outputStream << '(' << v.x() << ' ' << v.y() << ' ' << v.z() << ')';
292 struct PropertyImpl<bool, const char *> {
293 static void Export(const bool &self, const Callback<void(const char *)> &returnz) {
294 returnz(self ? "true" : "false");
297 static void Import(bool &self, const char *value) {
298 self = string_equal(value, "true");
303 struct PropertyImpl<int, const char *> {
304 static void Export(const int &self, const Callback<void(const char *)> &returnz) {
306 sprintf(buffer, "%d", self);
310 static void Import(int &self, const char *value) {
311 if (!string_parse_int(value, self)) {
318 struct PropertyImpl<std::size_t, const char *> {
319 static void Export(const std::size_t &self, const Callback<void(const char *)> &returnz) {
321 sprintf(buffer, "%u", Unsigned(self));
325 static void Import(std::size_t &self, const char *value) {
327 if (string_parse_int(value, i) && i >= 0) {
336 struct PropertyImpl<float, const char *> {
337 static void Export(const float &self, const Callback<void(const char *)> &returnz) {
339 sprintf(buffer, "%g", self);
343 static void Import(float &self, const char *value) {
344 if (!string_parse_float(value, self)) {
351 struct PropertyImpl<Vector3, const char *> {
352 static void Export(const Vector3 &self, const Callback<void(const char *)> &returnz) {
354 sprintf(buffer, "%g %g %g", self[0], self[1], self[2]);
358 static void Import(Vector3 &self, const char *value) {
359 if (!string_parse_vector3(value, self)) {
360 self = Vector3(0, 0, 0);