#endif
#include "props.hxx"
-#include "PropertyInterpolationMgr.hxx"
-#include "vectorPropTemplates.hxx"
#include <algorithm>
#include <limits>
#include <stdio.h>
#include <string.h>
-#include <boost/algorithm/string/find_iterator.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/bind.hpp>
-#include <boost/functional/hash.hpp>
-#include <boost/range.hpp>
-
#if PROPS_STANDALONE
-#include <iostream>
+# include <iostream>
+using std::cerr;
#else
-
-#include <simgear/compiler.h>
-#include <simgear/debug/logstream.hxx>
-
-#if ( _MSC_VER == 1200 )
+# include <boost/algorithm/string/find_iterator.hpp>
+# include <boost/algorithm/string/predicate.hpp>
+# include <boost/algorithm/string/classification.hpp>
+# include <boost/bind.hpp>
+# include <boost/functional/hash.hpp>
+# include <boost/range.hpp>
+# include <simgear/compiler.h>
+# include <simgear/debug/logstream.hxx>
+
+# include "PropertyInterpolationMgr.hxx"
+# include "vectorPropTemplates.hxx"
+
+# if ( _MSC_VER == 1200 )
// MSVC 6 is buggy, and needs something strange here
using std::vector<SGPropertyNode_ptr>;
using std::vector<SGPropertyChangeListener *>;
using std::vector<SGPropertyNode *>;
-#endif
+# endif
#endif
-#if PROPS_STANDALONE
-using std::cerr;
-#endif
using std::endl;
using std::find;
using std::sort;
// Local path normalization code.
////////////////////////////////////////////////////////////////////////
+#if PROPS_STANDALONE
+struct PathComponent
+{
+ string name;
+ int index;
+};
+#endif
+
/**
* Parse the name for a path component.
*
return false;
if (!isalpha(name[0]) && name[0] != '_')
return false;
+#if PROPS_STANDALONE
+ std::string is_any_of("_-.");
+ bool rv = true;
+ for(unsigned i=1; i<name.length(); ++i) {
+ if (!isalnum(name[i]) && is_any_of.find(name[i]) == std::string::npos) {
+ rv = false;
+ break;
+ }
+ }
+ return rv;
+#else
return all(make_iterator_range(name.begin(), name.end()),
is_alnum() || is_any_of("_-."));
+#endif
+}
+
+#if PROPS_STANDALONE
+/**
+ * Parse the name for a path component.
+ *
+ * Name: [_a-zA-Z][-._a-zA-Z0-9]*
+ */
+static inline const string
+parse_name (const string &path, int &i)
+{
+ string name = "";
+ int max = (int)path.size();
+
+ if (path[i] == '.') {
+ i++;
+ if (i < max && path[i] == '.') {
+ i++;
+ name = "..";
+ } else {
+ name = ".";
+ }
+ if (i < max && path[i] != '/')
+ throw string("Illegal character after " + name);
+ }
+
+ else if (isalpha(path[i]) || path[i] == '_') {
+ name += path[i];
+ i++;
+
+ // The rules inside a name are a little
+ // less restrictive.
+ while (i < max) {
+ if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
+ path[i] == '-' || path[i] == '.') {
+ name += path[i];
+ } else if (path[i] == '[' || path[i] == '/') {
+ break;
+ } else {
+ throw string("name may contain only ._- and alphanumeric characters");
+ }
+ i++;
+ }
+ }
+
+ else {
+ if (name.size() == 0)
+ throw string("name must begin with alpha or '_'");
+ }
+
+ return name;
+}
+
+
+/**
+ * Parse the optional integer index for a path component.
+ *
+ * Index: "[" [0-9]+ "]"
+ */
+static inline int
+parse_index (const string &path, int &i)
+{
+ int index = 0;
+
+ if (path[i] != '[')
+ return 0;
+ else
+ i++;
+
+ for (int max = (int)path.size(); i < max; i++) {
+ if (isdigit(path[i])) {
+ index = (index * 10) + (path[i] - '0');
+ } else if (path[i] == ']') {
+ i++;
+ return index;
+ } else {
+ break;
+ }
+ }
+
+ throw string("unterminated index (looking for ']')");
}
+/**
+ * Parse a single path component.
+ *
+ * Component: Name Index?
+ */
+static inline PathComponent
+parse_component (const string &path, int &i)
+{
+ PathComponent component;
+ component.name = parse_name(path, i);
+ if (component.name[0] != '.')
+ component.index = parse_index(path, i);
+ else
+ component.index = -1;
+ return component;
+}
+
+/**
+ * Parse a path into its components.
+ */
+static void
+parse_path (const string &path, vector<PathComponent> &components)
+{
+ int pos = 0;
+ int max = (int)path.size();
+
+ // Check for initial '/'
+ if (path[pos] == '/') {
+ PathComponent root;
+ root.name = "";
+ root.index = -1;
+ components.push_back(root);
+ pos++;
+ while (pos < max && path[pos] == '/')
+ pos++;
+ }
+
+ while (pos < max) {
+ components.push_back(parse_component(path, pos));
+ while (pos < max && path[pos] == '/')
+ pos++;
+ }
+}
+#endif
+
+
////////////////////////////////////////////////////////////////////////
// Other static utility functions.
////////////////////////////////////////////////////////////////////////
find_child (Itr begin, Itr end, int index, const PropertyList& nodes)
{
size_t nNodes = nodes.size();
+#if PROPS_STANDALONE
+ for (int i = 0; i < nNodes; i++) {
+ SGPropertyNode * node = nodes[i];
+ if (node->getIndex() == index && compare_strings(node->getName(), begin))
+ return i;
+ }
+#else
boost::iterator_range<Itr> name(begin, end);
for (size_t i = 0; i < nNodes; i++) {
SGPropertyNode * node = nodes[i];
if (node->getIndex() == index && boost::equals(node->getName(), name))
return static_cast<int>(i);
}
+#endif
return -1;
}
// Internal function for parsing property paths. last_index provides
// and index value for the last node name token, if supplied.
+#if PROPS_STANDALONE
+static SGPropertyNode *
+find_node (SGPropertyNode * current,
+ const vector<PathComponent> &components,
+ int position,
+ bool create)
+{
+ // Run off the end of the list
+ if (current == 0) {
+ return 0;
+ }
+
+ // Success! This is the one we want.
+ else if (position >= (int)components.size()) {
+ return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
+ }
+
+ // Empty component means root.
+ else if (components[position].name == "") {
+ return find_node(current->getRootNode(), components, position + 1, create);
+ }
+
+ // . means current directory
+ else if (components[position].name == ".") {
+ return find_node(current, components, position + 1, create);
+ }
+
+ // .. means parent directory
+ else if (components[position].name == "..") {
+ SGPropertyNode * parent = current->getParent();
+ if (parent == 0)
+ throw string("Attempt to move past root with '..'");
+ else
+ return find_node(parent, components, position + 1, create);
+ }
+
+ // Otherwise, a child name
+ else {
+ SGPropertyNode * child =
+ current->getChild(components[position].name.c_str(),
+ components[position].index,
+ create);
+ return find_node(child, components, position + 1, create);
+ }
+}
+#else
template<typename Range>
SGPropertyNode*
find_node (SGPropertyNode * current,
const Range& path,
- bool create,
+ bool create,
int last_index = -1)
{
using namespace boost;
else
return find_node_aux(current, itr, create, last_index);
}
+#endif
////////////////////////////////////////////////////////////////////////
// Private methods from SGPropertyNode (may be inlined for speed).
void
SGPropertyNode::trace_write () const
{
-#if PROPS_STANDALONE
- cerr << "TRACE: Write node " << getPath () << ", value \""
- << make_string() << '"' << endl;
-#else
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
<< ", value \"" << make_string() << '"');
-#endif
}
/**
void
SGPropertyNode::trace_read () const
{
-#if PROPS_STANDALONE
- cerr << "TRACE: Write node " << getPath () << ", value \""
- << make_string() << '"' << endl;
-#else
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
<< ", value \"" << make_string() << '"');
-#endif
}
////////////////////////////////////////////////////////////////////////
return true;
}
-#if PROPS_STANDALONE
-#else
if (!target)
{
SG_LOG(SG_GENERAL, SG_ALERT,
SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create alias at " << target->getPath() << ". "
"Source " << getPath() << " is a tied property.");
}
-#endif
return false;
}
SGPropertyNode *
SGPropertyNode::getChild (const std::string& name, int index, bool create)
{
+#if PROPS_STANDALONE
+ const char *n = name.c_str();
+ int pos = find_child(n, n + strlen(n), index, _children);
+ if (pos >= 0) {
+ return _children[pos];
+#else
SGPropertyNode* node = getExistingChild(name.begin(), name.end(), index);
if (node) {
return node;
+#endif
} else if (create) {
- node = new SGPropertyNode(name, index, this);
+ SGPropertyNode* node = new SGPropertyNode(name, index, this);
_children.push_back(node);
fireChildAdded(node);
return node;
case props::UNSPECIFIED:
result = set_string(value);
break;
+#if !PROPS_STANDALONE
case props::VEC3D:
result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
break;
case props::VEC4D:
result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
break;
+#endif
case props::NONE:
default:
break;
}
//------------------------------------------------------------------------------
+#if !PROPS_STANDALONE
bool SGPropertyNode::interpolate( const std::string& type,
const SGPropertyNode& target,
double duration,
}
simgear::PropertyInterpolationMgr* SGPropertyNode::_interpolation_mgr = 0;
+#endif
//------------------------------------------------------------------------------
std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
SGPropertyNode *
SGPropertyNode::getNode (const char * relative_path, bool create)
{
+#if PROPS_STANDALONE
+ vector<PathComponent> components;
+ parse_path(relative_path, components);
+ return find_node(this, components, 0, create);
+
+#else
using namespace boost;
return find_node(this, make_iterator_range(relative_path, relative_path
+ strlen(relative_path)),
create);
+#endif
}
SGPropertyNode *
SGPropertyNode::getNode (const char * relative_path, int index, bool create)
{
+#if PROPS_STANDALONE
+ vector<PathComponent> components;
+ parse_path(relative_path, components);
+ if (components.size() > 0)
+ components.back().index = index;
+ return find_node(this, components, 0, create);
+
+#else
using namespace boost;
+
return find_node(this, make_iterator_range(relative_path, relative_path
+ strlen(relative_path)),
create, index);
+#endif
}
const SGPropertyNode *
_properties.erase(it);
}
+#if !PROPS_STANDALONE
template<>
std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
{
}
return stream;
}
+#endif
namespace simgear
{
+#if !PROPS_STANDALONE
template<>
std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
{
}
return stream;
}
+#endif
namespace
{
case props::STRING:
case props::UNSPECIFIED:
return !strcmp(lhs.getStringValue(), rhs.getStringValue());
+#if !PROPS_STANDALONE
case props::VEC3D:
return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
case props::VEC4D:
return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
+#endif
default:
return false;
}
}
};
+#if !PROPS_STANDALONE
size_t hash_value(const SGPropertyNode& node)
{
using namespace boost;
-
if (node.nChildren() == 0) {
switch (node.getType()) {
case props::NONE:
return seed;
}
}
+#endif
// end of props.cxx
#include <sstream>
#include <typeinfo>
-#include <boost/utility.hpp>
-#include <boost/type_traits/is_enum.hpp>
-
-#if PROPS_STANDALONE
-#else
#include <simgear/compiler.h>
-#include <simgear/debug/logstream.hxx>
+#if PROPS_STANDALONE
+// taken from: boost/utility/enable_if.hpp
+#ifndef SG_LOG
+# define SG_GENERAL 0
+# define SG_ALERT 0
+# define SG_WARN 1
+# define SG_LOG(type, level, message) (type) ? (std::cerr <<message << endl) : (std::cout <<message << endl)
#endif
+namespace boost {
+ template <bool B, class T = void>
+ struct enable_if_c {
+ typedef T type;
+ };
+
+ template <class T>
+ struct enable_if_c<false, T> {};
+ template <class Cond, class T = void>
+ struct enable_if : public enable_if_c<Cond::value, T> {};
-#include <simgear/math/SGMathFwd.hxx>
-#include <simgear/math/sg_types.hxx>
+ template <bool B, class T = void>
+ struct disable_if_c {
+ typedef T type;
+ };
+
+ template <class T>
+ struct disable_if_c<true, T> {};
+
+ template <class Cond, class T = void>
+ struct disable_if : public disable_if_c<Cond::value, T> {};
+}
+#else
+# include <boost/utility.hpp>
+# include <boost/type_traits/is_enum.hpp>
+
+# include <simgear/debug/logstream.hxx>
+# include <simgear/math/SGMathFwd.hxx>
+# include <simgear/math/sg_types.hxx>
+#endif
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
// XXX This whole file should be in the simgear namespace, but I don't
// have the guts yet...
+using namespace std;
+
namespace simgear
{
return ret;
}
+#if !PROPS_STANDALONE
/**
* Interpolate current value to target value within given time.
*
* Get the interpolation manager
*/
static simgear::PropertyInterpolationMgr* getInterpolationMgr();
+#endif
/**
* Print the value of the property to a stream.
// Convenience functions for use in templates
template<typename T>
+#if PROPS_STANDALONE
+T
+#else
typename boost::disable_if<boost::is_enum<T>, T>::type
+#endif
getValue(const SGPropertyNode*);
template<>
/** Extract enum from SGPropertyNode */
template<typename T>
+#if PROPS_STANDALONE
+inline T
+#else
inline typename boost::enable_if<boost::is_enum<T>, T>::type
+#endif
getValue(const SGPropertyNode* node)
{
typedef simgear::enum_traits<T> Traits;