// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> // 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., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. #include "argsparser.h" #include "../objects/object_imp.h" #include "../objects/object_holder.h" #include <cassert> #include <algorithm> #include <kdebug.h> void ArgsParser::initialize( const struct spec* args, int n ) { std::vector<spec> vect( args, args + n ); initialize( vect ); } ArgsParser::ArgsParser() { } ArgsParser::ArgsParser( const std::vector<spec>& args ) { initialize( args ); } void ArgsParser::initialize( const std::vector<spec>& args ) { margs = args; } ArgsParser::ArgsParser( const spec* args, int n ) { initialize( args, n ); } static bool hasimp( const ObjectCalcer& o, const ObjectImpType* imptype ) { return o.imp()->inherits( imptype ); } static bool hasimp( const ObjectImp& o, const ObjectImpType* imptype ) { return o.inherits( imptype ); } static bool isvalid( const ObjectImp& o ) { return o.valid(); } static bool isvalid( const ObjectCalcer& o ) { return o.imp()->valid(); } // we use a template method that is used for both Objects and Args to // not have to write the same thing twice.. template <class Collection> static int check( const Collection& c, const std::vector<ArgsParser::spec>& margs ) { std::vector<bool> found( margs.size() ); for ( typename Collection::const_iterator o = c.begin(); o != c.end(); ++o ) { for ( uint i = 0; i < margs.size(); ++i ) { if ( hasimp( **o, margs[i].type ) && !found[i] ) { // object o is of a type that we're looking for found[i] = true; goto matched; }; }; return ArgsParser::Invalid; matched: ; }; for( uint i = 0; i < margs.size(); ++i ) if ( !found[i] ) return ArgsParser::Valid; return ArgsParser::Complete; } int ArgsParser::check( const Args& os ) const { return ::check( os, margs ); } int ArgsParser::check( const std::vector<ObjectCalcer*>& os ) const { return ::check( os, margs ); } template <typename Collection> static Collection parse( const Collection& os, const std::vector<ArgsParser::spec> margs ) { Collection ret( margs.size(), static_cast<typename Collection::value_type>( 0 ) ); for ( typename Collection::const_iterator o = os.begin(); o != os.end(); ++o ) { for( uint i = 0; i < margs.size(); ++i ) if ( hasimp( **o, margs[i].type ) && ret[i] == 0 ) { // object o is of a type that we're looking for ret[i] = *o; goto added; } added: ; }; // remove 0's from the output.. ret.erase( std::remove( ret.begin(), ret.end(), static_cast<typename Collection::value_type>( 0 ) ), ret.end() ); return ret; } Args ArgsParser::parse( const Args& os ) const { return ::parse( os, margs ); } std::vector<ObjectCalcer*> ArgsParser::parse( const std::vector<ObjectCalcer*>& os ) const { return ::parse( os, margs ); } ArgsParser ArgsParser::without( const ObjectImpType* type ) const { std::vector<spec> ret; ret.reserve( margs.size() - 1 ); for ( uint i = 0; i < margs.size(); ++i ) if ( margs[i].type != type ) ret.push_back( margs[i] ); return ArgsParser( ret ); } ArgsParser::spec ArgsParser::findSpec( const ObjectImp* obj, const Args& parents ) const { spec ret; ret.type = 0; std::vector<bool> found( margs.size(), false ); for ( Args::const_iterator o = parents.begin(); o != parents.end(); ++o ) { for ( uint i = 0; i < margs.size(); ++i ) { if ( (*o)->inherits( margs[i].type ) && !found[i] ) { // object o is of a type that we're looking for found[i] = true; if ( *o == obj ) return margs[i]; // i know that "goto's are *evil*", but they're very useful // and completely harmless if you use them as better "break;" // statements.. trust me ;) goto matched; }; }; matched: ; }; kdDebug() << k_funcinfo << "no proper spec found :(" << endl; return ret; } const ObjectImpType* ArgsParser::impRequirement( const ObjectImp* o, const Args& parents ) const { spec s = findSpec( o, parents ); return s.type; } std::string ArgsParser::usetext( const ObjectImp* obj, const Args& sel ) const { spec s = findSpec( obj, sel ); return s.usetext; } template<typename Collection> static bool checkArgs( const Collection& os, uint min, const std::vector<ArgsParser::spec>& argsspec ) { assert( os.size() <= argsspec.size() ); if( os.size() < min ) return false; uint checknum = os.size(); for ( uint i = 0; i < checknum; ++i ) { if( !isvalid( *os[i] ) ) return false; if( !hasimp( *os[i], argsspec[i].type ) ) return false; } return true; } bool ArgsParser::checkArgs( const Args& os ) const { return checkArgs( os, margs.size() ); } bool ArgsParser::checkArgs( const Args& os, uint min ) const { return ::checkArgs( os, min, margs ); } bool ArgsParser::checkArgs( const std::vector<ObjectCalcer*>& os ) const { return checkArgs( os, margs.size() ); } bool ArgsParser::checkArgs( const std::vector<ObjectCalcer*>& os, uint minobjects ) const { return ::checkArgs( os, minobjects, margs ); } ArgsParser::~ArgsParser() { } bool ArgsParser::isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const { spec s = findSpec( o, parents ); return s.onOrThrough; } std::string ArgsParser::selectStatement( const Args& selection ) const { std::vector<bool> found( margs.size(), false ); for ( Args::const_iterator o = selection.begin(); o != selection.end(); ++o ) { for ( uint i = 0; i < margs.size(); ++i ) { if ( (*o)->inherits( margs[i].type ) && !found[i] ) { // object o is of a type that we're looking for found[i] = true; break; } } } for ( uint i = 0; i < margs.size(); ++i ) { if ( !found[i] ) return margs[i].selectstat; } kdDebug() << k_funcinfo << "no proper select statement found :(" << endl; return 0; }