libzypp  10.5.0
LookupAttr.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <sstream>
00014 
00015 #include "zypp/base/LogTools.h"
00016 #include "zypp/base/String.h"
00017 
00018 #include "zypp/sat/detail/PoolImpl.h"
00019 
00020 #include "zypp/sat/Pool.h"
00021 #include "zypp/sat/LookupAttr.h"
00022 #include "zypp/sat/AttrMatcher.h"
00023 
00024 #include "zypp/CheckSum.h"
00025 
00026 using std::endl;
00027 
00029 namespace zypp
00030 { 
00031 
00032   namespace sat
00033   { 
00034 
00035     using detail::noSolvableId;
00036 
00038     //
00039     //  CLASS NAME : LookupAttr::Impl
00040     //
00042 
00055     class LookupAttr::Impl
00056     {
00057       public:
00058         Impl()
00059         : _parent( SolvAttr::noAttr )
00060         {}
00061         Impl( SolvAttr attr_r, Location loc_r )
00062         : _attr( attr_r ), _parent( attr_r.parent() ), _solv( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId )
00063         {}
00064         Impl( SolvAttr attr_r, Repository repo_r, Location loc_r )
00065         : _attr( attr_r ), _parent( attr_r.parent() ), _repo( repo_r ), _solv( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId )
00066         {}
00067         Impl( SolvAttr attr_r, Solvable solv_r )
00068         : _attr( attr_r ), _parent( attr_r.parent() ), _solv( solv_r )
00069         {}
00070 
00071       public:
00072         SolvAttr attr() const
00073         { return _attr; }
00074 
00075         void setAttr( SolvAttr attr_r )
00076         {
00077           _attr = attr_r;
00078           SolvAttr p( _attr.parent() );
00079           if ( p != SolvAttr::noAttr )
00080             _parent = p;
00081         }
00082 
00083         const AttrMatcher & attrMatcher() const
00084         { return _attrMatcher; }
00085 
00086         void setAttrMatcher( const AttrMatcher & matcher_r )
00087         {
00088           matcher_r.compile();
00089           _attrMatcher = matcher_r;
00090         }
00091 
00092       public:
00093         bool pool() const
00094         { return ! (_repo || _solv); }
00095 
00096         void setPool( Location loc_r )
00097         {
00098           _repo = Repository::noRepository;
00099           _solv = Solvable( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId );
00100         }
00101 
00102         Repository repo() const
00103         { return _repo; }
00104 
00105         void setRepo( Repository repo_r, Location loc_r  )
00106         {
00107           _repo = repo_r;
00108           _solv = Solvable( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId );
00109         }
00110 
00111         Solvable solvable() const
00112         { return _solv; }
00113 
00114         void setSolvable( Solvable solv_r )
00115         {
00116           _repo = Repository::noRepository;
00117           _solv = solv_r;
00118         }
00119 
00120         SolvAttr parent() const
00121         { return _parent; }
00122 
00123         void setParent( SolvAttr attr_r )
00124         { _parent = attr_r; }
00125 
00126       public:
00127         LookupAttr::iterator begin() const
00128         {
00129           if ( _attr == SolvAttr::noAttr || sat::Pool::instance().reposEmpty() )
00130             return end();
00131 
00132           detail::RepoIdType whichRepo = detail::noRepoId; // all repos
00133           if ( _solv )
00134             whichRepo = _solv.repository().id();
00135           else if ( _repo )
00136             whichRepo = _repo.id();
00137 
00138           detail::DIWrap dip( whichRepo, _solv.id(), _attr.id(), _attrMatcher.searchstring(), _attrMatcher.flags().get() );
00139           if ( _parent != SolvAttr::noAttr )
00140             ::dataiterator_prepend_keyname( dip.get(), _parent.id() );
00141 
00142           return iterator( dip ); // iterator takes over ownership!
00143         }
00144 
00145         LookupAttr::iterator end() const
00146         { return iterator(); }
00147 
00148       private:
00149         SolvAttr   _attr;
00150         SolvAttr   _parent;
00151         Repository _repo;
00152         Solvable   _solv;
00153         AttrMatcher _attrMatcher;
00154 
00155       private:
00156         friend Impl * rwcowClone<Impl>( const Impl * rhs );
00158         Impl * clone() const
00159         { return new Impl( *this ); }
00160     };
00161 
00163     //
00164     //  CLASS NAME : LookupAttr
00165     //
00167 
00168     LookupAttr::LookupAttr()
00169       : _pimpl( new Impl )
00170     {}
00171 
00172     LookupAttr::LookupAttr( SolvAttr attr_r, Location loc_r )
00173       : _pimpl( new Impl( attr_r, loc_r ) )
00174     {}
00175     LookupAttr::LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Location loc_r )
00176       : _pimpl( new Impl( attr_r, loc_r ) )
00177     { _pimpl->setParent( parent_r ); }
00178 
00179     LookupAttr::LookupAttr( SolvAttr attr_r, Repository repo_r, Location loc_r )
00180       : _pimpl( new Impl( attr_r, repo_r, loc_r ) )
00181     {}
00182     LookupAttr::LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Repository repo_r, Location loc_r )
00183       : _pimpl( new Impl( attr_r, repo_r, loc_r ) )
00184     { _pimpl->setParent( parent_r ); }
00185 
00186     LookupAttr::LookupAttr( SolvAttr attr_r, Solvable solv_r )
00187       : _pimpl( new Impl( attr_r, solv_r ) )
00188     {}
00189     LookupAttr::LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Solvable solv_r )
00190       : _pimpl( new Impl( attr_r, solv_r ) )
00191     { _pimpl->setParent( parent_r ); }
00192 
00193 
00195 
00196     SolvAttr LookupAttr::attr() const
00197     { return _pimpl->attr(); }
00198 
00199     void LookupAttr::setAttr( SolvAttr attr_r )
00200     { _pimpl->setAttr( attr_r ); }
00201 
00202     const AttrMatcher & LookupAttr::attrMatcher() const
00203     { return _pimpl->attrMatcher(); }
00204 
00205     void LookupAttr::setAttrMatcher( const AttrMatcher & matcher_r )
00206     { _pimpl->setAttrMatcher( matcher_r ); }
00207 
00209 
00210     bool LookupAttr::pool() const
00211     { return _pimpl->pool(); }
00212 
00213     void LookupAttr::setPool( Location loc_r )
00214     { _pimpl->setPool( loc_r ); }
00215 
00216     Repository LookupAttr::repo() const
00217     { return _pimpl->repo(); }
00218 
00219     void LookupAttr::setRepo( Repository repo_r, Location loc_r )
00220     { _pimpl->setRepo( repo_r, loc_r ); }
00221 
00222     Solvable LookupAttr::solvable() const
00223     { return _pimpl->solvable(); }
00224 
00225     void LookupAttr::setSolvable( Solvable solv_r )
00226     { _pimpl->setSolvable( solv_r ); }
00227 
00228     SolvAttr LookupAttr::parent() const
00229     { return _pimpl->parent(); }
00230 
00231     void LookupAttr::setParent( SolvAttr attr_r )
00232     { _pimpl->setParent( attr_r ); }
00233 
00235 
00236     LookupAttr::iterator LookupAttr::begin() const
00237     { return _pimpl->begin(); }
00238 
00239     LookupAttr::iterator LookupAttr::end() const
00240     { return _pimpl->end(); }
00241 
00242     bool LookupAttr::empty() const
00243     { return begin() == end(); }
00244 
00245     LookupAttr::size_type LookupAttr::size() const
00246     {
00247       size_type c = 0;
00248       for_( it, begin(), end() )
00249         ++c;
00250       return c;
00251     }
00252 
00254 
00255     std::ostream & operator<<( std::ostream & str, const LookupAttr & obj )
00256     {
00257       if ( obj.attr() == SolvAttr::noAttr )
00258         return str << "search nothing";
00259 
00260       if ( obj.attr() )
00261         str << "seach " << obj.attr() << " in ";
00262       else
00263         str << "seach ALL in ";
00264 
00265       if ( obj.solvable() )
00266         return str << obj.solvable();
00267       if ( obj.repo() )
00268         return str << obj.repo();
00269       return str << "pool";
00270     }
00271 
00272     std::ostream & dumpOn( std::ostream & str, const LookupAttr & obj )
00273     {
00274       return dumpRange( str << obj, obj.begin(), obj.end() );
00275     }
00276 
00278     //
00279     //  CLASS NAME : LookupRepoAttr
00280     //
00282 
00283     LookupRepoAttr::LookupRepoAttr( SolvAttr attr_r, Repository repo_r )
00284       : LookupAttr( attr_r, repo_r, REPO_ATTR )
00285     {}
00286 
00287     void LookupRepoAttr::setRepo( Repository repo_r )
00288     { LookupAttr::setRepo( repo_r, REPO_ATTR ); }
00289 
00291     //
00292     //  CLASS NAME : detail::DIWrap
00293     //
00295 
00296     namespace detail
00297     {
00298       DIWrap::DIWrap( RepoIdType repoId_r, SolvableIdType solvId_r, IdType attrId_r,
00299                       const std::string & mstring_r, int flags_r )
00300       : _dip( new ::Dataiterator )
00301       , _mstring( mstring_r )
00302       {
00303         ::dataiterator_init( _dip, sat::Pool::instance().get(), repoId_r, solvId_r, attrId_r,
00304                              _mstring.empty() ? 0 : _mstring.c_str(), flags_r );
00305       }
00306 
00307       DIWrap::DIWrap( RepoIdType repoId_r, SolvableIdType solvId_r, IdType attrId_r,
00308                       const char * mstring_r, int flags_r )
00309       : _dip( new ::Dataiterator )
00310       , _mstring( mstring_r ? mstring_r : "" )
00311       {
00312         ::dataiterator_init( _dip, sat::Pool::instance().get(), repoId_r, solvId_r, attrId_r,
00313                              _mstring.empty() ? 0 : _mstring.c_str(), flags_r );
00314       }
00315 
00316       DIWrap::DIWrap( const DIWrap & rhs )
00317         : _dip( 0 )
00318         , _mstring( rhs._mstring )
00319       {
00320         if ( rhs._dip )
00321         {
00322           _dip = new ::Dataiterator;
00323           ::dataiterator_init_clone( _dip, rhs._dip );
00324         }
00325       }
00326 
00327       DIWrap::~DIWrap()
00328       {
00329         if ( _dip )
00330         {
00331           ::dataiterator_free( _dip );
00332           delete _dip;
00333         }
00334       }
00335 
00336       std::ostream & operator<<( std::ostream & str, const DIWrap & obj )
00337       { return str << obj.get(); }
00338     }
00339 
00341     //
00342     //  CLASS NAME : LookupAttr::iterator
00343     //
00345 
00347     // position and moving
00349 
00350     Repository LookupAttr::iterator::inRepo() const
00351     { return _dip ? Repository( _dip->repo ) : Repository::noRepository; }
00352 
00353     Solvable LookupAttr::iterator::inSolvable() const
00354     { return _dip ? Solvable( _dip->solvid ) : Solvable::noSolvable; }
00355 
00356     SolvAttr LookupAttr::iterator::inSolvAttr() const
00357     { return _dip ? SolvAttr( _dip->key->name ) : SolvAttr::noAttr; }
00358 
00359     void LookupAttr::iterator::nextSkipSolvAttr()
00360     { if ( _dip ) ::dataiterator_skip_attribute( _dip.get() ); }
00361 
00362     void LookupAttr::iterator::nextSkipSolvable()
00363     { if ( _dip ) ::dataiterator_skip_solvable( _dip.get() ); }
00364 
00365     void LookupAttr::iterator::nextSkipRepo()
00366     { if ( _dip ) ::dataiterator_skip_repo( _dip.get() ); }
00367 
00368     void LookupAttr::iterator::stayInThisSolvable()
00369     { if ( _dip ) { _dip.get()->repoid = -1; _dip.get()->flags |= SEARCH_THISSOLVID; } }
00370 
00371     void LookupAttr::iterator::stayInThisRepo()
00372     { if ( _dip ) { _dip.get()->repoid = -1; } }
00373 
00375     // attr value type test
00377 
00378     detail::IdType LookupAttr::iterator::solvAttrType() const
00379     { return _dip ? _dip->key->type : detail::noId; }
00380 
00381     bool LookupAttr::iterator::solvAttrNumeric() const
00382     {
00383       switch ( solvAttrType() )
00384       {
00385         case REPOKEY_TYPE_U32:
00386         case REPOKEY_TYPE_NUM:
00387         case REPOKEY_TYPE_CONSTANT:
00388           return true;
00389           break;
00390       }
00391       return false;
00392     }
00393 
00394     bool LookupAttr::iterator::solvAttrString() const
00395     {
00396       switch ( solvAttrType() )
00397       {
00398         case REPOKEY_TYPE_ID:
00399         case REPOKEY_TYPE_IDARRAY:
00400         case REPOKEY_TYPE_CONSTANTID:
00401         case REPOKEY_TYPE_STR:
00402         case REPOKEY_TYPE_DIRSTRARRAY:
00403           return true;
00404           break;
00405       }
00406       return false;
00407     }
00408 
00409     bool LookupAttr::iterator::solvAttrIdString() const
00410     {
00411       switch ( solvAttrType() )
00412       {
00413         case REPOKEY_TYPE_ID:
00414         case REPOKEY_TYPE_IDARRAY:
00415         case REPOKEY_TYPE_CONSTANTID:
00416           return true;
00417           break;
00418       }
00419       return false;
00420     }
00421 
00422     bool LookupAttr::iterator::solvAttrCheckSum() const
00423     {
00424       switch ( solvAttrType() )
00425       {
00426         case REPOKEY_TYPE_MD5:
00427         case REPOKEY_TYPE_SHA1:
00428         case REPOKEY_TYPE_SHA256:
00429           return true;
00430           break;
00431       }
00432       return false;
00433     }
00434 
00436     namespace
00437     {
00438       enum SubType { ST_NONE,   // no sub-structure
00439                      ST_FLEX,   // flexarray
00440                      ST_SUB };  // inside sub-structure
00441       SubType subType( const detail::DIWrap & dip )
00442       {
00443         if ( ! dip )
00444           return ST_NONE;
00445         if ( dip.get()->key->type == REPOKEY_TYPE_FLEXARRAY )
00446           return ST_FLEX;
00447         return dip.get()->kv.parent ? ST_SUB : ST_NONE;
00448       }
00449     }
00451 
00452     bool LookupAttr::iterator::solvAttrSubEntry() const
00453     { return subType( _dip ) != ST_NONE; }
00454 
00456     // Iterate sub-structures.
00458 
00459     bool LookupAttr::iterator::subEmpty() const
00460     { return( subBegin() == subEnd() ); }
00461 
00462     LookupAttr::size_type LookupAttr::iterator::subSize() const
00463     {
00464       size_type c = 0;
00465       for_( it, subBegin(), subEnd() )
00466         ++c;
00467       return c;
00468     }
00469 
00470     LookupAttr::iterator LookupAttr::iterator::subBegin() const
00471     {
00472       SubType subtype( subType( _dip ) );
00473       if ( subtype == ST_NONE )
00474         return subEnd();
00475       // setup the new sub iterator with the remembered position
00476       detail::DIWrap dip( 0, 0, 0 );
00477       ::dataiterator_clonepos( dip.get(), _dip.get() );
00478       switch ( subtype )
00479       {
00480         case ST_NONE:   // not reached
00481           break;
00482         case ST_FLEX:
00483           ::dataiterator_seek( dip.get(), DI_SEEK_CHILD|DI_SEEK_STAY );
00484           break;
00485         case ST_SUB:
00486           ::dataiterator_seek( dip.get(), DI_SEEK_REWIND|DI_SEEK_STAY );
00487           break;
00488       }
00489       return iterator( dip ); // iterator takes over ownership!
00490     }
00491 
00492     LookupAttr::iterator LookupAttr::iterator::subEnd() const
00493     {
00494       return iterator();
00495     }
00496 
00497     LookupAttr::iterator LookupAttr::iterator::subFind( SolvAttr attr_r ) const
00498     {
00499       iterator it = subBegin();
00500       if ( attr_r != sat::SolvAttr::allAttr )
00501       {
00502         while ( it != subEnd() && it.inSolvAttr() != attr_r )
00503           ++it;
00504       }
00505       return it;
00506     }
00507 
00508     LookupAttr::iterator LookupAttr::iterator::subFind( const C_Str & attrname_r ) const
00509     {
00510       if ( attrname_r.empty() )
00511         return subBegin();
00512 
00513       SubType subtype( subType( _dip ) );
00514       if ( subtype == ST_NONE )
00515         return subBegin();
00516 
00517       std::string subattr( inSolvAttr().asString() );
00518       if ( subtype == ST_FLEX )
00519       {
00520         // append ":attrname"
00521         subattr += ":";
00522         subattr += attrname_r;
00523       }
00524       else
00525       {
00526         // replace "oldname" after ':' with "attrname"
00527         std::string::size_type pos( subattr.rfind( ':' ) );
00528         if ( pos != std::string::npos )
00529         {
00530           subattr.erase( pos+1 );
00531           subattr += attrname_r;
00532         }
00533         else
00534           subattr = attrname_r; // no ':' so replace all.
00535       }
00536       return subFind( SolvAttr( subattr ) );
00537     }
00538 
00540     // attr value retrieval
00542 
00543     int LookupAttr::iterator::asInt() const
00544     {
00545       if ( _dip )
00546       {
00547         switch ( solvAttrType() )
00548         {
00549           case REPOKEY_TYPE_U32:
00550           case REPOKEY_TYPE_NUM:
00551           case REPOKEY_TYPE_CONSTANT:
00552             return _dip->kv.num;
00553             break;
00554         }
00555       }
00556       return 0;
00557     }
00558 
00559     unsigned LookupAttr::iterator::asUnsigned() const
00560     { return asInt(); }
00561 
00562     bool LookupAttr::iterator::asBool() const
00563     { return asInt(); }
00564 
00565 
00566     const char * LookupAttr::iterator::c_str() const
00567     {
00568       if ( _dip )
00569       {
00570         switch ( solvAttrType() )
00571         {
00572           case REPOKEY_TYPE_ID:
00573           case REPOKEY_TYPE_IDARRAY:
00574           case REPOKEY_TYPE_CONSTANTID:
00575             if ( _dip->data && _dip->data->localpool )
00576               return ::stringpool_id2str( &_dip->data->spool, _dip->kv.id ); // in local pool
00577             else
00578               return IdString( _dip->kv.id ).c_str(); // in global pool
00579             break;
00580 
00581           case REPOKEY_TYPE_STR:
00582             return _dip->kv.str;
00583             break;
00584 
00585           case REPOKEY_TYPE_DIRSTRARRAY:
00586             return ::repodata_dir2str( _dip->data, _dip->kv.id, _dip->kv.str );
00587             break;
00588         }
00589       }
00590       return 0;
00591     }
00592 
00593     std::string LookupAttr::iterator::asString() const
00594     {
00595       if ( _dip )
00596       {
00597         switch ( solvAttrType() )
00598         {
00599           case REPOKEY_TYPE_ID:
00600           case REPOKEY_TYPE_IDARRAY:
00601           case REPOKEY_TYPE_CONSTANTID:
00602             {
00603               detail::IdType id = ::repodata_globalize_id( _dip->data, _dip->kv.id, 1 );
00604               return ISRELDEP(id) ? Capability( id ).asString()
00605                                   : IdString( id ).asString();
00606             }
00607             break;
00608 
00609           case REPOKEY_TYPE_STR:
00610           case REPOKEY_TYPE_DIRSTRARRAY:
00611             {
00612               const char * ret( c_str() );
00613               return ret ? ret : "";
00614             }
00615             break;
00616 
00617           case REPOKEY_TYPE_U32:
00618           case REPOKEY_TYPE_NUM:
00619           case REPOKEY_TYPE_CONSTANT:
00620             return str::numstring( asInt() );
00621             break;
00622 
00623           case REPOKEY_TYPE_MD5:
00624           case REPOKEY_TYPE_SHA1:
00625           case REPOKEY_TYPE_SHA256:
00626             {
00627               return asCheckSum().asString();
00628             }
00629             break;
00630 
00631           case REPOKEY_TYPE_FLEXARRAY:
00632             {
00633               std::ostringstream str;
00634               str << "{" << endl;
00635               for_( it, subBegin(), subEnd() )
00636               {
00637                 str << "  " << it.inSolvAttr() << " = " << it.asString() << endl;
00638               }
00639               str << "}";
00640              return str.str();
00641             }
00642             break;
00643         }
00644       }
00645       return std::string();
00646     }
00647 
00648     IdString LookupAttr::iterator::idStr() const
00649     {
00650       if ( _dip )
00651       {
00652         switch ( solvAttrType() )
00653         {
00654           case REPOKEY_TYPE_ID:
00655           case REPOKEY_TYPE_IDARRAY:
00656           case REPOKEY_TYPE_CONSTANTID:
00657             return IdString( ::repodata_globalize_id( _dip->data, _dip->kv.id, 1 ) );
00658             break;
00659         }
00660       }
00661       return IdString();
00662     }
00663 
00664     CheckSum LookupAttr::iterator::asCheckSum() const
00665     {
00666       if ( _dip )
00667       {
00668         switch ( solvAttrType() )
00669         {
00670           case REPOKEY_TYPE_MD5:
00671             return CheckSum::md5( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
00672             break;
00673 
00674           case REPOKEY_TYPE_SHA1:
00675             return CheckSum::sha1( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
00676             break;
00677 
00678           case REPOKEY_TYPE_SHA256:
00679             return CheckSum::sha256( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
00680             break;
00681         }
00682       }
00683       return CheckSum();
00684     }
00685 
00687     // internal stuff below
00689 
00690     LookupAttr::iterator::iterator()
00691     : iterator_adaptor_( 0 )
00692     {}
00693 
00694     LookupAttr::iterator::iterator( const iterator & rhs )
00695     : iterator_adaptor_( 0 )
00696     , _dip( rhs._dip )
00697     {
00698       base_reference() = _dip.get();
00699     }
00700 
00701     LookupAttr::iterator::iterator( detail::DIWrap & dip_r )
00702     : iterator_adaptor_( 0 )
00703     {
00704       _dip.swap( dip_r ); // take ownership!
00705       base_reference() = _dip.get();
00706       increment();
00707     }
00708 
00709     LookupAttr::iterator::~iterator()
00710     {}
00711 
00712     LookupAttr::iterator & LookupAttr::iterator::operator=( const iterator & rhs )
00713     {
00714       if ( &rhs != this )
00715       {
00716         _dip = rhs._dip;
00717         base_reference() = _dip.get();
00718       }
00719       return *this;
00720     }
00721 
00723 
00724     bool LookupAttr::iterator::dip_equal( const ::_Dataiterator & lhs, const ::_Dataiterator & rhs ) const
00725     {
00726       // Iterator equal is same position in same container.
00727       // Here: same attribute in same solvable.
00728       return( lhs.solvid == rhs.solvid && lhs.key->name == rhs.key->name );
00729     }
00730 
00731     detail::IdType LookupAttr::iterator::dereference() const
00732     {
00733       return _dip ? ::repodata_globalize_id( _dip->data, _dip->kv.id, 1 )
00734                   : detail::noId;
00735     }
00736 
00737     void LookupAttr::iterator::increment()
00738     {
00739       if ( _dip && ! ::dataiterator_step( _dip.get() ) )
00740       {
00741         _dip.reset();
00742         base_reference() = 0;
00743       }
00744     }
00745 
00746     std::ostream & operator<<( std::ostream & str, const LookupAttr::iterator & obj )
00747     {
00748       const ::_Dataiterator * dip = obj.get();
00749       if ( ! dip )
00750         return str << "EndOfQuery";
00751 
00752       if ( obj.inSolvable() )
00753         str << obj.inSolvable();
00754       else if ( obj.inRepo() )
00755         str << obj.inRepo();
00756 
00757       str << '<' << obj.inSolvAttr() << (obj.solvAttrSubEntry() ? ">(*" : ">(")
00758           <<  IdString(obj.solvAttrType()) << ") = " << obj.asString();
00759       return str;
00760     }
00761 
00762     template<> CheckSum LookupAttr::iterator::asType<CheckSum>() const
00763     { return asCheckSum(); }
00764 
00766   } // namespace sat
00769 } // namespace zypp
00771 
00772 std::ostream & operator<<( std::ostream & str, const ::_Dataiterator * obj )
00773 {
00774   str << "::_Dataiterator(";
00775   if ( ! obj )
00776   {
00777     str << "NULL";
00778   }
00779   else
00780   {
00781     str << "|" << zypp::Repository(obj->repo);
00782     str << "|" << zypp::sat::Solvable(obj->solvid);
00783     str << "|" << zypp::IdString(obj->key->name);
00784     str << "|" << zypp::IdString(obj->key->type);
00785     str << "|" << obj->repodataid;
00786     str << "|" << obj->repoid;
00787   }
00788   return str << ")";
00789 }
00790