Nasal String wrapper and allow adding methods to string objects.
- Add nasal::String for wrapping Nasal string data and accessing string methods (which eg. could be exposed to Nasal) - Allow adding functions from C/C++ which are callable on Nasal strings.
This commit is contained in:
@@ -441,14 +441,17 @@ static const char* getMember_r(naContext ctx, naRef obj, naRef field, naRef* out
|
|||||||
naRef p;
|
naRef p;
|
||||||
struct VecRec* pv;
|
struct VecRec* pv;
|
||||||
if(--count < 0) return "too many parents";
|
if(--count < 0) return "too many parents";
|
||||||
if(!IS_HASH(obj) && !IS_GHOST(obj)) return "non-objects have no members";
|
|
||||||
|
|
||||||
if (IS_GHOST(obj)) {
|
if (IS_GHOST(obj)) {
|
||||||
if (ghostGetMember(ctx, obj, field, out)) return "";
|
if (ghostGetMember(ctx, obj, field, out)) return "";
|
||||||
if(!ghostGetMember(ctx, obj, globals->parentsRef, &p)) return 0;
|
if(!ghostGetMember(ctx, obj, globals->parentsRef, &p)) return 0;
|
||||||
} else {
|
} else if (IS_HASH(obj)) {
|
||||||
if(naHash_get(obj, field, out)) return "";
|
if(naHash_get(obj, field, out)) return "";
|
||||||
if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
|
if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
|
||||||
|
} else if (IS_STR(obj) ) {
|
||||||
|
return getMember_r(ctx, getStringMethods(ctx), field, out, count);
|
||||||
|
} else {
|
||||||
|
return "non-objects have no members";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!IS_VEC(p)) return "object \"parents\" field not vector";
|
if(!IS_VEC(p)) return "object \"parents\" field not vector";
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ include (SimGearComponent)
|
|||||||
set(HEADERS
|
set(HEADERS
|
||||||
Ghost.hxx
|
Ghost.hxx
|
||||||
NasalHash.hxx
|
NasalHash.hxx
|
||||||
|
NasalString.hxx
|
||||||
from_nasal_detail.hxx
|
from_nasal_detail.hxx
|
||||||
from_nasal.hxx
|
from_nasal.hxx
|
||||||
nasal_traits.hxx
|
nasal_traits.hxx
|
||||||
@@ -11,6 +12,7 @@ set(HEADERS
|
|||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
NasalHash.cxx
|
NasalHash.cxx
|
||||||
|
NasalString.cxx
|
||||||
from_nasal.cxx
|
from_nasal.cxx
|
||||||
to_nasal.cxx
|
to_nasal.cxx
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
// Wrapper class for Nasal strings
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library 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
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#include "NasalString.hxx"
|
||||||
|
#include "to_nasal.hxx"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace nasal
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate (eg. for std::find_if) returning true if no character of the
|
||||||
|
* stored string given by the range [begin, end) matches.
|
||||||
|
*/
|
||||||
|
struct no_match:
|
||||||
|
public std::unary_function<const char, bool>
|
||||||
|
{
|
||||||
|
no_match(const char* begin, const char* end):
|
||||||
|
_begin(begin),
|
||||||
|
_end(end)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator()(const char c) const
|
||||||
|
{
|
||||||
|
return std::find(_begin, _end, c) == _end;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* _begin;
|
||||||
|
const char* _end;
|
||||||
|
};
|
||||||
|
|
||||||
|
//template<typename Iterator>
|
||||||
|
//Iterator
|
||||||
|
//rfind_first_of( Iterator rbegin_src, Iterator rend_src,
|
||||||
|
// Iterator begin_find, Iterator end_find )
|
||||||
|
//{
|
||||||
|
// for(; rbegin_src != rend_src; --rbegin_src)
|
||||||
|
// {
|
||||||
|
// for(Iterator chr = begin_find; chr != end_find; ++chr)
|
||||||
|
// {
|
||||||
|
// if( *rbegin_src == *chr )
|
||||||
|
// return rbegin_src;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return rend_src;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
const size_t String::npos = static_cast<size_t>(-1);
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
String::String(naContext c, const char* str):
|
||||||
|
_str( to_nasal(c, str) )
|
||||||
|
{
|
||||||
|
assert( naIsString(_str) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
String::String(naRef str):
|
||||||
|
_str(str)
|
||||||
|
{
|
||||||
|
assert( naIsString(_str) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
const char* String::c_str() const
|
||||||
|
{
|
||||||
|
return naStr_data(_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
const char* String::begin() const
|
||||||
|
{
|
||||||
|
return c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
const char* String::end() const
|
||||||
|
{
|
||||||
|
return c_str() + size();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
size_t String::size() const
|
||||||
|
{
|
||||||
|
return naStr_len(_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
size_t String::length() const
|
||||||
|
{
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool String::empty() const
|
||||||
|
{
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
int String::compare(size_t pos, size_t len, const String& rhs) const
|
||||||
|
{
|
||||||
|
if( pos >= size() )
|
||||||
|
throw std::out_of_range("nasal::String::compare: pos");
|
||||||
|
|
||||||
|
return memcmp( begin() + pos,
|
||||||
|
rhs.begin(),
|
||||||
|
std::min(rhs.size(), std::min(size() - pos, len)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool String::starts_with(const String& rhs) const
|
||||||
|
{
|
||||||
|
return rhs.size() <= size() && compare(0, npos, rhs) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
size_t String::find(const char c, size_t pos) const
|
||||||
|
{
|
||||||
|
if( pos >= size() )
|
||||||
|
return npos;
|
||||||
|
|
||||||
|
const char* result = std::find(begin() + pos, end(), c);
|
||||||
|
|
||||||
|
return result != end() ? result - begin() : npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
size_t String::find_first_of(const String& chr, size_t pos) const
|
||||||
|
{
|
||||||
|
if( pos >= size() )
|
||||||
|
return npos;
|
||||||
|
|
||||||
|
const char* result = std::find_first_of( begin() + pos, end(),
|
||||||
|
chr.begin(), chr.end() );
|
||||||
|
|
||||||
|
return result != end() ? result - begin() : npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
size_t String::find_first_not_of(const String& chr, size_t pos) const
|
||||||
|
{
|
||||||
|
if( pos >= size() )
|
||||||
|
return npos;
|
||||||
|
|
||||||
|
const char* result = std::find_if( begin() + pos, end(),
|
||||||
|
no_match(chr.begin(), chr.end()) );
|
||||||
|
|
||||||
|
return result != end() ? result - begin() : npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
const naRef String::get_naRef() const
|
||||||
|
{
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nasal
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
///@file Wrapper class for Nasal strings
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library 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
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#ifndef SG_NASAL_STRING_HXX_
|
||||||
|
#define SG_NASAL_STRING_HXX_
|
||||||
|
|
||||||
|
#include "from_nasal.hxx"
|
||||||
|
#include "to_nasal.hxx"
|
||||||
|
|
||||||
|
namespace nasal
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Nasal String
|
||||||
|
*/
|
||||||
|
class String
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const size_t npos;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Nasal String
|
||||||
|
*
|
||||||
|
* @param c Nasal context for creating the string
|
||||||
|
* @param str String data
|
||||||
|
*/
|
||||||
|
String(naContext c, const char* str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize from an existing Nasal String
|
||||||
|
*
|
||||||
|
* @param str Existing Nasal String
|
||||||
|
*/
|
||||||
|
String(naRef string);
|
||||||
|
|
||||||
|
const char* c_str() const;
|
||||||
|
const char* begin() const;
|
||||||
|
const char* end() const;
|
||||||
|
|
||||||
|
size_t size() const;
|
||||||
|
size_t length() const;
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
int compare(size_t pos, size_t len, const String& rhs) const;
|
||||||
|
bool starts_with(const String& rhs) const;
|
||||||
|
|
||||||
|
size_t find(const char c, size_t pos = 0) const;
|
||||||
|
size_t find_first_of(const String& chr, size_t pos = 0) const;
|
||||||
|
size_t find_first_not_of(const String& chr, size_t pos = 0) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Nasal representation of String
|
||||||
|
*/
|
||||||
|
const naRef get_naRef() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
naRef _str;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace nasal
|
||||||
|
|
||||||
|
#endif /* SG_NASAL_STRING_HXX_ */
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Ghost.hxx"
|
#include "Ghost.hxx"
|
||||||
#include "NasalHash.hxx"
|
#include "NasalHash.hxx"
|
||||||
|
#include "NasalString.hxx"
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
@@ -111,6 +112,27 @@ int main(int argc, char* argv[])
|
|||||||
Hash mod = hash.createHash("mod");
|
Hash mod = hash.createHash("mod");
|
||||||
mod.set("parent", hash);
|
mod.set("parent", hash);
|
||||||
|
|
||||||
|
String string( to_nasal(c, "Test") );
|
||||||
|
VERIFY( from_nasal<std::string>(c, string.get_naRef()) == "Test" );
|
||||||
|
VERIFY( string.c_str() == std::string("Test") );
|
||||||
|
VERIFY( string.starts_with(string) );
|
||||||
|
VERIFY( string.starts_with(String(c, "T")) );
|
||||||
|
VERIFY( string.starts_with(String(c, "Te")) );
|
||||||
|
VERIFY( string.starts_with(String(c, "Tes")) );
|
||||||
|
VERIFY( string.starts_with(String(c, "Test")) );
|
||||||
|
VERIFY( !string.starts_with(String(c, "Test1")) );
|
||||||
|
VERIFY( !string.starts_with(String(c, "bb")) );
|
||||||
|
VERIFY( !string.starts_with(String(c, "bbasdasdafasd")) );
|
||||||
|
VERIFY( string.find('e') == 1 );
|
||||||
|
VERIFY( string.find('9') == String::npos );
|
||||||
|
VERIFY( string.find_first_of(String(c, "st")) == 2 );
|
||||||
|
VERIFY( string.find_first_of(String(c, "st"), 3) == 3 );
|
||||||
|
VERIFY( string.find_first_of(String(c, "xyz")) == String::npos );
|
||||||
|
VERIFY( string.find_first_not_of(String(c, "Tst")) == 1 );
|
||||||
|
VERIFY( string.find_first_not_of(String(c, "Tse"), 2) == 3 );
|
||||||
|
VERIFY( string.find_first_not_of(String(c, "abc")) == 0 );
|
||||||
|
VERIFY( string.find_first_not_of(String(c, "abc"), 20) == String::npos );
|
||||||
|
|
||||||
Ghost<BasePtr>::init("BasePtr")
|
Ghost<BasePtr>::init("BasePtr")
|
||||||
.method<&Base::member>("member")
|
.method<&Base::member>("member")
|
||||||
.member("str", &Base::getString, &Base::setString);
|
.member("str", &Base::getString, &Base::setString);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "from_nasal_detail.hxx"
|
#include "from_nasal_detail.hxx"
|
||||||
#include "NasalHash.hxx"
|
#include "NasalHash.hxx"
|
||||||
|
#include "NasalString.hxx"
|
||||||
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
@@ -70,4 +71,13 @@ namespace nasal
|
|||||||
return Hash(ref, c);
|
return Hash(ref, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
String from_nasal_helper(naContext c, naRef ref, String*)
|
||||||
|
{
|
||||||
|
if( !naIsString(ref) )
|
||||||
|
throw bad_nasal_cast("Not a string");
|
||||||
|
|
||||||
|
return String(ref);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace nasal
|
} // namespace nasal
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class SGPath;
|
|||||||
namespace nasal
|
namespace nasal
|
||||||
{
|
{
|
||||||
class Hash;
|
class Hash;
|
||||||
|
class String;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when converting a type from/to Nasal has failed
|
* Thrown when converting a type from/to Nasal has failed
|
||||||
@@ -87,6 +88,11 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
Hash from_nasal_helper(naContext c, naRef ref, Hash*);
|
Hash from_nasal_helper(naContext c, naRef ref, Hash*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Nasal string to a nasal::String
|
||||||
|
*/
|
||||||
|
String from_nasal_helper(naContext c, naRef ref, String*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a Nasal number to a C++ numeric type
|
* Convert a Nasal number to a C++ numeric type
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -119,6 +119,9 @@ naRef naInit_readline(naContext c);
|
|||||||
naRef naInit_gtk(naContext ctx);
|
naRef naInit_gtk(naContext ctx);
|
||||||
naRef naInit_cairo(naContext ctx);
|
naRef naInit_cairo(naContext ctx);
|
||||||
|
|
||||||
|
// Returns a hash which can be used to add methods callable on strings
|
||||||
|
naRef naInit_string(naContext c);
|
||||||
|
|
||||||
// Context stack inspection, frame zero is the "top"
|
// Context stack inspection, frame zero is the "top"
|
||||||
int naStackDepth(naContext ctx);
|
int naStackDepth(naContext ctx);
|
||||||
int naGetLine(naContext ctx, int frame);
|
int naGetLine(naContext ctx, int frame);
|
||||||
@@ -159,6 +162,7 @@ naRef naStr_fromdata(naRef dst, const char* data, int len);
|
|||||||
naRef naStr_concat(naRef dest, naRef s1, naRef s2);
|
naRef naStr_concat(naRef dest, naRef s1, naRef s2);
|
||||||
naRef naStr_substr(naRef dest, naRef str, int start, int len);
|
naRef naStr_substr(naRef dest, naRef str, int start, int len);
|
||||||
naRef naInternSymbol(naRef sym);
|
naRef naInternSymbol(naRef sym);
|
||||||
|
naRef getStringMethods(naContext c);
|
||||||
|
|
||||||
// Vector utilities:
|
// Vector utilities:
|
||||||
int naVec_size(naRef v);
|
int naVec_size(naRef v);
|
||||||
|
|||||||
@@ -320,3 +320,27 @@ static int fromnum(double val, unsigned char* s)
|
|||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
return ptr - s;
|
return ptr - s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static naRef string_methods;
|
||||||
|
static int init = 0; // As we can't use naNil() for static initialization we
|
||||||
|
// need a separate variable for saving whether we have
|
||||||
|
// already initialized.
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
naRef naInit_string(naContext c)
|
||||||
|
{
|
||||||
|
string_methods = naNewHash(c);
|
||||||
|
init = 1;
|
||||||
|
return string_methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
naRef getStringMethods(naContext c)
|
||||||
|
{
|
||||||
|
if( !init )
|
||||||
|
return naNil();
|
||||||
|
|
||||||
|
return string_methods;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user