diff options
Diffstat (limited to 'tdeio/tdeio/ktraderparsetree.cpp')
-rw-r--r-- | tdeio/tdeio/ktraderparsetree.cpp | 714 |
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 ); +} + +} |