]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/stringio.h
Merge commit '515673c08f8718a237e90c2130a1f5294f966d6a'
[xonotic/netradiant.git] / libs / stringio.h
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
33 inline float string_read_float(const char* string)
34 {
35   return static_cast<float>(atof(string));
36 }
37
38 inline int string_read_int(const char* string)
39 {
40   return atoi(string);
41 }
42
43 inline bool char_is_whitespace(char c)
44 {
45   return c == ' ' || c == '\t';
46 }
47
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
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
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
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
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)
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
160 inline double buffer_parse_floating_literal(const char*& buffer)
161 {
162   return strtod(buffer, const_cast<char**>(&buffer));
163 }
164
165 inline int buffer_parse_signed_decimal_integer_literal(const char*& buffer)
166 {
167   return strtol(buffer, const_cast<char**>(&buffer), 10);
168 }
169
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]
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
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>
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>
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
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
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
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
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
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
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
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
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
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>
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
347 inline void CopiedString_importString(CopiedString& self, const char* string)
348 {
349   self = string;
350 }
351 typedef ReferenceCaller1<CopiedString, const char*, CopiedString_importString> CopiedStringImportStringCaller;
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
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;
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
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;
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
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;
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
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;
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
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;
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:
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:
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
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>
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>
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:
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
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>
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>
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:
524   SizeFromString(const char* string)
525   {
526     Size_importString(m_value, string);
527   }
528   operator std::size_t() const
529   {
530     return m_value;
531   }
532 };
533
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>
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>
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