summaryrefslogtreecommitdiffstats
path: root/tdeio/tdeio/ktraderparsetree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdeio/tdeio/ktraderparsetree.cpp')
-rw-r--r--tdeio/tdeio/ktraderparsetree.cpp714
1 files changed, 714 insertions, 0 deletions
diff --git a/tdeio/tdeio/ktraderparsetree.cpp b/tdeio/tdeio/ktraderparsetree.cpp
new file mode 100644
index 000000000..0a04b7918
--- /dev/null
+++ b/tdeio/tdeio/ktraderparsetree.cpp
@@ -0,0 +1,714 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+
+ 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; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "ktraderparsetree.h"
+
+namespace TDEIO {
+
+bool ParseTreeOR::eval( ParseContext *_context ) const
+{
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+
+// don't evaluate both expressions but return immediately
+// if the first one of them succeeds. Otherwise queries like
+// ((not exist Blah) or (Blah == 'Foo')) do not work, because
+// the evaluation of the second term ends up in a fatal error
+// (Simon)
+
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+
+ if ( c1.type != ParseContext::T_BOOL )
+ return false;
+
+ _context->b = c1.b;
+ _context->type = ParseContext::T_BOOL;
+ if ( c1.b )
+ return true;
+
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+
+ if ( c2.type != ParseContext::T_BOOL )
+ return false;
+
+ _context->b = ( c1.b || c2.b );
+ _context->type = ParseContext::T_BOOL;
+
+ return true;
+}
+
+bool ParseTreeAND::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_BOOL;
+
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( c1.type != ParseContext::T_BOOL )
+ return false;
+ if ( !c1.b )
+ {
+ _context->b = false;
+ return true;
+ }
+
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+ if ( c2.type != ParseContext::T_BOOL )
+ return false;
+
+ _context->b = ( c1.b && c2.b );
+
+ return true;
+}
+
+bool ParseTreeCALC::eval( ParseContext *_context ) const
+{
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+
+ // Bool extension
+ if ( c1.type != ParseContext::T_NUM && c1.type != ParseContext::T_DOUBLE && c1.type != ParseContext::T_BOOL )
+ return false;
+ // Bool extension
+ if ( c2.type != ParseContext::T_NUM && c2.type != ParseContext::T_DOUBLE && c2.type != ParseContext::T_BOOL )
+ return false;
+ // Bool extension
+ if ( c1.type == ParseContext::T_BOOL && c2.type == ParseContext::T_BOOL )
+ return false;
+
+ /**
+ * Make types compatible
+ */
+ if ( c1.type == ParseContext::T_NUM && c2.type == ParseContext::T_DOUBLE )
+ {
+ c1.type = ParseContext::T_DOUBLE;
+ c1.f = (double)c1.i;
+ }
+ else if ( c1.type == ParseContext::T_DOUBLE && c2.type == ParseContext::T_NUM )
+ {
+ c2.type = ParseContext::T_DOUBLE;
+ c2.f = (double)c2.i;
+ }
+ // Bool extension
+ else if ( c1.type == ParseContext::T_BOOL && c2.type == ParseContext::T_NUM )
+ {
+ c1.type = ParseContext::T_NUM;
+ if ( c1.b )
+ c1.i = 1;
+ else
+ c1.i = -1;
+ }
+ // Bool extension
+ else if ( c1.type == ParseContext::T_BOOL && c2.type == ParseContext::T_DOUBLE )
+ {
+ c1.type = ParseContext::T_DOUBLE;
+ if ( c1.b )
+ c1.f = 1.0;
+ else
+ c1.f = -1.0;
+ }
+ // Bool extension
+ else if ( c1.type == ParseContext::T_NUM && c2.type == ParseContext::T_BOOL )
+ {
+ c2.type = ParseContext::T_NUM;
+ if ( c2.b )
+ c2.i = 1;
+ else
+ c2.i = -1;
+ }
+ // Bool extension
+ else if ( c1.type == ParseContext::T_DOUBLE && c2.type == ParseContext::T_BOOL )
+ {
+ c2.type = ParseContext::T_DOUBLE;
+ if ( c2.b )
+ c2.f = 1.0;
+ else
+ c2.f = -1.0;
+ }
+
+ _context->type = c1.type;
+
+ /**
+ * Calculate
+ */
+ switch( m_cmd )
+ {
+ case 1: /* Add */
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->f = ( c1.f + c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->i = ( c1.i + c2.i );
+ return true;
+ }
+ break;
+ case 2: /* Sub */
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->f = ( c1.f - c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->i = ( c1.i - c2.i );
+ return true;
+ }
+ break;
+ case 3: /* Mul */
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ //cout << "Double Mult" << endl;
+ _context->f = ( c1.f * c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->i = ( c1.i * c2.i );
+ return true;
+ }
+ break;
+ case 4: /* Div */
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->f = ( c1.f / c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->i = ( c1.i / c2.i );
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+
+bool ParseTreeCMP::eval( ParseContext *_context ) const
+{
+ //cout << "CMP 1 cmd=" << m_cmd << endl;
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+
+ /**
+ * Make types compatible
+ */
+ if ( c1.type == ParseContext::T_NUM && c2.type == ParseContext::T_DOUBLE )
+ {
+ c1.type = ParseContext::T_DOUBLE;
+ c1.f = (double)c1.i;
+ }
+ else if ( c1.type == ParseContext::T_DOUBLE && c2.type == ParseContext::T_NUM )
+ {
+ c2.type = ParseContext::T_DOUBLE;
+ c2.f = (double)c2.i;
+ }
+
+ /**
+ * Compare
+ */
+ _context->type = ParseContext::T_BOOL;
+
+ switch( m_cmd )
+ {
+ case 1: /* EQ */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_STRING )
+ {
+ _context->b = ( c1.str == c2.str );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_BOOL )
+ {
+ _context->b = ( c1.b == c2.b );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f == c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i == c2.i );
+ return true;
+ }
+ break;
+ case 2: /* NEQ */
+ if ( c1.type != c2.type )
+ {
+ _context->b = true;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_STRING )
+ {
+ _context->b = ( c1.str != c2.str );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_BOOL )
+ {
+ _context->b = ( c1.b != c2.b );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f != c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i != c2.i );
+ return true;
+ }
+ break;
+ case 3: /* GEQ */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f >= c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i >= c2.i );
+ return true;
+ }
+ _context->b = false;
+ return true;
+
+ case 4: /* LEQ */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f <= c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i <= c2.i );
+ return true;
+ }
+ _context->b = false;
+ return true;
+
+ case 5: /* < */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f < c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i < c2.i );
+ return true;
+ }
+ _context->b = false;
+ return true;
+
+ case 6: /* > */
+ if ( c1.type != c2.type )
+ {
+ _context->b = false;
+ return true;
+ }
+ if ( c1.type == ParseContext::T_DOUBLE )
+ {
+ _context->b = ( c1.f > c2.f );
+ return true;
+ }
+ if ( c1.type == ParseContext::T_NUM )
+ {
+ _context->b = ( c1.i > c2.i );
+ return true;
+ }
+ _context->b = false;
+ return true;
+
+ }
+
+ return false;
+}
+
+bool ParseTreeNOT::eval( ParseContext *_context ) const
+{
+ ParseContext c1( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( c1.type != ParseContext::T_BOOL )
+ return false;
+
+ _context->b = !c1.b;
+ _context->type = ParseContext::T_BOOL;
+
+ return true;
+}
+
+bool ParseTreeEXIST::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_BOOL;
+
+ TQVariant prop = _context->service->property( m_id );
+ _context->b = prop.isValid();
+
+ return true;
+}
+
+bool ParseTreeMATCH::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_BOOL;
+
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+ if ( c1.type != ParseContext::T_STRING || c2.type != ParseContext::T_STRING )
+ return false;
+
+ _context->b = ( c2.str.find( c1.str ) != -1 );
+
+ return true;
+}
+
+bool ParseTreeIN::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_BOOL;
+
+ ParseContext c1( _context );
+ ParseContext c2( _context );
+ if ( !m_pLeft->eval( &c1 ) )
+ return false;
+ if ( !m_pRight->eval( &c2 ) )
+ return false;
+
+ if ( (c1.type == ParseContext::T_NUM) &&
+ (c2.type == ParseContext::T_SEQ) &&
+ ((*(c2.seq.begin())).type() == TQVariant::Int)) {
+
+ TQValueList<TQVariant>::ConstIterator it = c2.seq.begin();
+ TQValueList<TQVariant>::ConstIterator end = c2.seq.end();
+ _context->b = false;
+ for (; it != end; it++)
+ if ((*it).type() == TQVariant::Int &&
+ (*it).toInt() == c1.i) {
+ _context->b = true;
+ break;
+ }
+ return true;
+ }
+
+ if ( c1.type == ParseContext::T_DOUBLE &&
+ c2.type == ParseContext::T_SEQ &&
+ (*(c2.seq.begin())).type() == TQVariant::Double) {
+
+ TQValueList<TQVariant>::ConstIterator it = c2.seq.begin();
+ TQValueList<TQVariant>::ConstIterator end = c2.seq.end();
+ _context->b = false;
+ for (; it != end; it++)
+ if ((*it).type() == TQVariant::Double &&
+ (*it).toDouble() == c1.i) {
+ _context->b = true;
+ break;
+ }
+ return true;
+ }
+
+ if ( c1.type == ParseContext::T_STRING && c2.type == ParseContext::T_STR_SEQ )
+ {
+ _context->b = ( c2.strSeq.find( c1.str ) != c2.strSeq.end() );
+ return true;
+ }
+
+ return false;
+}
+
+bool ParseTreeID::eval( ParseContext *_context ) const
+{
+ TQVariant prop = _context->service->property( m_str );
+ if ( !prop.isValid() )
+ return false;
+
+ if ( prop.type() == TQVariant::String )
+ {
+ _context->str = prop.toString();
+ _context->type = ParseContext::T_STRING;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::Int )
+ {
+ _context->i = prop.toInt();
+ _context->type = ParseContext::T_NUM;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::Bool )
+ {
+ _context->b = prop.toBool();
+ _context->type = ParseContext::T_BOOL;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::Double )
+ {
+ _context->f = prop.toDouble();
+ _context->type = ParseContext::T_DOUBLE;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::List )
+ {
+ _context->seq = prop.toList();
+ _context->type = ParseContext::T_SEQ;
+ return true;
+ }
+
+ if ( prop.type() == TQVariant::StringList )
+ {
+ _context->strSeq = prop.toStringList();
+ _context->type = ParseContext::T_STR_SEQ;
+ return true;
+ }
+
+ // Value has unknown type
+ return false;
+}
+
+bool ParseTreeMIN2::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_DOUBLE;
+
+ TQVariant prop = _context->service->property( m_strId );
+ if ( !prop.isValid() )
+ return false;
+
+ if ( !_context->initMaxima( m_strId ) )
+ return false;
+
+ TQMap<TQString,PreferencesMaxima>::Iterator it = _context->maxima.find( m_strId );
+ if ( it == _context->maxima.end() )
+ return false;
+
+ if ( prop.type() == TQVariant::Int && it.data().type == PreferencesMaxima::PM_INT )
+ {
+ _context->f = (double)( prop.toInt() - it.data().iMin ) /
+ (double)(it.data().iMax - it.data().iMin ) * (-2.0) + 1.0;
+ return true;
+ }
+ else if ( prop.type() == TQVariant::Double && it.data().type == PreferencesMaxima::PM_DOUBLE )
+ {
+ _context->f = ( prop.toDouble() - it.data().fMin ) / (it.data().fMax - it.data().fMin )
+ * (-2.0) + 1.0;
+ return true;
+ }
+
+ return false;
+}
+
+bool ParseTreeMAX2::eval( ParseContext *_context ) const
+{
+ _context->type = ParseContext::T_DOUBLE;
+
+ TQVariant prop = _context->service->property( m_strId );
+ if ( !prop.isValid() )
+ return false;
+
+ // Create extrema
+ if ( !_context->initMaxima( m_strId ) )
+ return false;
+
+ // Find extrema
+ TQMap<TQString,PreferencesMaxima>::Iterator it = _context->maxima.find( m_strId );
+ if ( it == _context->maxima.end() )
+ return false;
+
+ if ( prop.type() == TQVariant::Int && it.data().type == PreferencesMaxima::PM_INT )
+ {
+ _context->f = (double)( prop.toInt() - it.data().iMin ) /
+ (double)(it.data().iMax - it.data().iMin ) * 2.0 - 1.0;
+ return true;
+ }
+ else if ( prop.type() == TQVariant::Double && it.data().type == PreferencesMaxima::PM_DOUBLE )
+ {
+ _context->f = ( prop.toDouble() - it.data().fMin ) /
+ (it.data().fMax - it.data().fMin ) * 2.0 - 1.0;
+ return true;
+ }
+
+ return false;
+}
+
+int matchConstraint( const ParseTreeBase *_tree, const KService::Ptr &_service,
+ const KServiceTypeProfile::OfferList& _list )
+{
+ // Empty tree matches always
+ if ( !_tree )
+ return 1;
+
+ TQMap<TQString,PreferencesMaxima> maxima;
+ ParseContext c( _service, _list, maxima );
+
+ // Error during evaluation ?
+ if ( !_tree->eval( &c ) )
+ return -1;
+
+ // Did we get a bool ?
+ if ( c.type != ParseContext::T_BOOL )
+ return -1;
+
+ return ( c.b ? 1 : 0 );
+}
+
+PreferencesReturn matchPreferences( const ParseTreeBase *_tree, const KService::Ptr &_service,
+ const KServiceTypeProfile::OfferList& _list )
+{
+ // By default: error
+ PreferencesReturn ret;
+
+ if ( !_tree )
+ return ret;
+
+ TQMap<TQString,PreferencesMaxima> maxima;
+ ParseContext c( _service, _list, maxima );
+
+ if ( !_tree->eval( &c ) )
+ return ret;
+
+ // Did we get a numeric return value ?
+ if ( c.type == ParseContext::T_NUM )
+ {
+ ret.type = PreferencesReturn::PRT_DOUBLE;
+ ret.f = (double)c.i;
+ }
+ else if ( c.type == ParseContext::T_DOUBLE )
+ {
+ ret.type = PreferencesReturn::PRT_DOUBLE;
+ ret.f = c.f;
+ }
+
+ return ret;
+}
+
+bool ParseContext::initMaxima( const TQString& _prop )
+{
+ // Is the property known ?
+ TQVariant prop = service->property( _prop );
+ if ( !prop.isValid() )
+ return false;
+
+ // Numeric ?
+ if ( prop.type() != TQVariant::Int && prop.type() != TQVariant::Double )
+ return false;
+
+ // Did we cache the result ?
+ TQMap<TQString,PreferencesMaxima>::Iterator it = maxima.find( _prop );
+ if ( it != maxima.end() )
+ return ( it.data().type == PreferencesMaxima::PM_DOUBLE ||
+ it.data().type == PreferencesMaxima::PM_INT );
+
+ // Double or Int ?
+ PreferencesMaxima extrema;
+ if ( prop.type() == TQVariant::Int )
+ extrema.type = PreferencesMaxima::PM_INVALID_INT;
+ else
+ extrema.type = PreferencesMaxima::PM_INVALID_DOUBLE;
+
+ // Iterate over all offers
+ KServiceTypeProfile::OfferList::ConstIterator oit = offers.begin();
+ for( ; oit != offers.end(); ++oit )
+ {
+ TQVariant p = (*oit).service()->property( _prop );
+ if ( p.isValid() )
+ {
+ // Determine new maximum/minimum
+ if ( extrema.type == PreferencesMaxima::PM_INVALID_INT )
+ {
+ extrema.type = PreferencesMaxima::PM_INT;
+ extrema.iMin = p.toInt();
+ extrema.iMax = p.toInt();
+ }
+ // Correct existing extrema
+ else if ( extrema.type == PreferencesMaxima::PM_INT )
+ {
+ if ( p.toInt() < extrema.iMin )
+ extrema.iMin = p.toInt();
+ if ( p.toInt() > extrema.iMax )
+ extrema.iMax = p.toInt();
+ }
+ // Determine new maximum/minimum
+ else if ( extrema.type == PreferencesMaxima::PM_INVALID_DOUBLE )
+ {
+ extrema.type = PreferencesMaxima::PM_DOUBLE;
+ extrema.fMin = p.toDouble();
+ extrema.fMax = p.toDouble();
+ }
+ // Correct existing extrema
+ else if ( extrema.type == PreferencesMaxima::PM_DOUBLE )
+ {
+ if ( p.toDouble() < it.data().fMin )
+ extrema.fMin = p.toDouble();
+ if ( p.toDouble() > it.data().fMax )
+ extrema.fMax = p.toDouble();
+ }
+ }
+ }
+
+ // Cache the result
+ maxima.insert( _prop, extrema );
+
+ // Did we succeed ?
+ return ( extrema.type == PreferencesMaxima::PM_DOUBLE ||
+ extrema.type == PreferencesMaxima::PM_INT );
+}
+
+}