[q3map2] Unwind script stack in case of script loading error.
[xonotic/netradiant.git] / libs / stringio.h
index 8a8bd9b..47772ee 100644 (file)
@@ -1,25 +1,25 @@
 /*
-Copyright (C) 2001-2006, William Joseph.
-All Rights Reserved.
+   Copyright (C) 2001-2006, William Joseph.
+   All Rights Reserved.
 
-This file is part of GtkRadiant.
+   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 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.
+   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
-*/
+   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)
+#if !defined ( INCLUDED_STRINGIO_H )
 #define INCLUDED_STRINGIO_H
 
 #include <stdlib.h>
@@ -29,525 +29,337 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "iscriplib.h"
 #include "string/string.h"
 #include "generic/callback.h"
+#include "property.h"
 
-inline float string_read_float(const char* string)
-{
-  return static_cast<float>(atof(string));
+inline float string_read_float( const char* string ){
+       return static_cast<float>( atof( string ) );
 }
 
-inline int string_read_int(const char* string)
-{
-  return atoi(string);
+inline int string_read_int( const char* string ){
+       return atoi( string );
 }
 
-inline bool char_is_whitespace(char c)
-{
-  return c == ' ' || c == '\t';
+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_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_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 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_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));
+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<char**>(&buffer));
-}
-
-inline int buffer_parse_signed_decimal_integer_literal(const char*& buffer)
-{
-  return strtol(buffer, const_cast<char**>(&buffer), 10);
-}
-
-inline int buffer_parse_unsigned_decimal_integer_literal(const char*& buffer)
-{
-  return strtoul(buffer, const_cast<char**>(&buffer), 10);
+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<char**>( &buffer ) );
+}
+
+inline int buffer_parse_signed_decimal_integer_literal( const char*& buffer ){
+       return strtol( buffer, const_cast<char**>( &buffer ), 10 );
+}
+
+inline int buffer_parse_unsigned_decimal_integer_literal( const char*& buffer ){
+       return strtoul( buffer, const_cast<char**>( &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);
+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);
+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 );
 }
 
 // <float><space><float><space><float>
 template<typename Element>
-inline bool string_parse_vector3(const char* string, BasicVector3<Element>& 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);
+inline bool string_parse_vector3( const char* string, BasicVector3<Element>& 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<typename Float>
-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;
-    }
-  }
+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);
+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);
+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
+#define RETURN_FALSE_IF_FAIL(expression) do { if (!(expression)) return false; } while (0)
 
