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/Vector3.h"
29 #include "iscriplib.h"
30 #include "string/string.h"
31 #include "generic/callback.h"
32 
buffer_parse_floating_literal(const char * & buffer)33 inline double buffer_parse_floating_literal (const char*& buffer)
34 {
35 	return strtod(buffer, const_cast<char**> (&buffer));
36 }
37 
buffer_parse_signed_decimal_integer_literal(const char * & buffer)38 inline int buffer_parse_signed_decimal_integer_literal (const char*& buffer)
39 {
40 	return strtol(buffer, const_cast<char**> (&buffer), 10);
41 }
42 
buffer_parse_unsigned_decimal_integer_literal(const char * & buffer)43 inline int buffer_parse_unsigned_decimal_integer_literal (const char*& buffer)
44 {
45 	return strtoul(buffer, const_cast<char**> (&buffer), 10);
46 }
47 
48 // [+|-][nnnnn][.nnnnn][e|E[+|-]nnnnn]
string_parse_float(const char * string,float & f)49 inline bool string_parse_float (const char* string, float& f)
50 {
51 	if (string_empty(string)) {
52 		return false;
53 	}
54 	f = float(buffer_parse_floating_literal(string));
55 	return string_empty(string);
56 }
57 
58 // format same as float
string_parse_double(const char * string,double & f)59 inline bool string_parse_double (const char* string, double& f)
60 {
61 	if (string_empty(string)) {
62 		return false;
63 	}
64 	f = buffer_parse_floating_literal(string);
65 	return string_empty(string);
66 }
67 
68 // <float><space><float><space><float>
69 template<typename Element>
string_parse_vector3(const std::string & str,BasicVector3<Element> & v)70 inline bool string_parse_vector3 (const std::string& str, BasicVector3<Element>& v)
71 {
72 	if (str.empty() || str[0] == ' ') {
73 		return false;
74 	}
75 
76 	const char* string = str.c_str();
77 	v[0] = float(buffer_parse_floating_literal(string));
78 	if (*string++ != ' ') {
79 		return false;
80 	}
81 	v[1] = float(buffer_parse_floating_literal(string));
82 	if (*string++ != ' ') {
83 		return false;
84 	}
85 	v[2] = float(buffer_parse_floating_literal(string));
86 	return string_empty(string);
87 }
88 
89 // decimal signed integer
string_parse_int(const std::string & str,int & i)90 inline bool string_parse_int (const std::string& str, int& i)
91 {
92 	if (str.empty()) {
93 		return false;
94 	}
95 	const char* string = str.c_str();
96 	i = buffer_parse_signed_decimal_integer_literal(string);
97 	return string_empty(string);
98 }
99 
100 // decimal unsigned integer
string_parse_size(const std::string & str,std::size_t & i)101 inline bool string_parse_size (const std::string& str, std::size_t& i)
102 {
103 	if (str.empty()) {
104 		return false;
105 	}
106 	const char* string = str.c_str();
107 	i = buffer_parse_unsigned_decimal_integer_literal(string);
108 	return string_empty(string);
109 }
110 
Tokeniser_unexpectedError(Tokeniser & tokeniser,const std::string & token,const std::string & expected)111 inline void Tokeniser_unexpectedError (Tokeniser& tokeniser, const std::string& token, const std::string& expected)
112 {
113 	globalErrorStream() << string::toString(tokeniser.getLine()) << ":" << string::toString(tokeniser.getColumn())
114 			<< ": parse error at '" << (token.length() ? token : "#EOF") << "': expected '" << expected << "'\n";
115 }
116 
Tokeniser_getFloat(Tokeniser & tokeniser,float & f)117 inline bool Tokeniser_getFloat (Tokeniser& tokeniser, float& f)
118 {
119 	const std::string token = tokeniser.getToken();
120 	if (token.length() && string_parse_float(token.c_str(), f)) {
121 		return true;
122 	}
123 	Tokeniser_unexpectedError(tokeniser, token, "#number");
124 	return false;
125 }
126 
Tokeniser_getDouble(Tokeniser & tokeniser,double & f)127 inline bool Tokeniser_getDouble (Tokeniser& tokeniser, double& f)
128 {
129 	const std::string token = tokeniser.getToken();
130 	if (token.length() && string_parse_double(token.c_str(), f)) {
131 		return true;
132 	}
133 	Tokeniser_unexpectedError(tokeniser, token, "#number");
134 	return false;
135 }
136 
Tokeniser_getSize(Tokeniser & tokeniser,std::size_t & i)137 inline bool Tokeniser_getSize (Tokeniser& tokeniser, std::size_t& i)
138 {
139 	const std::string token = tokeniser.getToken();
140 	if (token.length() && string_parse_size(token.c_str(), i)) {
141 		return true;
142 	}
143 	Tokeniser_unexpectedError(tokeniser, token, "#unsigned-integer");
144 	return false;
145 }
146 
Tokeniser_parseToken(Tokeniser & tokeniser,const char * expected)147 inline bool Tokeniser_parseToken (Tokeniser& tokeniser, const char* expected)
148 {
149 	const std::string token = tokeniser.getToken();
150 	if (token.length() && string_equal(token, expected)) {
151 		return true;
152 	}
153 	Tokeniser_unexpectedError(tokeniser, token, expected);
154 	return false;
155 }
156 
Tokeniser_nextTokenIsDigit(Tokeniser & tokeniser)157 inline bool Tokeniser_nextTokenIsDigit (Tokeniser& tokeniser)
158 {
159 	const std::string token = tokeniser.getToken();
160 	if (token.empty()) {
161 		return false;
162 	}
163 	char c = *token.c_str();
164 	tokeniser.ungetToken();
165 	return std::isdigit(c) != 0;
166 }
167 
168 template<typename TextOutputStreamType>
ostream_write(TextOutputStreamType & outputStream,const Vector3 & v)169 inline TextOutputStreamType& ostream_write (TextOutputStreamType& outputStream, const Vector3& v)
170 {
171 	return outputStream << "(" << v.x() << " " << v.y() << " " << v.z() << ")";
172 }
173 
StdString_importString(std::string & self,const char * string)174 inline void StdString_importString (std::string& self, const char* string)
175 {
176 	self = string;
177 }
178 typedef ReferenceCaller1<std::string, const char*, StdString_importString> StringImportStringCaller;
StdString_exportString(const std::string & self,const StringImportCallback & importer)179 inline void StdString_exportString (const std::string& self, const StringImportCallback& importer)
180 {
181 	importer(self.c_str());
182 }
183 typedef ConstReferenceCaller1<std::string, const StringImportCallback&, StdString_exportString>
184 		StringExportStringCaller;
185 
Bool_importString(bool & self,const char * string)186 inline void Bool_importString (bool& self, const char* string)
187 {
188 	self = string_equal(string, "true");
189 }
190 typedef ReferenceCaller1<bool, const char*, Bool_importString> BoolImportStringCaller;
Bool_exportString(const bool & self,const StringImportCallback & importer)191 inline void Bool_exportString (const bool& self, const StringImportCallback& importer)
192 {
193 	importer(self ? "true" : "false");
194 }
195 typedef ConstReferenceCaller1<bool, const StringImportCallback&, Bool_exportString> BoolExportStringCaller;
196 
Int_importString(int & self,const char * string)197 inline void Int_importString (int& self, const char* string)
198 {
199 	if (!string_parse_int(string, self)) {
200 		self = 0;
201 	}
202 }
203 typedef ReferenceCaller1<int, const char*, Int_importString> IntImportStringCaller;
Int_exportString(const int & self,const StringImportCallback & importer)204 inline void Int_exportString (const int& self, const StringImportCallback& importer)
205 {
206 	char buffer[16];
207 	sprintf(buffer, "%d", self);
208 	importer(buffer);
209 }
210 typedef ConstReferenceCaller1<int, const StringImportCallback&, Int_exportString> IntExportStringCaller;
211 
Size_importString(std::size_t & self,const char * string)212 inline void Size_importString (std::size_t& self, const char* string)
213 {
214 	int i;
215 	if (string_parse_int(string, i) && i >= 0) {
216 		self = i;
217 	} else {
218 		self = 0;
219 	}
220 }
221 typedef ReferenceCaller1<std::size_t, const char*, Size_importString> SizeImportStringCaller;
Size_exportString(const std::size_t & self,const StringImportCallback & importer)222 inline void Size_exportString (const std::size_t& self, const StringImportCallback& importer)
223 {
224 	char buffer[16];
225 	sprintf(buffer, "%u", Unsigned(self));
226 	importer(buffer);
227 }
228 typedef ConstReferenceCaller1<std::size_t, const StringImportCallback&, Size_exportString> SizeExportStringCaller;
229 
Float_importString(float & self,const char * string)230 inline void Float_importString (float& self, const char* string)
231 {
232 	if (!string_parse_float(string, self)) {
233 		self = 0;
234 	}
235 }
236 typedef ReferenceCaller1<float, const char*, Float_importString> FloatImportStringCaller;
Float_exportString(const float & self,const StringImportCallback & importer)237 inline void Float_exportString (const float& self, const StringImportCallback& importer)
238 {
239 	char buffer[16];
240 	sprintf(buffer, "%g", self);
241 	importer(buffer);
242 }
243 typedef ConstReferenceCaller1<float, const StringImportCallback&, Float_exportString> FloatExportStringCaller;
244 
Vector3_importString(Vector3 & self,const char * string)245 inline void Vector3_importString (Vector3& self, const char* string)
246 {
247 	//self(std::string(string));
248 	if (!string_parse_vector3(string, self)) {
249 		self = Vector3(0, 0, 0);
250 	}
251 }
252 typedef ReferenceCaller1<Vector3, const char*, Vector3_importString> Vector3ImportStringCaller;
Vector3_exportString(const Vector3 & self,const StringImportCallback & importer)253 inline void Vector3_exportString (const Vector3& self, const StringImportCallback& importer)
254 {
255 	char buffer[64];
256 	sprintf(buffer, "%g %g %g", self[0], self[1], self[2]);
257 	importer(buffer);
258 }
259 typedef ConstReferenceCaller1<Vector3, const StringImportCallback&, Vector3_exportString> Vector3ExportStringCaller;
260 
261 template<typename FirstArgument, typename Caller, typename FirstConversion>
262 class ImportConvert1
263 {
264 	public:
thunk(void * environment,FirstArgument firstArgument)265 		static void thunk (void* environment, FirstArgument firstArgument)
266 		{
267 			Caller::thunk(environment, FirstConversion(firstArgument));
268 		}
269 };
270 
271 class BoolFromString
272 {
273 		bool m_value;
274 	public:
BoolFromString(const char * string)275 		BoolFromString (const char* string)
276 		{
277 			Bool_importString(m_value, string);
278 		}
279 		operator bool () const
280 		{
281 			return m_value;
282 		}
283 };
284 
Bool_toString(const StringImportCallback & self,bool value)285 inline void Bool_toString (const StringImportCallback& self, bool value)
286 {
287 	Bool_exportString(value, self);
288 }
289 typedef ConstReferenceCaller1<StringImportCallback, bool, Bool_toString> BoolToString;
290 
291 template<typename Caller>
makeBoolStringImportCallback(const Caller & caller)292 inline StringImportCallback makeBoolStringImportCallback (const Caller& caller)
293 {
294 	return StringImportCallback(caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type,
295 			Caller, BoolFromString>::thunk);
296 }
297 
298 template<typename Caller>
makeBoolStringExportCallback(const Caller & caller)299 inline StringExportCallback makeBoolStringExportCallback (const Caller& caller)
300 {
301 	return StringExportCallback(caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type,
302 			Caller, BoolToString>::thunk);
303 }
304 
305 class IntFromString
306 {
307 		int m_value;
308 	public:
IntFromString(const char * string)309 		IntFromString (const char* string)
310 		{
311 			Int_importString(m_value, string);
312 		}
313 		operator int () const
314 		{
315 			return m_value;
316 		}
317 };
318 
Int_toString(const StringImportCallback & self,int value)319 inline void Int_toString (const StringImportCallback& self, int value)
320 {
321 	Int_exportString(value, self);
322 }
323 typedef ConstReferenceCaller1<StringImportCallback, int, Int_toString> IntToString;
324 
325 template<typename Caller>
makeIntStringImportCallback(const Caller & caller)326 inline StringImportCallback makeIntStringImportCallback (const Caller& caller)
327 {
328 	return StringImportCallback(caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type,
329 			Caller, IntFromString>::thunk);
330 }
331 
332 template<typename Caller>
makeIntStringExportCallback(const Caller & caller)333 inline StringExportCallback makeIntStringExportCallback (const Caller& caller)
334 {
335 	return StringExportCallback(caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type,
336 			Caller, IntToString>::thunk);
337 }
338 
339 class SizeFromString
340 {
341 		std::size_t m_value;
342 	public:
SizeFromString(const char * string)343 		SizeFromString (const char* string)
344 		{
345 			Size_importString(m_value, string);
346 		}
size_t()347 		operator std::size_t () const
348 		{
349 			return m_value;
350 		}
351 };
352 
Size_toString(const StringImportCallback & self,std::size_t value)353 inline void Size_toString (const StringImportCallback& self, std::size_t value)
354 {
355 	Size_exportString(value, self);
356 }
357 typedef ConstReferenceCaller1<StringImportCallback, std::size_t, Size_toString> SizeToString;
358 
359 template<typename Caller>
makeSizeStringImportCallback(const Caller & caller)360 inline StringImportCallback makeSizeStringImportCallback (const Caller& caller)
361 {
362 	return StringImportCallback(caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type,
363 			Caller, SizeFromString>::thunk);
364 }
365 
366 template<typename Caller>
makeSizeStringExportCallback(const Caller & caller)367 inline StringExportCallback makeSizeStringExportCallback (const Caller& caller)
368 {
369 	return StringExportCallback(caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type,
370 			Caller, SizeToString>::thunk);
371 }
372 
373 #endif
374