From 50e226a1467d53d9bcb2987d0b6cfb58beb66c9c Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 24 Aug 2011 09:46:20 +0100 Subject: [PATCH 1/8] Change IPAddress to use getaddrinfo internally, and store the sockaddr data via a pointer --- simgear/io/raw_socket.cxx | 100 ++++++++++++++++++++--------------- simgear/io/raw_socket.hxx | 35 ++++++------ simgear/io/sg_netChannel.cxx | 1 + 3 files changed, 73 insertions(+), 63 deletions(-) diff --git a/simgear/io/raw_socket.cxx b/simgear/io/raw_socket.cxx index 63c9b55e..8bcae985 100644 --- a/simgear/io/raw_socket.cxx +++ b/simgear/io/raw_socket.cxx @@ -25,8 +25,7 @@ #endif #include - -#include "sg_socket.hxx" +#include "raw_socket.hxx" #if defined(_WIN32) && !defined(__CYGWIN__) # define WINSOCK // use winsock convetions, otherwise standard POSIX @@ -37,6 +36,7 @@ #include #include #include // for snprintf +#include #if defined(WINSOCK) # include @@ -67,44 +67,49 @@ IPAddress::IPAddress ( const char* host, int port ) set ( host, port ) ; } - void IPAddress::set ( const char* host, int port ) { - memset(this, 0, sizeof(IPAddress)); + addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); + memset(addr, 0, sizeof(struct sockaddr_in)); - sin_family = AF_INET ; - sin_port = htons (port); + addr->sin_family = AF_INET ; + addr->sin_port = htons (port); /* Convert a string specifying a host name or one of a few symbolic - ** names to a numeric IP address. This usually calls gethostbyname() + ** names to a numeric IP address. This usually calls getaddrinfo() ** to do the work; the names "" and "" are special. */ if (!host || host[0] == '\0') { - sin_addr = INADDR_ANY; + addr->sin_addr.s_addr = INADDR_ANY; return; } if (strcmp(host, "") == 0) { - sin_addr = INADDR_BROADCAST; + addr->sin_addr.s_addr = INADDR_BROADCAST; return; } - sin_addr = inet_addr ( host ) ; - if (sin_addr != INADDR_NONE) { - return; + struct addrinfo* result = NULL; + int err = getaddrinfo(host, NULL, NULL /* no hints */, &result); + if (err) { + SG_LOG(SG_IO, SG_WARN, "getaddrinfo failed for '" << host << "' : " << gai_strerror(err)); + } else if (result->ai_addrlen != getAddrLen()) { + SG_LOG(SG_IO, SG_ALERT, "mismatch in socket address sizes"); + } else { + memcpy(addr, result->ai_addr, result->ai_addrlen); } -// finally, try gethostbyname - struct hostent *hp = gethostbyname ( host ) ; - if (!hp) { - SG_LOG(SG_IO, SG_WARN, "gethostbyname failed for " << host); - sin_addr = INADDR_ANY ; - return; - } - - memcpy ( (char *) &sin_addr, hp->h_addr, hp->h_length ) ; + + freeaddrinfo(result); + addr->sin_port = htons (port); // fix up port after getaddrinfo } +IPAddress::~IPAddress() +{ + if (addr) { + free (addr); + } +} /* Create a string object representing an IP address. This is always a string of the form 'dd.dd.dd.dd' (with variable @@ -112,31 +117,27 @@ void IPAddress::set ( const char* host, int port ) const char* IPAddress::getHost () const { -#if 0 - const char* buf = inet_ntoa ( sin_addr ) ; -#else static char buf [32]; - long x = ntohl(sin_addr); + long x = ntohl(addr->sin_addr.s_addr); sprintf(buf, "%d.%d.%d.%d", (int) (x>>24) & 0xff, (int) (x>>16) & 0xff, (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff ); -#endif return buf; } unsigned int IPAddress::getIP () const { - return sin_addr; + return addr->sin_addr.s_addr; } unsigned int IPAddress::getPort() const { - return ntohs(sin_port); + return ntohs(addr->sin_port); } unsigned int IPAddress::getFamily () const { - return sin_family; + return addr->sin_family; } const char* IPAddress::getLocalHost () @@ -163,9 +164,18 @@ const char* IPAddress::getLocalHost () bool IPAddress::getBroadcast () const { - return sin_addr == INADDR_BROADCAST; + return (addr->sin_addr.s_addr == INADDR_BROADCAST); } +unsigned int IPAddress::getAddrLen() const +{ + return sizeof(struct sockaddr_in); +} + +struct sockaddr* IPAddress::getAddr() const +{ + return (struct sockaddr*) addr; +} Socket::Socket () { @@ -262,8 +272,8 @@ int Socket::bind ( const char* host, int port ) IPAddress addr ( host, port ) ; #if !defined(WINSOCK) - if( (result = ::bind(handle,(const sockaddr*)&addr,sizeof(IPAddress))) < 0 ) { - SG_LOG(SG_IO, SG_ALERT, "bind(" << host << ":" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")"); + if( (result = ::bind(handle, addr.getAddr(), addr.getAddrLen() ) ) < 0 ) { + SG_LOG(SG_IO, SG_ALERT, "bind(" << addr.getHost() << ":" << addr.getPort() << ") failed. Errno " << errno << " (" << strerror(errno) << ")"); return result; } #endif @@ -294,7 +304,7 @@ int Socket::bind ( const char* host, int port ) } } #if defined(WINSOCK) - else if( (result = ::bind(handle,(const sockaddr*)&addr,sizeof(IPAddress))) < 0 ) { + else if( (result = ::bind(handle,addr->getAddr(), addr->getAddrLen())) < 0 ) { SG_LOG(SG_IO, SG_ALERT, "bind(" << host << ":" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")"); return result; } @@ -321,20 +331,26 @@ int Socket::accept ( IPAddress* addr ) } else { - socklen_t addr_len = (socklen_t) sizeof(IPAddress) ; - return ::accept(handle,(sockaddr*)addr,&addr_len); + socklen_t addr_len = addr->getAddrLen(); ; + return ::accept(handle, addr->getAddr(), &addr_len); } } int Socket::connect ( const char* host, int port ) { - assert ( handle != -1 ) ; IPAddress addr ( host, port ) ; - if ( addr.getBroadcast() ) { + return connect ( &addr ); +} + + +int Socket::connect ( IPAddress* addr ) +{ + assert ( handle != -1 ) ; + if ( addr->getBroadcast() ) { setBroadcast( true ); } - return ::connect(handle,(const sockaddr*)&addr,sizeof(IPAddress)); + return ::connect(handle, addr->getAddr(), addr->getAddrLen() ); } @@ -350,7 +366,7 @@ int Socket::sendto ( const void * buffer, int size, { assert ( handle != -1 ) ; return ::sendto(handle,(const char*)buffer,size,flags, - (const sockaddr*)to,sizeof(IPAddress)); + (const sockaddr*) to->getAddr(), to->getAddrLen()); } @@ -365,8 +381,8 @@ int Socket::recvfrom ( void * buffer, int size, int flags, IPAddress* from ) { assert ( handle != -1 ) ; - socklen_t fromlen = (socklen_t) sizeof(IPAddress) ; - return ::recvfrom(handle,(char*)buffer,size,flags,(sockaddr*)from,&fromlen); + socklen_t fromlen = (socklen_t) from->getAddrLen() ; + return ::recvfrom(handle,(char*)buffer,size,flags, from->getAddr(),&fromlen); } @@ -526,8 +542,6 @@ static void netExit ( void ) int Socket::initSockets() { - assert ( sizeof(sockaddr_in) == sizeof(IPAddress) ) ; - #if defined(WINSOCK) /* Start up the windows networking */ WORD version_wanted = MAKEWORD(1,1); diff --git a/simgear/io/raw_socket.hxx b/simgear/io/raw_socket.hxx index 4eb30448..6ae529f2 100644 --- a/simgear/io/raw_socket.hxx +++ b/simgear/io/raw_socket.hxx @@ -23,12 +23,15 @@ #ifndef SG_IO_SOCKET_HXX #define SG_IO_SOCKET_HXX -#include +//#include -#if defined(__APPLE__) || defined(__FreeBSD__) -# include -#endif +//#if defined(__APPLE__) || defined(__FreeBSD__) +//# include +//#endif +struct sockaddr_in; +struct sockaddr; + namespace simgear { @@ -37,24 +40,12 @@ namespace simgear */ class IPAddress { - /* DANGER!!! This MUST match 'struct sockaddr_in' exactly! */ -#if defined(__APPLE__) || defined(__FreeBSD__) - __uint8_t sin_len; - __uint8_t sin_family; - in_port_t sin_port; - in_addr_t sin_addr; - char sin_zero[8]; -#else - short sin_family ; - unsigned short sin_port ; - unsigned int sin_addr ; - char sin_zero [ 8 ] ; -#endif - + struct sockaddr_in* addr; public: - IPAddress () {} + IPAddress () : addr(0) {} IPAddress ( const char* host, int port ) ; - + ~IPAddress(); + void set ( const char* host, int port ) ; const char* getHost () const ; unsigned int getPort() const ; @@ -63,6 +54,9 @@ public: static const char* getLocalHost () ; bool getBroadcast () const ; + + unsigned int getAddrLen() const; + sockaddr* getAddr() const; }; @@ -89,6 +83,7 @@ public: int listen ( int backlog ) ; int accept ( IPAddress* addr ) ; int connect ( const char* host, int port ) ; + int connect ( IPAddress* addr ) ; int send ( const void * buffer, int size, int flags = 0 ) ; int sendto ( const void * buffer, int size, int flags, const IPAddress* to ) ; int recv ( void * buffer, int size, int flags = 0 ) ; diff --git a/simgear/io/sg_netChannel.cxx b/simgear/io/sg_netChannel.cxx index c6502565..c3644b6c 100644 --- a/simgear/io/sg_netChannel.cxx +++ b/simgear/io/sg_netChannel.cxx @@ -34,6 +34,7 @@ #include #include #include +#include #include From b7654c181dc8d52875365b170bc3092e8e51d68f Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 24 Aug 2011 02:30:02 -0700 Subject: [PATCH 2/8] Copy constructor and assignment operator for revised IPAddress --- simgear/io/raw_socket.cxx | 24 ++++++++++++++++++++++++ simgear/io/raw_socket.hxx | 3 +++ 2 files changed, 27 insertions(+) diff --git a/simgear/io/raw_socket.cxx b/simgear/io/raw_socket.cxx index 8bcae985..7fe2c688 100644 --- a/simgear/io/raw_socket.cxx +++ b/simgear/io/raw_socket.cxx @@ -67,6 +67,30 @@ IPAddress::IPAddress ( const char* host, int port ) set ( host, port ) ; } +IPAddress::IPAddress( const IPAddress& other ) : + addr(NULL) +{ + if (other.addr) { + addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); + memcpy(addr, other.addr, sizeof(struct sockaddr_in)); + } +} + +const IPAddress& IPAddress::operator=(const IPAddress& other) +{ + if (addr) { + free(addr); + addr = NULL; + } + + if (other.addr) { + addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); + memcpy(addr, other.addr, sizeof(struct sockaddr_in)); + } + + return *this; +} + void IPAddress::set ( const char* host, int port ) { addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); diff --git a/simgear/io/raw_socket.hxx b/simgear/io/raw_socket.hxx index 6ae529f2..2b5031f3 100644 --- a/simgear/io/raw_socket.hxx +++ b/simgear/io/raw_socket.hxx @@ -46,6 +46,9 @@ public: IPAddress ( const char* host, int port ) ; ~IPAddress(); + IPAddress( const IPAddress& other ); + const IPAddress& operator=(const IPAddress& other); + void set ( const char* host, int port ) ; const char* getHost () const ; unsigned int getPort() const ; From 3753d5099251e2e1f653939c323f11762dafb721 Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 24 Aug 2011 02:30:27 -0700 Subject: [PATCH 3/8] Fix a release build issue, meaning of IDLE state was overloaded, add an explicit state when we're waiting for the response start. --- simgear/io/HTTPClient.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/simgear/io/HTTPClient.cxx b/simgear/io/HTTPClient.cxx index 96ef25bd..fb1b812f 100644 --- a/simgear/io/HTTPClient.cxx +++ b/simgear/io/HTTPClient.cxx @@ -100,7 +100,7 @@ public: } activeRequest = r; - state = STATE_IDLE; + state = STATE_SENT_REQUEST; bodyTransferSize = -1; chunkedTransfer = false; setTerminator("\r\n"); @@ -146,7 +146,7 @@ public: virtual void foundTerminator(void) { switch (state) { - case STATE_IDLE: + case STATE_SENT_REQUEST: activeRequest->responseStart(buffer); state = STATE_GETTING_HEADERS; buffer.clear(); @@ -170,6 +170,7 @@ public: state = STATE_GETTING_CHUNKED; break; + case STATE_GETTING_TRAILER: processTrailer(); buffer.clear(); @@ -354,6 +355,7 @@ private: enum ConnectionState { STATE_IDLE = 0, + STATE_SENT_REQUEST, STATE_GETTING_HEADERS, STATE_GETTING_BODY, STATE_GETTING_CHUNKED, From fa2720735178a94efeb7954d24d6cb3e26c82b0e Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 24 Aug 2011 11:25:37 +0100 Subject: [PATCH 4/8] Include ws2tcpip.h header (for getaddrinfo) on Windows --- simgear/io/raw_socket.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/simgear/io/raw_socket.cxx b/simgear/io/raw_socket.cxx index 7fe2c688..ecc8671f 100644 --- a/simgear/io/raw_socket.cxx +++ b/simgear/io/raw_socket.cxx @@ -39,7 +39,8 @@ #include #if defined(WINSOCK) -# include +# include +# include # include #else # include From 27e891684369a466ded2146aa26b4274cbefed4c Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 24 Aug 2011 11:29:09 +0100 Subject: [PATCH 5/8] Another Windows typo-fix. --- simgear/io/raw_socket.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simgear/io/raw_socket.cxx b/simgear/io/raw_socket.cxx index ecc8671f..aaa7d871 100644 --- a/simgear/io/raw_socket.cxx +++ b/simgear/io/raw_socket.cxx @@ -329,7 +329,7 @@ int Socket::bind ( const char* host, int port ) } } #if defined(WINSOCK) - else if( (result = ::bind(handle,addr->getAddr(), addr->getAddrLen())) < 0 ) { + else if( (result = ::bind(handle,addr.getAddr(), addr.getAddrLen())) < 0 ) { SG_LOG(SG_IO, SG_ALERT, "bind(" << host << ":" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")"); return result; } From 25c388178284a772e7abd6c70ecc7de487d70d14 Mon Sep 17 00:00:00 2001 From: Christian Schmitt Date: Wed, 24 Aug 2011 13:14:36 +0200 Subject: [PATCH 6/8] fix some of the CMake syntax and correctly print the headless option --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e97a0e8a..a72da9c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ SET(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README") set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules;${CMAKE_MODULE_PATH}") option(SIMGEAR_SHARED "Set to ON to build SimGear as a shared library/framework" OFF) -option(SIMGEAR_HEADLESS "Set to ON to build SimGear with GUI/graphics support" OFF) +option(SIMGEAR_HEADLESS "Set to ON to build SimGear without GUI/graphics support" OFF) option(JPEG_FACTORY "Enable JPEG-factory support" OFF) option(ENABLE_LIBSVN "Set to ON to build SimGear with libsvnclient support" ON) @@ -53,7 +53,7 @@ set (BOOST_CXX_FLAGS "-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION -DBOOST_BIMAP_DI find_package(ZLIB REQUIRED) find_package(Threads REQUIRED) -if (${SIMGEAR_HEADLESS}) +if(SIMGEAR_HEADLESS) message(STATUS "headlesss mode") set(NO_OPENSCENEGRAPH_INTERFACE 1) else() @@ -61,13 +61,13 @@ else() find_package(OpenAL REQUIRED) find_package(ALUT REQUIRED) find_package(OpenSceneGraph 2.8.1 REQUIRED osgText osgSim osgDB osgParticle osgUtil) -endif() +endif(SIMGEAR_HEADLESS) if(JPEG_FACTORY) message(STATUS "JPEG-factory enabled") find_package(JPEG REQUIRED) include_directories(${JPEG_INCLUDE_DIR}) -endif() +endif(JPEG_FACTORY) if(ENABLE_LIBSVN) find_package(SvnClient) From b3175205434bca918170dea198444db18fd0d7da Mon Sep 17 00:00:00 2001 From: Christian Schmitt Date: Wed, 24 Aug 2011 13:25:46 +0200 Subject: [PATCH 7/8] Make RTI configurable --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a72da9c8..49916a08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ option(SIMGEAR_SHARED "Set to ON to build SimGear as a shared library/framework" option(SIMGEAR_HEADLESS "Set to ON to build SimGear without GUI/graphics support" OFF) option(JPEG_FACTORY "Enable JPEG-factory support" OFF) option(ENABLE_LIBSVN "Set to ON to build SimGear with libsvnclient support" ON) +option(ENABLE_RTI "Set to ON to build SimGear with RTI support" OFF) set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted") @@ -86,8 +87,10 @@ check_include_file(sys/timeb.h HAVE_SYS_TIMEB_H) check_include_file(unistd.h HAVE_UNISTD_H) check_include_file(windows.h HAVE_WINDOWS_H) +if(ENABLE_RTI) # See if we have any rti library variant installed find_package(RTI) +endif(ENABLE_RTI) check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) check_function_exists(ftime HAVE_FTIME) From 09e610b900e6751da635619513a53972f9e67861 Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Wed, 24 Aug 2011 21:26:02 +0200 Subject: [PATCH 8/8] Implement #327 Add condition checking the range of a value New feature for elements: An (optional) element allows for fuzzy equals checks example: /foo 0.0 0.1 This condition evaluates as true if /foo is within [-0.05..0.05] (both inclusive) The precision tag works for int, long, float and double propeties. It has no meaning for bool properties. For string properties, precision sets the length of the strings to compare. --- simgear/props/condition.cxx | 174 +++++++++++++++++++++--------------- 1 file changed, 104 insertions(+), 70 deletions(-) diff --git a/simgear/props/condition.cxx b/simgear/props/condition.cxx index 85c539cf..d60cb440 100644 --- a/simgear/props/condition.cxx +++ b/simgear/props/condition.cxx @@ -126,21 +126,27 @@ public: const char * propname ); virtual void setRightProperty( SGPropertyNode *prop_root, const char * propname ); + virtual void setPrecisionProperty( SGPropertyNode *prop_root, + const char * propname ); // will make a local copy virtual void setLeftValue (const SGPropertyNode * value); virtual void setRightValue (const SGPropertyNode * value); + virtual void setPrecisionValue (const SGPropertyNode * value); void setLeftDExpression(SGExpressiond* dexp); void setRightDExpression(SGExpressiond* dexp); + void setPrecisionDExpression(SGExpressiond* dexp); private: Type _type; bool _reverse; SGPropertyNode_ptr _left_property; SGPropertyNode_ptr _right_property; + SGPropertyNode_ptr _precision_property; SGSharedPtr _left_dexp; SGSharedPtr _right_dexp; + SGSharedPtr _precision_dexp; }; @@ -261,8 +267,20 @@ SGOrCondition::addCondition (SGCondition * condition) // Implementation of SGComparisonCondition. //////////////////////////////////////////////////////////////////////// +template +static int doComp( T v1, T v2, T e ) +{ + T d = v1 - v2; + if( d < -e ) + return SGComparisonCondition::LESS_THAN; + else if( d > e ) + return SGComparisonCondition::GREATER_THAN; + else + return SGComparisonCondition::EQUALS; +} + static int -doComparison (const SGPropertyNode * left, const SGPropertyNode *right) +doComparison (const SGPropertyNode * left, const SGPropertyNode * right, const SGPropertyNode * precision ) { using namespace simgear; switch (left->getType()) { @@ -277,55 +295,28 @@ doComparison (const SGPropertyNode * left, const SGPropertyNode *right) return SGComparisonCondition::EQUALS; break; } - case props::INT: { - int v1 = left->getIntValue(); - int v2 = right->getIntValue(); - if (v1 < v2) - return SGComparisonCondition::LESS_THAN; - else if (v1 > v2) - return SGComparisonCondition::GREATER_THAN; - else - return SGComparisonCondition::EQUALS; - break; - } - case props::LONG: { - long v1 = left->getLongValue(); - long v2 = right->getLongValue(); - if (v1 < v2) - return SGComparisonCondition::LESS_THAN; - else if (v1 > v2) - return SGComparisonCondition::GREATER_THAN; - else - return SGComparisonCondition::EQUALS; - break; - } - case props::FLOAT: { - float v1 = left->getFloatValue(); - float v2 = right->getFloatValue(); - if (v1 < v2) - return SGComparisonCondition::LESS_THAN; - else if (v1 > v2) - return SGComparisonCondition::GREATER_THAN; - else - return SGComparisonCondition::EQUALS; - break; - } - case props::DOUBLE: { - double v1 = left->getDoubleValue(); - double v2 = right->getDoubleValue(); - if (v1 < v2) - return SGComparisonCondition::LESS_THAN; - else if (v1 > v2) - return SGComparisonCondition::GREATER_THAN; - else - return SGComparisonCondition::EQUALS; - break; - } + case props::INT: + return doComp(left->getIntValue(), right->getIntValue(), + precision ? abs(precision->getIntValue()/2) : 0 ); + + case props::LONG: + return doComp(left->getLongValue(), right->getLongValue(), + precision ? abs(precision->getLongValue()/2L) : 0L ); + + case props::FLOAT: + return doComp(left->getFloatValue(), right->getFloatValue(), + precision ? fabs(precision->getFloatValue()/2.0f) : 0.0f ); + + case props::DOUBLE: + return doComp(left->getDoubleValue(), right->getDoubleValue(), + precision ? fabs(precision->getDoubleValue()/2.0) : 0.0 ); + case props::STRING: case props::NONE: case props::UNSPECIFIED: { - string v1 = left->getStringValue(); - string v2 = right->getStringValue(); + size_t l = precision ? precision->getLongValue() : string::npos; + string v1 = string(left->getStringValue()).substr(0,l); + string v2 = string(right->getStringValue()).substr(0,l); if (v1 < v2) return SGComparisonCondition::LESS_THAN; else if (v1 > v2) @@ -367,8 +358,12 @@ SGComparisonCondition::test () const if (_right_dexp) { _right_property->setDoubleValue(_right_dexp->getValue(NULL)); } + + if (_precision_dexp) { + _precision_property->setDoubleValue(_precision_dexp->getValue(NULL)); + } - int cmp = doComparison(_left_property, _right_property); + int cmp = doComparison(_left_property, _right_property, _precision_property ); if (!_reverse) return (cmp == _type); else @@ -389,12 +384,24 @@ SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root, _right_property = prop_root->getNode(propname, true); } +void +SGComparisonCondition::setPrecisionProperty( SGPropertyNode *prop_root, + const char * propname ) +{ + _precision_property = prop_root->getNode(propname, true); +} + void SGComparisonCondition::setLeftValue (const SGPropertyNode *node) { _left_property = new SGPropertyNode(*node); } +void +SGComparisonCondition::setPrecisionValue (const SGPropertyNode *node) +{ + _precision_property = new SGPropertyNode(*node); +} void SGComparisonCondition::setRightValue (const SGPropertyNode *node) @@ -414,6 +421,13 @@ SGComparisonCondition::setRightDExpression(SGExpressiond* dexp) { _right_property = new SGPropertyNode(); _right_dexp = dexp; +} + +void +SGComparisonCondition::setPrecisionDExpression(SGExpressiond* dexp) +{ + _precision_property = new SGPropertyNode(); + _precision_dexp = dexp; } //////////////////////////////////////////////////////////////////////// // Read a condition and use it if necessary. @@ -479,34 +493,54 @@ readComparison( SGPropertyNode *prop_root, bool reverse) { SGComparisonCondition * condition = new SGComparisonCondition(type, reverse); - if (node->nChildren() != 2) { - throw sg_exception("condition: comparison without two children"); + if (node->nChildren() < 2 || node->nChildren() > 3 ) { + throw sg_exception("condition: comparison without two or three children"); } const SGPropertyNode* left = node->getChild(0), *right = node->getChild(1); - string leftName(left->getName()); - if (leftName == "property") { - condition->setLeftProperty(prop_root, left->getStringValue()); - } else if (leftName == "value") { - condition->setLeftValue(left); - } else if (leftName == "expression") { - SGExpressiond* exp = SGReadDoubleExpression(prop_root, left->getChild(0)); - condition->setLeftDExpression(exp); - } else { - throw sg_exception("Unknown condition comparison left child:" + leftName); + + { + string leftName(left->getName()); + if (leftName == "property") { + condition->setLeftProperty(prop_root, left->getStringValue()); + } else if (leftName == "value") { + condition->setLeftValue(left); + } else if (leftName == "expression") { + SGExpressiond* exp = SGReadDoubleExpression(prop_root, left->getChild(0)); + condition->setLeftDExpression(exp); + } else { + throw sg_exception("Unknown condition comparison left child:" + leftName); + } } - string rightName(right->getName()); - if (rightName == "property") { - condition->setRightProperty(prop_root, right->getStringValue()); - } else if (rightName == "value") { - condition->setRightValue(right); - } else if (rightName == "expression") { - SGExpressiond* exp = SGReadDoubleExpression(prop_root, right->getChild(0)); - condition->setRightDExpression(exp); - } else { - throw sg_exception("Unknown condition comparison right child:" + rightName); + { + string rightName(right->getName()); + if (rightName == "property") { + condition->setRightProperty(prop_root, right->getStringValue()); + } else if (rightName == "value") { + condition->setRightValue(right); + } else if (rightName == "expression") { + SGExpressiond* exp = SGReadDoubleExpression(prop_root, right->getChild(0)); + condition->setRightDExpression(exp); + } else { + throw sg_exception("Unknown condition comparison right child:" + rightName); + } + } + + if( node->nChildren() == 3 ) { + const SGPropertyNode *n = node->getChild(2); + string name(n->getName()); + if (name == "precision-property") { + condition->setPrecisionProperty(prop_root, n->getStringValue()); + } else if (name == "precision-value") { + condition->setPrecisionValue(n); + } else if (name == "precision-expression") { + SGExpressiond* exp = SGReadDoubleExpression(prop_root, n->getChild(0)); + condition->setPrecisionDExpression(exp); + } else { + throw sg_exception("Unknown condition comparison precision child:" + name ); + } } return condition;