-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 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_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_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_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_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_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;
+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<typename TextOutputStreamType>
-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<CopiedString, const char*, CopiedString_importString> CopiedStringImportStringCaller;
-inline void CopiedString_exportString(const CopiedString& self, const StringImportCallback& importer)
-{
-  importer(self.c_str());
-}
-typedef ConstReferenceCaller1<CopiedString, const StringImportCallback&, CopiedString_exportString> CopiedStringExportStringCaller;
-
-inline void Bool_importString(bool& self, const char* string)
-{
-  self = string_equal(string, "true");
-}
-typedef ReferenceCaller1<bool, const char*, Bool_importString> BoolImportStringCaller;
-inline void Bool_exportString(const bool& self, const StringImportCallback& importer)
-{
-  importer(self ? "true" : "false");
-}
-typedef ConstReferenceCaller1<bool, const StringImportCallback&, Bool_exportString> BoolExportStringCaller;
-
-inline void Int_importString(int& self, const char* string)
-{
-  if(!string_parse_int(string, self))
-  {
-    self = 0;
-  }
-}
-typedef ReferenceCaller1<int, const char*, Int_importString> IntImportStringCaller;
-inline void Int_exportString(const int& self, const StringImportCallback& importer)
-{
-  char buffer[16];
-  sprintf(buffer, "%d", self);
-  importer(buffer);
-}
-typedef ConstReferenceCaller1<int, const StringImportCallback&, Int_exportString> 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<std::size_t, const char*, Size_importString> 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<std::size_t, const StringImportCallback&, Size_exportString> SizeExportStringCaller;
-
-inline void Float_importString(float& self, const char* string)
-{
-  if(!string_parse_float(string, self))
-  {
-    self = 0;
-  }
-}
-typedef ReferenceCaller1<float, const char*, Float_importString> FloatImportStringCaller;
-inline void Float_exportString(const float& self, const StringImportCallback& importer)
-{
-  char buffer[16];
-  sprintf(buffer, "%g", self);
-  importer(buffer);
-}
-typedef ConstReferenceCaller1<float, const StringImportCallback&, Float_exportString> FloatExportStringCaller;
-
-inline void Vector3_importString(Vector3& self, const char* string)
-{
-  if(!string_parse_vector3(string, self))
-  {
-    self = Vector3(0, 0, 0);
-  }
+inline TextOutputStreamType& ostream_write( TextOutputStreamType& outputStream, const Vector3& v ){
+       return outputStream << '(' << v.x() << ' ' << v.y() << ' ' << v.z() << ')';
 }
-typedef ReferenceCaller1<Vector3, const char*, Vector3_importString> 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<Vector3, const StringImportCallback&, Vector3_exportString> Vector3ExportStringCaller;
 
 
+template<>
+struct PropertyImpl<bool, const char *> {
+       static void Export(const bool &self, const Callback<void(const char *)> &returnz) {
+               returnz(self ? "true" : "false");
+       }
 
-template<typename FirstArgument, typename Caller, typename FirstConversion>
-class ImportConvert1
-{
-public:
-  static void thunk(void* environment, FirstArgument firstArgument)
-  {
-    Caller::thunk(environment, FirstConversion(firstArgument));
-  }
+    static void Import(bool &self, const char *value) {
+        self = string_equal(value, "true");
+    }
 };
 
-
-class BoolFromString
-{
-  bool m_value;
-public:
-  BoolFromString(const char* string)
-  {
-    Bool_importString(m_value, string);
-  }
-  operator bool() const
-  {
-    return m_value;
-  }
+template<>
+struct PropertyImpl<int, const char *> {
+       static void Export(const int &self, const Callback<void(const char *)> &returnz) {
+               char buffer[16];
+               sprintf(buffer, "%d", self);
+               returnz(buffer);
+       }
+
+    static void Import(int &self, const char *value) {
+        if (!string_parse_int(value, self)) {
+            self = 0;
+        }
+    }
 };
 
-inline void Bool_toString(const StringImportCallback& self, bool value)
-{
-  Bool_exportString(value, self);
-}
-typedef ConstReferenceCaller1<StringImportCallback, bool, Bool_toString> BoolToString;
-
-
-template<typename Caller>
-inline StringImportCallback makeBoolStringImportCallback(const Caller& caller)
-{
-  return StringImportCallback(caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type, Caller, BoolFromString>::thunk);
-}
-
-template<typename Caller>
-inline StringExportCallback makeBoolStringExportCallback(const Caller& caller)
-{
-  return StringExportCallback(caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type, Caller, BoolToString>::thunk);
-}
-
-
-class IntFromString
-{
-  int m_value;
-public:
-  IntFromString(const char* string)
-  {
-    Int_importString(m_value, string);
-  }
-  operator int() const
-  {
-    return m_value;
-  }
+template<>
+struct PropertyImpl<std::size_t, const char *> {
+       static void Export(const std::size_t &self, const Callback<void(const char *)> &returnz) {
+               char buffer[16];
+               sprintf(buffer, "%u", Unsigned(self));
+               returnz(buffer);
+       }
+
+    static void Import(std::size_t &self, const char *value) {
+        int i;
+        if (string_parse_int(value, i) && i >= 0) {
+            self = i;
+        } else {
+            self = 0;
+        }
+    }
 };
 
-inline void Int_toString(const StringImportCallback& self, int value)
-{
-  Int_exportString(value, self);
-}
-typedef ConstReferenceCaller1<StringImportCallback, int, Int_toString> IntToString;
-
-
-template<typename Caller>
-inline StringImportCallback makeIntStringImportCallback(const Caller& caller)
-{
-  return StringImportCallback(caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type, Caller, IntFromString>::thunk);
-}
-
-template<typename Caller>
-inline StringExportCallback makeIntStringExportCallback(const Caller& caller)
-{
-  return StringExportCallback(caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type, Caller, IntToString>::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;
-  }
+template<>
+struct PropertyImpl<float, const char *> {
+       static void Export(const float &self, const Callback<void(const char *)> &returnz) {
+               char buffer[16];
+               sprintf(buffer, "%g", self);
+               returnz(buffer);
+       }
+
+    static void Import(float &self, const char *value) {
+        if (!string_parse_float(value, self)) {
+            self = 0;
+        }
+    }
 };
 
-inline void Size_toString(const StringImportCallback& self, std::size_t value)
-{
-  Size_exportString(value, self);
-}
-typedef ConstReferenceCaller1<StringImportCallback, std::size_t, Size_toString> SizeToString;
-
-
-template<typename Caller>
-inline StringImportCallback makeSizeStringImportCallback(const Caller& caller)
-{
-  return StringImportCallback(caller.getEnvironment(), ImportConvert1<StringImportCallback::first_argument_type, Caller, SizeFromString>::thunk);
-}
-
-template<typename Caller>
-inline StringExportCallback makeSizeStringExportCallback(const Caller& caller)
-{
-  return StringExportCallback(caller.getEnvironment(), ImportConvert1<StringExportCallback::first_argument_type, Caller, SizeToString>::thunk);
-}
+template<>
+struct PropertyImpl<Vector3, const char *> {
+       static void Export(const Vector3 &self, const Callback<void(const char *)> &returnz) {
+               char buffer[64];
+               sprintf(buffer, "%g %g %g", self[0], self[1], self[2]);
+               returnz(buffer);
+       }
+
+    static void Import(Vector3 &self, const char *value) {
+        if (!string_parse_vector3(value, self)) {
+            self = Vector3(0, 0, 0);
+        }
+    }
+};
 
 #endif