Files
simgear/simgear/props/condition.cxx
T

423 lines
10 KiB
C++

// condition.cxx - Declarations and inline methods for property conditions.
//
// Written by David Megginson, started 2000.
// CLO May 2003 - Split out condition specific code.
//
// This file is in the Public Domain, and comes with no warranty.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear/compiler.h>
#endif
// #include <iostream>
#include <simgear/structure/exception.hxx>
#include "props.hxx"
#include "condition.hxx"
using std::istream;
using std::ostream;
////////////////////////////////////////////////////////////////////////
// Implementation of SGCondition.
////////////////////////////////////////////////////////////////////////
SGCondition::SGCondition ()
{
}
SGCondition::~SGCondition ()
{
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGPropertyCondition.
////////////////////////////////////////////////////////////////////////
SGPropertyCondition::SGPropertyCondition ( SGPropertyNode *prop_root,
const char *propname )
: _node( prop_root->getNode(propname, true) )
{
}
SGPropertyCondition::~SGPropertyCondition ()
{
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGNotCondition.
////////////////////////////////////////////////////////////////////////
SGNotCondition::SGNotCondition (SGCondition * condition)
: _condition(condition)
{
}
SGNotCondition::~SGNotCondition ()
{
}
bool
SGNotCondition::test () const
{
return !(_condition->test());
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGAndCondition.
////////////////////////////////////////////////////////////////////////
SGAndCondition::SGAndCondition ()
{
}
SGAndCondition::~SGAndCondition ()
{
}
bool
SGAndCondition::test () const
{
int nConditions = _conditions.size();
for (int i = 0; i < nConditions; i++) {
if (!_conditions[i]->test())
return false;
}
return true;
}
void
SGAndCondition::addCondition (SGCondition * condition)
{
_conditions.push_back(condition);
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGOrCondition.
////////////////////////////////////////////////////////////////////////
SGOrCondition::SGOrCondition ()
{
}
SGOrCondition::~SGOrCondition ()
{
}
bool
SGOrCondition::test () const
{
int nConditions = _conditions.size();
for (int i = 0; i < nConditions; i++) {
if (_conditions[i]->test())
return true;
}
return false;
}
void
SGOrCondition::addCondition (SGCondition * condition)
{
_conditions.push_back(condition);
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGComparisonCondition.
////////////////////////////////////////////////////////////////////////
static int
doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
{
switch (left->getType()) {
case SGPropertyNode::BOOL: {
bool v1 = left->getBoolValue();
bool v2 = right->getBoolValue();
if (v1 < v2)
return SGComparisonCondition::LESS_THAN;
else if (v1 > v2)
return SGComparisonCondition::GREATER_THAN;
else
return SGComparisonCondition::EQUALS;
break;
}
case SGPropertyNode::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 SGPropertyNode::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 SGPropertyNode::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 SGPropertyNode::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 SGPropertyNode::STRING:
case SGPropertyNode::NONE:
case SGPropertyNode::UNSPECIFIED: {
string v1 = left->getStringValue();
string v2 = right->getStringValue();
if (v1 < v2)
return SGComparisonCondition::LESS_THAN;
else if (v1 > v2)
return SGComparisonCondition::GREATER_THAN;
else
return SGComparisonCondition::EQUALS;
break;
}
}
throw sg_exception("condition: unrecognized node type in comparison");
return 0;
}
SGComparisonCondition::SGComparisonCondition (Type type, bool reverse)
: _type(type),
_reverse(reverse),
_left_property(0),
_right_property(0),
_right_value(0)
{
}
SGComparisonCondition::~SGComparisonCondition ()
{
}
bool
SGComparisonCondition::test () const
{
// Always fail if incompletely specified
if (_left_property == 0 ||
(_right_property == 0 && _right_value == 0))
return false;
// Get LESS_THAN, EQUALS, or GREATER_THAN
int cmp =
doComparison(_left_property,
(_right_property != 0 ? _right_property : _right_value));
if (!_reverse)
return (cmp == _type);
else
return (cmp != _type);
}
void
SGComparisonCondition::setLeftProperty( SGPropertyNode *prop_root,
const char * propname )
{
_left_property = prop_root->getNode(propname, true);
}
void
SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root,
const char * propname )
{
_right_value = 0;
_right_property = prop_root->getNode(propname, true);
}
void
SGComparisonCondition::setRightValue (const SGPropertyNode *node)
{
_right_property = 0;
_right_value = new SGPropertyNode(*node);
}
////////////////////////////////////////////////////////////////////////
// Read a condition and use it if necessary.
////////////////////////////////////////////////////////////////////////
// Forward declaration
static SGCondition * readCondition( SGPropertyNode *prop_root,
const SGPropertyNode *node );
static SGCondition *
readPropertyCondition( SGPropertyNode *prop_root,
const SGPropertyNode *node )
{
return new SGPropertyCondition( prop_root, node->getStringValue() );
}
static SGCondition *
readNotCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
int nChildren = node->nChildren();
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode * child = node->getChild(i);
SGCondition * condition = readCondition(prop_root, child);
if (condition != 0)
return new SGNotCondition(condition);
}
SG_LOG(SG_COCKPIT, SG_ALERT, "empty 'not' condition");
return 0;
}
static SGCondition *
readAndConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
SGAndCondition * andCondition = new SGAndCondition;
int nChildren = node->nChildren();
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode * child = node->getChild(i);
SGCondition * condition = readCondition(prop_root, child);
if (condition != 0)
andCondition->addCondition(condition);
}
return andCondition;
}
static SGCondition *
readOrConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
SGOrCondition * orCondition = new SGOrCondition;
int nChildren = node->nChildren();
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode * child = node->getChild(i);
SGCondition * condition = readCondition(prop_root, child);
if (condition != 0)
orCondition->addCondition(condition);
}
return orCondition;
}
static SGCondition *
readComparison( SGPropertyNode *prop_root,
const SGPropertyNode *node,
SGComparisonCondition::Type type,
bool reverse)
{
SGComparisonCondition * condition = new SGComparisonCondition(type, reverse);
condition->setLeftProperty(prop_root, node->getStringValue("property[0]"));
if (node->hasValue("property[1]"))
condition->setRightProperty(prop_root, node->getStringValue("property[1]"));
else if (node->hasValue("value"))
condition->setRightValue(node->getChild("value", 0));
else
throw sg_exception("condition: comparison without property[1] or value");
return condition;
}
static SGCondition *
readCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
const string &name = node->getName();
if (name == "property")
return readPropertyCondition(prop_root, node);
else if (name == "not")
return readNotCondition(prop_root, node);
else if (name == "and")
return readAndConditions(prop_root, node);
else if (name == "or")
return readOrConditions(prop_root, node);
else if (name == "less-than")
return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
false);
else if (name == "less-than-equals")
return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
true);
else if (name == "greater-than")
return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
false);
else if (name == "greater-than-equals")
return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
true);
else if (name == "equals")
return readComparison(prop_root, node, SGComparisonCondition::EQUALS,
false);
else if (name == "not-equals")
return readComparison(prop_root, node, SGComparisonCondition::EQUALS, true);
else
return 0;
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGConditional.
////////////////////////////////////////////////////////////////////////
SGConditional::SGConditional ()
: _condition (0)
{
}
SGConditional::~SGConditional ()
{
}
void
SGConditional::setCondition (SGCondition * condition)
{
_condition = condition;
}
bool
SGConditional::test () const
{
return ((_condition == 0) || _condition->test());
}
// The top-level is always an implicit 'and' group
SGCondition *
sgReadCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
return readAndConditions(prop_root, node);
}
// end of condition.cxx