1
0
Fork 0
flightgear/src/Main/fg_props.cxx
david aa872ed040 Patch from Frederic Bouvier (FIXME comments added by David Megginson):
I made these modifications to correct the problem of getter functions
returning pointers to local variables. Those variables are no longer
locals and become static. One should be aware that it kills reentrancy
!
2002-04-07 21:20:16 +00:00

1185 lines
27 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// fg_props.cxx -- support for FlightGear properties.
//
// Written by David Megginson, started 2000.
//
// Copyright (C) 2000, 2001 David Megginson - david@megginson.com
//
// This program 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.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear/compiler.h>
#endif
#include <simgear/misc/exception.hxx>
#include <simgear/magvar/magvar.hxx>
#include <simgear/timing/sg_time.hxx>
#include STL_IOSTREAM
#include <ATC/ATCdisplay.hxx>
#include <Aircraft/aircraft.hxx>
#include <Time/tmp.hxx>
#include <FDM/UIUCModel/uiuc_aircraftdir.h>
#ifndef FG_NEW_ENVIRONMENT
# include <WeatherCM/FGLocalWeatherDatabase.h>
#else
# include <Environment/environment.hxx>
#endif // FG_NEW_ENVIRONMENT
#include <Objects/matlib.hxx>
#include <GUI/gui.h>
#include "globals.hxx"
#include "fgfs.hxx"
#include "fg_props.hxx"
#if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
SG_USING_STD(istream);
SG_USING_STD(ostream);
#endif
#if !defined(FG_NEW_ENVIRONMENT)
static double getWindNorth ();
static double getWindEast ();
static double getWindDown ();
#endif // FG_NEW_ENVIRONMENT
static bool winding_ccw = true; // FIXME: temporary
static bool fdm_data_logging = false; // FIXME: temporary
////////////////////////////////////////////////////////////////////////
// Default property bindings (not yet handled by any module).
////////////////////////////////////////////////////////////////////////
struct LogClassMapping {
sgDebugClass c;
string name;
LogClassMapping(sgDebugClass cc, string nname) { c = cc; name = nname; }
};
LogClassMapping log_class_mappings [] = {
LogClassMapping(SG_NONE, "none"),
LogClassMapping(SG_TERRAIN, "terrain"),
LogClassMapping(SG_ASTRO, "astro"),
LogClassMapping(SG_FLIGHT, "flight"),
LogClassMapping(SG_INPUT, "input"),
LogClassMapping(SG_GL, "gl"),
LogClassMapping(SG_VIEW, "view"),
LogClassMapping(SG_COCKPIT, "cockpit"),
LogClassMapping(SG_GENERAL, "general"),
LogClassMapping(SG_MATH, "math"),
LogClassMapping(SG_EVENT, "event"),
LogClassMapping(SG_AIRCRAFT, "aircraft"),
LogClassMapping(SG_AUTOPILOT, "autopilot"),
LogClassMapping(SG_IO, "io"),
LogClassMapping(SG_CLIPPER, "clipper"),
LogClassMapping(SG_NETWORK, "network"),
LogClassMapping(SG_UNDEFD, "")
};
/**
* Get the logging classes.
*/
static const char *
getLoggingClasses ()
{
sgDebugClass classes = logbuf::get_log_classes();
static string result = ""; // FIXME
for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
if ((classes&log_class_mappings[i].c) > 0) {
if (!result.empty())
result += '|';
result += log_class_mappings[i].name;
}
}
return result.c_str();
}
static void
addLoggingClass (const string &name)
{
sgDebugClass classes = logbuf::get_log_classes();
for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
if (name == log_class_mappings[i].name) {
logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
return;
}
}
SG_LOG(SG_GENERAL, SG_ALERT, "Unknown logging class: " << name);
}
/**
* Set the logging classes.
*/
static void
setLoggingClasses (const char * c)
{
string classes = c;
logbuf::set_log_classes(SG_NONE);
if (classes == "none") {
SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
return;
}
if (classes.empty() || classes == "all") { // default
logbuf::set_log_classes(SG_ALL);
SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
<< getLoggingClasses());
return;
}
string rest = classes;
string name = "";
int sep = rest.find('|');
while (sep > 0) {
name = rest.substr(0, sep);
rest = rest.substr(sep+1);
addLoggingClass(name);
sep = rest.find('|');
}
addLoggingClass(rest);
SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
<< getLoggingClasses());
}
/**
* Get the logging priority.
*/
static const char *
getLoggingPriority ()
{
switch (logbuf::get_log_priority()) {
case SG_BULK:
return "bulk";
case SG_DEBUG:
return "debug";
case SG_INFO:
return "info";
case SG_WARN:
return "warn";
case SG_ALERT:
return "alert";
default:
SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
<< logbuf::get_log_priority());
return "unknown";
}
}
/**
* Set the logging priority.
*/
static void
setLoggingPriority (const char * p)
{
string priority = p;
if (priority == "bulk") {
logbuf::set_log_priority(SG_BULK);
} else if (priority == "debug") {
logbuf::set_log_priority(SG_DEBUG);
} else if (priority.empty() || priority == "info") { // default
logbuf::set_log_priority(SG_INFO);
} else if (priority == "warn") {
logbuf::set_log_priority(SG_WARN);
} else if (priority == "alert") {
logbuf::set_log_priority(SG_ALERT);
} else {
SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
}
SG_LOG(SG_GENERAL, SG_INFO, "Logging priority is " << getLoggingPriority());
}
/**
* Return the current aircraft directory (UIUC) as a string.
*/
static const char *
getAircraftDir ()
{
return aircraft_dir.c_str();
}
/**
* Set the current aircraft directory (UIUC).
*/
static void
setAircraftDir (const char * dir)
{
aircraft_dir = dir;
}
/**
* Return the number of milliseconds elapsed since simulation started.
*/
static long
getElapsedTime_ms ()
{
return globals->get_elapsed_time_ms();
}
/**
* Return the current Zulu time.
*/
static const char *
getDateString ()
{
static char buf[64]; // FIXME
struct tm * t = globals->get_time_params()->getGmt();
sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
return buf;
}
/**
* Set the current Zulu time.
*/
static void
setDateString (const char * date_string)
{
static const SGPropertyNode *cur_time_override
= fgGetNode("/sim/time/cur-time-override", true);
SGTime * st = globals->get_time_params();
struct tm * current_time = st->getGmt();
struct tm new_time;
// Scan for basic ISO format
// YYYY-MM-DDTHH:MM:SS
int ret = sscanf(date_string, "%d-%d-%dT%d:%d:%d",
&(new_time.tm_year), &(new_time.tm_mon),
&(new_time.tm_mday), &(new_time.tm_hour),
&(new_time.tm_min), &(new_time.tm_sec));
// Be pretty picky about this, so
// that strange things don't happen
// if the save file has been edited
// by hand.
if (ret != 6) {
SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
<< " not in YYYY-MM-DDTHH:MM:SS format; skipped");
return;
}
// OK, it looks like we got six
// values, one way or another.
new_time.tm_year -= 1900;
new_time.tm_mon -= 1;
// Now, tell flight gear to use
// the new time. This was far
// too difficult, by the way.
long int warp =
mktime(&new_time) - mktime(current_time) + globals->get_warp();
double lon = current_aircraft.fdm_state->get_Longitude();
double lat = current_aircraft.fdm_state->get_Latitude();
globals->set_warp(warp);
st->update(lon, lat, cur_time_override->getLongValue(), warp);
fgUpdateSkyAndLightingParams();
}
/**
* Return the GMT as a string.
*/
static const char *
getGMTString ()
{
static char buf[16]; // FIXME
struct tm *t = globals->get_time_params()->getGmt();
sprintf(buf, " %.2d:%.2d:%.2d",
t->tm_hour, t->tm_min, t->tm_sec);
// cout << t << " " << buf << endl;
return buf;
}
/**
* Get the texture rendering state.
*/
static bool
getTextures ()
{
return (material_lib.get_step() == 0);
}
/**
* Set the texture rendering state.
*/
static void
setTextures (bool textures)
{
if (textures)
material_lib.set_step(0);
else
material_lib.set_step(1);
}
/**
* Return the magnetic variation
*/
static double
getMagVar ()
{
return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
}
/**
* Return the magnetic dip
*/
static double
getMagDip ()
{
return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
}
/**
* Return the current heading in degrees.
*/
static double
getHeadingMag ()
{
return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
}
#if !defined(FG_NEW_ENVIRONMENT)
/**
* Get the current visibility (meters).
*/
static double
getVisibility ()
{
return WeatherDatabase->getWeatherVisibility();
}
/**
* Set the current visibility (meters).
*/
static void
setVisibility (double visibility)
{
WeatherDatabase->setWeatherVisibility(visibility);
}
/**
* Get the current wind north velocity (feet/second).
*/
static double
getWindNorth ()
{
return current_aircraft.fdm_state->get_V_north_airmass();
}
/**
* Set the current wind north velocity (feet/second).
*/
static void
setWindNorth (double speed)
{
current_aircraft.fdm_state
->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
}
/**
* Get the current wind east velocity (feet/second).
*/
static double
getWindEast ()
{
return current_aircraft.fdm_state->get_V_east_airmass();
}
/**
* Set the current wind east velocity (feet/second).
*/
static void
setWindEast (double speed)
{
cout << "Set wind-east to " << speed << endl;
current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
speed,
getWindDown());
}
/**
* Get the current wind down velocity (feet/second).
*/
static double
getWindDown ()
{
return current_aircraft.fdm_state->get_V_down_airmass();
}
/**
* Set the current wind down velocity (feet/second).
*/
static void
setWindDown (double speed)
{
current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
getWindEast(),
speed);
}
#endif // FG_NEW_ENVIRONMENT
static long
getWarp ()
{
return globals->get_warp();
}
static void
setWarp (long warp)
{
globals->set_warp(warp);
}
static long
getWarpDelta ()
{
return globals->get_warp_delta();
}
static void
setWarpDelta (long delta)
{
globals->set_warp_delta(delta);
}
static bool
getWindingCCW ()
{
return winding_ccw;
}
static void
setWindingCCW (bool state)
{
winding_ccw = state;
if ( winding_ccw )
glFrontFace ( GL_CCW );
else
glFrontFace ( GL_CW );
}
static bool
getFullScreen ()
{
#if defined(FX) && !defined(WIN32)
return globals->get_fullscreen();
#else
return false;
#endif
}
static void
setFullScreen (bool state)
{
#if defined(FX) && !defined(WIN32)
globals->set_fullscreen(state);
# if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
XMesaSetFXmode( state ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
# endif
#endif
}
static bool
getFDMDataLogging ()
{
return fdm_data_logging;
}
static void
setFDMDataLogging (bool state)
{
// kludge; no getter or setter available
if (state != fdm_data_logging) {
fgToggleFDMdataLogging();
fdm_data_logging = state;
}
}
////////////////////////////////////////////////////////////////////////
// Tie the properties.
////////////////////////////////////////////////////////////////////////
void
fgInitProps ()
{
// Simulation
fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
// fgTie("/sim/freeze", getFreeze, setFreeze);
fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
fgTie("/sim/time/elapsed-ms", getElapsedTime_ms);
fgTie("/sim/time/gmt", getDateString, setDateString);
fgSetArchivable("/sim/time/gmt");
fgTie("/sim/time/gmt-string", getGMTString);
fgTie("/sim/rendering/textures", getTextures, setTextures);
// Orientation
fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
// Environment
#if !defined(FG_NEW_ENVIRONMENT)
fgTie("/environment/visibility-m", getVisibility, setVisibility);
fgSetArchivable("/environment/visibility-m");
fgTie("/environment/wind-from-north-fps", getWindNorth, setWindNorth);
fgSetArchivable("/environment/wind-from-north-fps");
fgTie("/environment/wind-from-east-fps", getWindEast, setWindEast);
fgSetArchivable("/environment/wind-from-east-fps");
fgTie("/environment/wind-from-down-fps", getWindDown, setWindDown);
fgSetArchivable("/environment/wind-from-down-fps");
#endif
fgTie("/environment/magnetic-variation-deg", getMagVar);
fgTie("/environment/magnetic-dip-deg", getMagDip);
fgTie("/sim/time/warp", getWarp, setWarp, false);
fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
// Misc. Temporary junk.
fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
}
void
fgUpdateProps ()
{
}
////////////////////////////////////////////////////////////////////////
// Save and restore.
////////////////////////////////////////////////////////////////////////
/**
* Save the current state of the simulator to a stream.
*/
bool
fgSaveFlight (ostream &output, bool write_all)
{
fgSetBool("/sim/startup/onground", false);
fgSetArchivable("/sim/startup/onground");
fgSetBool("/sim/startup/trim", false);
fgSetArchivable("/sim/startup/trim");
fgSetString("/sim/startup/speed-set", "UVW");
fgSetArchivable("/sim/startup/speed-set");
try {
writeProperties(output, globals->get_props(), write_all);
} catch (const sg_exception &e) {
guiErrorMessage("Error saving flight: ", e);
return false;
}
return true;
}
/**
* Restore the current state of the simulator from a stream.
*/
bool
fgLoadFlight (istream &input)
{
SGPropertyNode props;
try {
readProperties(input, &props);
} catch (const sg_exception &e) {
guiErrorMessage("Error reading saved flight: ", e);
return false;
}
fgSetBool("/sim/startup/onground", false);
fgSetBool("/sim/startup/trim", false);
fgSetString("/sim/startup/speed-set", "UVW");
copyProperties(&props, globals->get_props());
// When loading a flight, make it the
// new initial state.
globals->saveInitialState();
return true;
}
////////////////////////////////////////////////////////////////////////
// Property convenience functions.
////////////////////////////////////////////////////////////////////////
SGPropertyNode *
fgGetNode (const char * path, bool create)
{
return globals->get_props()->getNode(path, create);
}
SGPropertyNode *
fgGetNode (const char * path, int index, bool create)
{
return globals->get_props()->getNode(path, index, create);
}
bool
fgHasNode (const char * path)
{
return (fgGetNode(path, false) != 0);
}
bool
fgGetBool (const char * name, bool defaultValue)
{
return globals->get_props()->getBoolValue(name, defaultValue);
}
int
fgGetInt (const char * name, int defaultValue)
{
return globals->get_props()->getIntValue(name, defaultValue);
}
int
fgGetLong (const char * name, long defaultValue)
{
return globals->get_props()->getLongValue(name, defaultValue);
}
float
fgGetFloat (const char * name, float defaultValue)
{
return globals->get_props()->getFloatValue(name, defaultValue);
}
double
fgGetDouble (const char * name, double defaultValue)
{
return globals->get_props()->getDoubleValue(name, defaultValue);
}
const char *
fgGetString (const char * name, const char * defaultValue)
{
return globals->get_props()->getStringValue(name, defaultValue);
}
bool
fgSetBool (const char * name, bool val)
{
return globals->get_props()->setBoolValue(name, val);
}
bool
fgSetInt (const char * name, int val)
{
return globals->get_props()->setIntValue(name, val);
}
bool
fgSetLong (const char * name, long val)
{
return globals->get_props()->setLongValue(name, val);
}
bool
fgSetFloat (const char * name, float val)
{
return globals->get_props()->setFloatValue(name, val);
}
bool
fgSetDouble (const char * name, double val)
{
return globals->get_props()->setDoubleValue(name, val);
}
bool
fgSetString (const char * name, const char * val)
{
return globals->get_props()->setStringValue(name, val);
}
void
fgSetArchivable (const char * name, bool state)
{
SGPropertyNode * node = globals->get_props()->getNode(name);
if (node == 0)
SG_LOG(SG_GENERAL, SG_ALERT,
"Attempt to set archive flag for non-existant property "
<< name);
else
node->setAttribute(SGPropertyNode::ARCHIVE, state);
}
void
fgSetReadable (const char * name, bool state)
{
SGPropertyNode * node = globals->get_props()->getNode(name);
if (node == 0)
SG_LOG(SG_GENERAL, SG_ALERT,
"Attempt to set read flag for non-existant property "
<< name);
else
node->setAttribute(SGPropertyNode::READ, state);
}
void
fgSetWritable (const char * name, bool state)
{
SGPropertyNode * node = globals->get_props()->getNode(name);
if (node == 0)
SG_LOG(SG_GENERAL, SG_ALERT,
"Attempt to set write flag for non-existant property "
<< name);
else
node->setAttribute(SGPropertyNode::WRITE, state);
}
void
fgUntie (const char * name)
{
if (!globals->get_props()->untie(name))
SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGCondition.
////////////////////////////////////////////////////////////////////////
FGCondition::FGCondition ()
{
}
FGCondition::~FGCondition ()
{
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGPropertyCondition.
////////////////////////////////////////////////////////////////////////
FGPropertyCondition::FGPropertyCondition (const char * propname)
: _node(fgGetNode(propname, true))
{
}
FGPropertyCondition::~FGPropertyCondition ()
{
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGNotCondition.
////////////////////////////////////////////////////////////////////////
FGNotCondition::FGNotCondition (FGCondition * condition)
: _condition(condition)
{
}
FGNotCondition::~FGNotCondition ()
{
delete _condition;
}
bool
FGNotCondition::test () const
{
return !(_condition->test());
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGAndCondition.
////////////////////////////////////////////////////////////////////////
FGAndCondition::FGAndCondition ()
{
}
FGAndCondition::~FGAndCondition ()
{
for (unsigned int i = 0; i < _conditions.size(); i++)
delete _conditions[i];
}
bool
FGAndCondition::test () const
{
int nConditions = _conditions.size();
for (int i = 0; i < nConditions; i++) {
if (!_conditions[i]->test())
return false;
}
return true;
}
void
FGAndCondition::addCondition (FGCondition * condition)
{
_conditions.push_back(condition);
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGOrCondition.
////////////////////////////////////////////////////////////////////////
FGOrCondition::FGOrCondition ()
{
}
FGOrCondition::~FGOrCondition ()
{
for (unsigned int i = 0; i < _conditions.size(); i++)
delete _conditions[i];
}
bool
FGOrCondition::test () const
{
int nConditions = _conditions.size();
for (int i = 0; i < nConditions; i++) {
if (_conditions[i]->test())
return true;
}
return false;
}
void
FGOrCondition::addCondition (FGCondition * condition)
{
_conditions.push_back(condition);
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGComparisonCondition.
////////////////////////////////////////////////////////////////////////
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 FGComparisonCondition::LESS_THAN;
else if (v1 > v2)
return FGComparisonCondition::GREATER_THAN;
else
return FGComparisonCondition::EQUALS;
break;
}
case SGPropertyNode::INT: {
int v1 = left->getIntValue();
int v2 = right->getIntValue();
if (v1 < v2)
return FGComparisonCondition::LESS_THAN;
else if (v1 > v2)
return FGComparisonCondition::GREATER_THAN;
else
return FGComparisonCondition::EQUALS;
break;
}
case SGPropertyNode::LONG: {
long v1 = left->getLongValue();
long v2 = right->getLongValue();
if (v1 < v2)
return FGComparisonCondition::LESS_THAN;
else if (v1 > v2)
return FGComparisonCondition::GREATER_THAN;
else
return FGComparisonCondition::EQUALS;
break;
}
case SGPropertyNode::FLOAT: {
float v1 = left->getFloatValue();
float v2 = right->getFloatValue();
if (v1 < v2)
return FGComparisonCondition::LESS_THAN;
else if (v1 > v2)
return FGComparisonCondition::GREATER_THAN;
else
return FGComparisonCondition::EQUALS;
break;
}
case SGPropertyNode::DOUBLE: {
double v1 = left->getDoubleValue();
double v2 = right->getDoubleValue();
if (v1 < v2)
return FGComparisonCondition::LESS_THAN;
else if (v1 > v2)
return FGComparisonCondition::GREATER_THAN;
else
return FGComparisonCondition::EQUALS;
break;
}
case SGPropertyNode::STRING:
case SGPropertyNode::NONE:
case SGPropertyNode::UNSPECIFIED: {
string v1 = left->getStringValue();
string v2 = right->getStringValue();
if (v1 < v2)
return FGComparisonCondition::LESS_THAN;
else if (v1 > v2)
return FGComparisonCondition::GREATER_THAN;
else
return FGComparisonCondition::EQUALS;
break;
}
}
throw sg_exception("Unrecognized node type");
return 0;
}
FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
: _type(type),
_reverse(reverse),
_left_property(0),
_right_property(0),
_right_value(0)
{
}
FGComparisonCondition::~FGComparisonCondition ()
{
delete _right_value;
}
bool
FGComparisonCondition::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
FGComparisonCondition::setLeftProperty (const char * propname)
{
_left_property = fgGetNode(propname, true);
}
void
FGComparisonCondition::setRightProperty (const char * propname)
{
delete _right_value;
_right_value = 0;
_right_property = fgGetNode(propname, true);
}
void
FGComparisonCondition::setRightValue (const SGPropertyNode *node)
{
_right_property = 0;
delete _right_value;
_right_value = new SGPropertyNode(*node);
}
////////////////////////////////////////////////////////////////////////
// Read a condition and use it if necessary.
////////////////////////////////////////////////////////////////////////
// Forward declaration
static FGCondition * readCondition (const SGPropertyNode * node);
static FGCondition *
readPropertyCondition (const SGPropertyNode * node)
{
return new FGPropertyCondition(node->getStringValue());
}
static FGCondition *
readNotCondition (const SGPropertyNode * node)
{
int nChildren = node->nChildren();
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode * child = node->getChild(i);
FGCondition * condition = readCondition(child);
if (condition != 0)
return new FGNotCondition(condition);
}
SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
return 0;
}
static FGCondition *
readAndConditions (const SGPropertyNode * node)
{
FGAndCondition * andCondition = new FGAndCondition;
int nChildren = node->nChildren();
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode * child = node->getChild(i);
FGCondition * condition = readCondition(child);
if (condition != 0)
andCondition->addCondition(condition);
}
return andCondition;
}
static FGCondition *
readOrConditions (const SGPropertyNode * node)
{
FGOrCondition * orCondition = new FGOrCondition;
int nChildren = node->nChildren();
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode * child = node->getChild(i);
FGCondition * condition = readCondition(child);
if (condition != 0)
orCondition->addCondition(condition);
}
return orCondition;
}
static FGCondition *
readComparison (const SGPropertyNode * node,
FGComparisonCondition::Type type,
bool reverse)
{
FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
condition->setLeftProperty(node->getStringValue("property[0]"));
if (node->hasValue("property[1]"))
condition->setRightProperty(node->getStringValue("property[1]"));
else
condition->setRightValue(node->getChild("value", 0));
return condition;
}
static FGCondition *
readCondition (const SGPropertyNode * node)
{
const string &name = node->getName();
if (name == "property")
return readPropertyCondition(node);
else if (name == "not")
return readNotCondition(node);
else if (name == "and")
return readAndConditions(node);
else if (name == "or")
return readOrConditions(node);
else if (name == "less-than")
return readComparison(node, FGComparisonCondition::LESS_THAN, false);
else if (name == "less-than-equals")
return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
else if (name == "greater-than")
return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
else if (name == "greater-than-equals")
return readComparison(node, FGComparisonCondition::LESS_THAN, true);
else if (name == "equals")
return readComparison(node, FGComparisonCondition::EQUALS, false);
else if (name == "not-equals")
return readComparison(node, FGComparisonCondition::EQUALS, true);
else
return 0;
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGConditional.
////////////////////////////////////////////////////////////////////////
FGConditional::FGConditional ()
: _condition (0)
{
}
FGConditional::~FGConditional ()
{
delete _condition;
}
void
FGConditional::setCondition (FGCondition * condition)
{
delete _condition;
_condition = condition;
}
bool
FGConditional::test () const
{
return ((_condition == 0) || _condition->test());
}
// The top-level is always an implicit 'and' group
FGCondition *
fgReadCondition (const SGPropertyNode * node)
{
return readAndConditions(node);
}
// end of fg_props.cxx