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