/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined (INCLUDED_STRINGIO_H) #define INCLUDED_STRINGIO_H #include #include #include "math/vector.h" #include "iscriplib.h" #include "string/string.h" #include "generic/callback.h" inline float string_read_float(const char* string) { return static_cast(atof(string)); } inline int string_read_int(const char* string) { return atoi(string); } inline bool char_is_whitespace(char c) { return c == ' ' || c == '\t'; } inline const char* string_remove_whitespace(const char* string) { for(;;) { if(!char_is_whitespace(*string)) { break; } ++string; } return string; } inline const char* string_remove_zeros(const char* string) { for(;;) { char c = *string; if(c != '0') { break; } ++string; } return string; } inline const char* string_remove_sign(const char* string) { if(*string == '-' || *string == '+') // signed zero - acceptable { return ++string; } return string; } inline bool string_is_unsigned_zero(const char* string) { for(;*string != '\0'; ++string) { if(*string != '0') { return false; } } return true; } inline bool string_is_signed_zero(const char* string) { return string_is_unsigned_zero(string_remove_sign(string)); } //[whitespaces][+|-][nnnnn][.nnnnn][e|E[+|-]nnnn] //(where whitespaces are any tab or space character and nnnnn may be any number of digits) inline bool string_is_float_zero(const char* string) { string = string_remove_whitespace(string); if(string_empty(string)) { return false; } string = string_remove_sign(string); if(string_empty(string)) { // no whole number or fraction part return false; } // whole-number part string = string_remove_zeros(string); if(string_empty(string)) { // no fraction or exponent return true; } if(*string == '.') { // fraction part if(*string++ != '0') { // invalid fraction return false; } string = string_remove_zeros(++string); if(string_empty(string)) { // no exponent return true; } } if(*string == 'e' || *string == 'E') { // exponent part string = string_remove_sign(++string); if(*string++ != '0') { // invalid exponent return false; } string = string_remove_zeros(++string); if(string_empty(string)) { // no trailing whitespace return true; } } string = string_remove_whitespace(string); return string_empty(string); } inline double buffer_parse_floating_literal(const char*& buffer) { return strtod(buffer, const_cast(&buffer)); } inline int buffer_parse_signed_decimal_integer_literal(const char*& buffer) { return strtol(buffer, const_cast(&buffer), 10); } inline int buffer_parse_unsigned_decimal_integer_literal(const char*& buffer) { return strtoul(buffer, const_cast(&buffer), 10); } // [+|-][nnnnn][.nnnnn][e|E[+|-]nnnnn] inline bool string_parse_float(const char* string, float& f) { if(string_empty(string)) { return false; } f = float(buffer_parse_floating_literal(string)); return string_empty(string); } // format same as float inline bool string_parse_double(const char* string, double& f) { if(string_empty(string)) { return false; } f = buffer_parse_floating_literal(string); return string_empty(string); } // template inline bool string_parse_vector3(const char* string, BasicVector3& v) { if(string_empty(string) || *string == ' ') { return false; } v[0] = float(buffer_parse_floating_literal(string)); if(*string++ != ' ') { return false; } v[1] = float(buffer_parse_floating_literal(string)); if(*string++ != ' ') { return false; } v[2] = float(buffer_parse_floating_literal(string)); return string_empty(string); } template inline bool string_parse_vector(const char* string, Float* first, Float* last) { if(first != last && (string_empty(string) || *string == ' ')) { return false; } for(;;) { *first = float(buffer_parse_floating_literal(string)); if(++first == last) { return string_empty(string); } if(*string++ != ' ') { return false; } } } // decimal signed integer inline bool string_parse_int(const char* string, int& i) { if(string_empty(string)) { return false; } i = buffer_parse_signed_decimal_integer_literal(string); return string_empty(string); } // decimal unsigned integer inline bool string_parse_size(const char* string, std::size_t& i) { if(string_empty(string)) { return false; } i = buffer_parse_unsigned_decimal_integer_literal(string); return string_empty(string); } #define RETURN_FALSE_IF_FAIL(expression) if(!expression) return false; else inline void Tokeniser_unexpectedError(Tokeniser& tokeniser, const char* token, const char* expected) { globalErrorStream() << Unsigned(tokeniser.getLine()) << ":" << Unsigned(tokeniser.getColumn()) << ": parse error at '" << (token != 0 ? token : "#EOF") << "': expected '" << expected << "'\n"; } inline bool Tokeniser_getFloat(Tokeniser& tokeniser, float& f) { const char* token = tokeniser.getToken(); if(token != 0 && string_parse_float(token, f)) { return true; } Tokeniser_unexpectedError(tokeniser, token, "#number"); return false; } inline bool Tokeniser_getDouble(Tokeniser& tokeniser, double& f) { const char* token = tokeniser.getToken(); if(token != 0 && string_parse_double(token, f)) { return true; } Tokeniser_unexpectedError(tokeniser, token, "#number"); return false; } inline bool Tokeniser_getInteger(Tokeniser& tokeniser, int& i) { const char* token = tokeniser.getToken(); if(token != 0 && string_parse_int(token, i)) { return true; } Tokeniser_unexpectedError(tokeniser, token, "#integer"); return false; } inline bool Tokeniser_getSize(Tokeniser& tokeniser, std::size_t& i) { const char* token = tokeniser.getToken(); if(token != 0 && string_parse_size(token, i)) { return true; } Tokeniser_unexpectedError(tokeniser, token, "#unsigned-integer"); return false; } inline bool Tokeniser_parseToken(Tokeniser& tokeniser, const char* expected) { const char* token = tokeniser.getToken(); if(token != 0 && string_equal(token, expected)) { return true; } Tokeniser_unexpectedError(tokeniser, token, expected); return false; } inline bool Tokeniser_nextTokenIsDigit(Tokeniser& tokeniser) { const char* token = tokeniser.getToken(); if(token == 0) { return false; } char c = *token; tokeniser.ungetToken(); return std::isdigit(c) != 0; } template inline TextOutputStreamType& ostream_write(TextOutputStreamType& outputStream, const Vector3& v) { return outputStream << '(' << v.x() << ' ' << v.y() << ' ' << v.z() << ')'; } inline void CopiedString_importString(CopiedString& self, const char* string) { self = string; } typedef ReferenceCaller1 CopiedStringImportStringCaller; inline void CopiedString_exportString(const CopiedString& self, const StringImportCallback& importer) { importer(self.c_str()); } typedef ConstReferenceCaller1 CopiedStringExportStringCaller; inline void Bool_importString(bool& self, const char* string) { self = string_equal(string, "true"); } typedef ReferenceCaller1 BoolImportStringCaller; inline void Bool_exportString(const bool& self, const StringImportCallback& importer) { importer(self ? "true" : "false"); } typedef ConstReferenceCaller1 BoolExportStringCaller; inline void Int_importString(int& self, const char* string) { if(!string_parse_int(string, self)) { self = 0; } } typedef ReferenceCaller1 IntImportStringCaller; inline void Int_exportString(const int& self, const StringImportCallback& importer) { char buffer[16]; sprintf(buffer, "%d", self); importer(buffer); } typedef ConstReferenceCaller1 IntExportStringCaller; inline void Size_importString(std::size_t& self, const char* string) { int i; if(string_parse_int(string, i) && i >= 0) { self = i; } else { self = 0; } } typedef ReferenceCaller1 SizeImportStringCaller; inline void Size_exportString(const std::size_t& self, const StringImportCallback& importer) { char buffer[16]; sprintf(buffer, "%u", Unsigned(self)); importer(buffer); } typedef ConstReferenceCaller1 SizeExportStringCaller; inline void Float_importString(float& self, const char* string) { if(!string_parse_float(string, self)) { self = 0; } } typedef ReferenceCaller1 FloatImportStringCaller; inline void Float_exportString(const float& self, const StringImportCallback& importer) { char buffer[16]; sprintf(buffer, "%g", self); importer(buffer); } typedef ConstReferenceCaller1 FloatExportStringCaller; inline void Vector3_importString(Vector3& self, const char* string) { if(!string_parse_vector3(string, self)) { self = Vector3(0, 0, 0); } } typedef ReferenceCaller1 Vector3ImportStringCaller; inline void Vector3_exportString(const Vector3& self, const StringImportCallback& importer) { char buffer[64]; sprintf(buffer, "%g %g %g", self[0], self[1], self[2]); importer(buffer); } typedef ConstReferenceCaller1 Vector3ExportStringCaller; template class ImportConvert1 { public: static void thunk(void* environment, FirstArgument firstArgument) { Caller::thunk(environment, FirstConversion(firstArgument)); } }; class BoolFromString { bool m_value; public: BoolFromString(const char* string) { Bool_importString(m_value, string); } operator bool() const { return m_value; } }; inline void Bool_toString(const StringImportCallback& self, bool value) { Bool_exportString(value, self); } typedef ConstReferenceCaller1 BoolToString; template inline StringImportCallback makeBoolStringImportCallback(const Caller& caller) { return StringImportCallback(caller.getEnvironment(), ImportConvert1::thunk); } template inline StringExportCallback makeBoolStringExportCallback(const Caller& caller) { return StringExportCallback(caller.getEnvironment(), ImportConvert1::thunk); } class IntFromString { int m_value; public: IntFromString(const char* string) { Int_importString(m_value, string); } operator int() const { return m_value; } }; inline void Int_toString(const StringImportCallback& self, int value) { Int_exportString(value, self); } typedef ConstReferenceCaller1 IntToString; template inline StringImportCallback makeIntStringImportCallback(const Caller& caller) { return StringImportCallback(caller.getEnvironment(), ImportConvert1::thunk); } template inline StringExportCallback makeIntStringExportCallback(const Caller& caller) { return StringExportCallback(caller.getEnvironment(), ImportConvert1::thunk); } class SizeFromString { std::size_t m_value; public: SizeFromString(const char* string) { Size_importString(m_value, string); } operator std::size_t() const { return m_value; } }; inline void Size_toString(const StringImportCallback& self, std::size_t value) { Size_exportString(value, self); } typedef ConstReferenceCaller1 SizeToString; template inline StringImportCallback makeSizeStringImportCallback(const Caller& caller) { return StringImportCallback(caller.getEnvironment(), ImportConvert1::thunk); } template inline StringExportCallback makeSizeStringExportCallback(const Caller& caller) { return StringExportCallback(caller.getEnvironment(), ImportConvert1::thunk); } #endif