Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / sat / LookupAttr.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/sat/LookupAttr.cc
10  *
11 */
12 #include <iostream>
13 #include <sstream>
14
15 #include "zypp/base/LogTools.h"
16 #include "zypp/base/String.h"
17
18 #include "zypp/sat/detail/PoolImpl.h"
19
20 #include "zypp/sat/Pool.h"
21 #include "zypp/sat/LookupAttr.h"
22 #include "zypp/base/StrMatcher.h"
23
24 #include "zypp/CheckSum.h"
25
26 using std::endl;
27
28 ///////////////////////////////////////////////////////////////////
29 namespace zypp
30 { /////////////////////////////////////////////////////////////////
31   ///////////////////////////////////////////////////////////////////
32   namespace sat
33   { /////////////////////////////////////////////////////////////////
34
35     using detail::noSolvableId;
36
37     ///////////////////////////////////////////////////////////////////
38     //
39     //  CLASS NAME : LookupAttr::Impl
40     //
41     ///////////////////////////////////////////////////////////////////
42     /**
43      * LookupAttr implememtation.
44      *
45      * Repository and Solvable must not be set at the same time!
46      *
47      * \note When looking in pool or repo, \ref Solvable \c _solv is
48      * somewhat abused to store eiter \c Id \c 0 or \c SOLVID_META, which
49      * indicates whether the dataiterator should look into solvable or
50      * repository metadata. Remember that all \ref Solvables with an
51      * \e invalid \c Id, are treated as <tt>== Solvable::noSolvable</tt>,
52      * and in a boolean context evaluate to \c false. Thus \c noSolvable
53      * may have different \c Ids.
54      */
55     class LookupAttr::Impl
56     {
57       public:
58         Impl()
59         : _parent( SolvAttr::noAttr )
60         {}
61         Impl( SolvAttr attr_r, Location loc_r )
62         : _attr( attr_r ), _parent( attr_r.parent() ), _solv( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId )
63         {}
64         Impl( SolvAttr attr_r, Repository repo_r, Location loc_r )
65         : _attr( attr_r ), _parent( attr_r.parent() ), _repo( repo_r ), _solv( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId )
66         {}
67         Impl( SolvAttr attr_r, Solvable solv_r )
68         : _attr( attr_r ), _parent( attr_r.parent() ), _solv( solv_r )
69         {}
70
71       public:
72         SolvAttr attr() const
73         { return _attr; }
74
75         void setAttr( SolvAttr attr_r )
76         {
77           _attr = attr_r;
78           SolvAttr p( _attr.parent() );
79           if ( p != SolvAttr::noAttr )
80             _parent = p;
81         }
82
83         const StrMatcher & strMatcher() const
84         { return _strMatcher; }
85
86         void setStrMatcher( const StrMatcher & matcher_r )
87         {
88           matcher_r.compile();
89           _strMatcher = matcher_r;
90         }
91
92       public:
93         bool pool() const
94         { return ! (_repo || _solv); }
95
96         void setPool( Location loc_r )
97         {
98           _repo = Repository::noRepository;
99           _solv = Solvable( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId );
100         }
101
102         Repository repo() const
103         { return _repo; }
104
105         void setRepo( Repository repo_r, Location loc_r  )
106         {
107           _repo = repo_r;
108           _solv = Solvable( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId );
109         }
110
111         Solvable solvable() const
112         { return _solv; }
113
114         void setSolvable( Solvable solv_r )
115         {
116           _repo = Repository::noRepository;
117           _solv = solv_r;
118         }
119
120         SolvAttr parent() const
121         { return _parent; }
122
123         void setParent( SolvAttr attr_r )
124         { _parent = attr_r; }
125
126       public:
127         LookupAttr::iterator begin() const
128         {
129           if ( _attr == SolvAttr::noAttr || sat::Pool::instance().reposEmpty() )
130             return end();
131
132           detail::RepoIdType whichRepo = detail::noRepoId; // all repos
133           if ( _solv )
134             whichRepo = _solv.repository().id();
135           else if ( _repo )
136             whichRepo = _repo.id();
137
138           detail::DIWrap dip( whichRepo, _solv.id(), _attr.id(), _strMatcher.searchstring(), _strMatcher.flags().get() );
139           if ( _parent != SolvAttr::noAttr )
140             ::dataiterator_prepend_keyname( dip.get(), _parent.id() );
141
142           return iterator( dip ); // iterator takes over ownership!
143         }
144
145         LookupAttr::iterator end() const
146         { return iterator(); }
147
148       private:
149         SolvAttr   _attr;
150         SolvAttr   _parent;
151         Repository _repo;
152         Solvable   _solv;
153         StrMatcher _strMatcher;
154
155       private:
156         friend Impl * rwcowClone<Impl>( const Impl * rhs );
157         /** clone for RWCOW_pointer */
158         Impl * clone() const
159         { return new Impl( *this ); }
160     };
161
162     ///////////////////////////////////////////////////////////////////
163     //
164     //  CLASS NAME : LookupAttr
165     //
166     ///////////////////////////////////////////////////////////////////
167
168     LookupAttr::LookupAttr()
169       : _pimpl( new Impl )
170     {}
171
172     LookupAttr::LookupAttr( SolvAttr attr_r, Location loc_r )
173       : _pimpl( new Impl( attr_r, loc_r ) )
174     {}
175     LookupAttr::LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Location loc_r )
176       : _pimpl( new Impl( attr_r, loc_r ) )
177     { _pimpl->setParent( parent_r ); }
178
179     LookupAttr::LookupAttr( SolvAttr attr_r, Repository repo_r, Location loc_r )
180       : _pimpl( new Impl( attr_r, repo_r, loc_r ) )
181     {}
182     LookupAttr::LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Repository repo_r, Location loc_r )
183       : _pimpl( new Impl( attr_r, repo_r, loc_r ) )
184     { _pimpl->setParent( parent_r ); }
185
186     LookupAttr::LookupAttr( SolvAttr attr_r, Solvable solv_r )
187       : _pimpl( new Impl( attr_r, solv_r ) )
188     {}
189     LookupAttr::LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Solvable solv_r )
190       : _pimpl( new Impl( attr_r, solv_r ) )
191     { _pimpl->setParent( parent_r ); }
192
193
194     ///////////////////////////////////////////////////////////////////
195
196     SolvAttr LookupAttr::attr() const
197     { return _pimpl->attr(); }
198
199     void LookupAttr::setAttr( SolvAttr attr_r )
200     { _pimpl->setAttr( attr_r ); }
201
202     const StrMatcher & LookupAttr::strMatcher() const
203     { return _pimpl->strMatcher(); }
204
205     void LookupAttr::setStrMatcher( const StrMatcher & matcher_r )
206     { _pimpl->setStrMatcher( matcher_r ); }
207
208     ///////////////////////////////////////////////////////////////////
209
210     bool LookupAttr::pool() const
211     { return _pimpl->pool(); }
212
213     void LookupAttr::setPool( Location loc_r )
214     { _pimpl->setPool( loc_r ); }
215
216     Repository LookupAttr::repo() const
217     { return _pimpl->repo(); }
218
219     void LookupAttr::setRepo( Repository repo_r, Location loc_r )
220     { _pimpl->setRepo( repo_r, loc_r ); }
221
222     Solvable LookupAttr::solvable() const
223     { return _pimpl->solvable(); }
224
225     void LookupAttr::setSolvable( Solvable solv_r )
226     { _pimpl->setSolvable( solv_r ); }
227
228     SolvAttr LookupAttr::parent() const
229     { return _pimpl->parent(); }
230
231     void LookupAttr::setParent( SolvAttr attr_r )
232     { _pimpl->setParent( attr_r ); }
233
234     ///////////////////////////////////////////////////////////////////
235
236     LookupAttr::iterator LookupAttr::begin() const
237     { return _pimpl->begin(); }
238
239     LookupAttr::iterator LookupAttr::end() const
240     { return _pimpl->end(); }
241
242     bool LookupAttr::empty() const
243     { return begin() == end(); }
244
245     LookupAttr::size_type LookupAttr::size() const
246     {
247       size_type c = 0;
248       for_( it, begin(), end() )
249         ++c;
250       return c;
251     }
252
253     ///////////////////////////////////////////////////////////////////
254
255     std::ostream & operator<<( std::ostream & str, const LookupAttr & obj )
256     {
257       if ( obj.attr() == SolvAttr::noAttr )
258         return str << "search nothing";
259
260       if ( obj.attr() )
261         str << "seach " << obj.attr() << " in ";
262       else
263         str << "seach ALL in ";
264
265       if ( obj.solvable() )
266         return str << obj.solvable();
267       if ( obj.repo() )
268         return str << obj.repo();
269       return str << "pool";
270     }
271
272     std::ostream & dumpOn( std::ostream & str, const LookupAttr & obj )
273     {
274       return dumpRange( str << obj, obj.begin(), obj.end() );
275     }
276
277     ///////////////////////////////////////////////////////////////////
278     //
279     //  CLASS NAME : LookupRepoAttr
280     //
281     ///////////////////////////////////////////////////////////////////
282
283     LookupRepoAttr::LookupRepoAttr( SolvAttr attr_r, Repository repo_r )
284       : LookupAttr( attr_r, repo_r, REPO_ATTR )
285     {}
286
287     void LookupRepoAttr::setRepo( Repository repo_r )
288     { LookupAttr::setRepo( repo_r, REPO_ATTR ); }
289
290     ///////////////////////////////////////////////////////////////////
291     //
292     //  CLASS NAME : detail::DIWrap
293     //
294     ///////////////////////////////////////////////////////////////////
295
296     namespace detail
297     {
298       DIWrap::DIWrap( RepoIdType repoId_r, SolvableIdType solvId_r, IdType attrId_r,
299                       const std::string & mstring_r, int flags_r )
300       : _dip( new ::Dataiterator )
301       , _mstring( mstring_r )
302       {
303         ::dataiterator_init( _dip, sat::Pool::instance().get(), repoId_r, solvId_r, attrId_r,
304                              _mstring.empty() ? 0 : _mstring.c_str(), flags_r );
305       }
306
307       DIWrap::DIWrap( RepoIdType repoId_r, SolvableIdType solvId_r, IdType attrId_r,
308                       const char * mstring_r, int flags_r )
309       : _dip( new ::Dataiterator )
310       , _mstring( mstring_r ? mstring_r : "" )
311       {
312         ::dataiterator_init( _dip, sat::Pool::instance().get(), repoId_r, solvId_r, attrId_r,
313                              _mstring.empty() ? 0 : _mstring.c_str(), flags_r );
314       }
315
316       DIWrap::DIWrap( const DIWrap & rhs )
317         : _dip( 0 )
318         , _mstring( rhs._mstring )
319       {
320         if ( rhs._dip )
321         {
322           _dip = new ::Dataiterator;
323           ::dataiterator_init_clone( _dip, rhs._dip );
324           ::dataiterator_strdup( _dip );
325         }
326       }
327
328       DIWrap::~DIWrap()
329       {
330         if ( _dip )
331         {
332           ::dataiterator_free( _dip );
333           delete _dip;
334         }
335       }
336
337       std::ostream & operator<<( std::ostream & str, const DIWrap & obj )
338       { return str << obj.get(); }
339     }
340
341     ///////////////////////////////////////////////////////////////////
342     //
343     //  CLASS NAME : LookupAttr::iterator
344     //
345     ///////////////////////////////////////////////////////////////////
346
347     ///////////////////////////////////////////////////////////////////
348     // position and moving
349     ///////////////////////////////////////////////////////////////////
350
351     Repository LookupAttr::iterator::inRepo() const
352     { return _dip ? Repository( _dip->repo ) : Repository::noRepository; }
353
354     Solvable LookupAttr::iterator::inSolvable() const
355     { return _dip ? Solvable( _dip->solvid ) : Solvable::noSolvable; }
356
357     SolvAttr LookupAttr::iterator::inSolvAttr() const
358     { return _dip ? SolvAttr( _dip->key->name ) : SolvAttr::noAttr; }
359
360     void LookupAttr::iterator::nextSkipSolvAttr()
361     { if ( _dip ) ::dataiterator_skip_attribute( _dip.get() ); }
362
363     void LookupAttr::iterator::nextSkipSolvable()
364     { if ( _dip ) ::dataiterator_skip_solvable( _dip.get() ); }
365
366     void LookupAttr::iterator::nextSkipRepo()
367     { if ( _dip ) ::dataiterator_skip_repo( _dip.get() ); }
368
369     void LookupAttr::iterator::stayInThisSolvable()
370     { if ( _dip ) { _dip.get()->repoid = -1; _dip.get()->flags |= SEARCH_THISSOLVID; } }
371
372     void LookupAttr::iterator::stayInThisRepo()
373     { if ( _dip ) { _dip.get()->repoid = -1; } }
374
375     ///////////////////////////////////////////////////////////////////
376     // attr value type test
377     ///////////////////////////////////////////////////////////////////
378
379     detail::IdType LookupAttr::iterator::solvAttrType() const
380     { return _dip ? _dip->key->type : detail::noId; }
381
382     bool LookupAttr::iterator::solvAttrNumeric() const
383     {
384       switch ( solvAttrType() )
385       {
386         case REPOKEY_TYPE_U32:
387         case REPOKEY_TYPE_NUM:
388         case REPOKEY_TYPE_CONSTANT:
389           return true;
390           break;
391       }
392       return false;
393     }
394
395     bool LookupAttr::iterator::solvAttrString() const
396     {
397       switch ( solvAttrType() )
398       {
399         case REPOKEY_TYPE_ID:
400         case REPOKEY_TYPE_IDARRAY:
401         case REPOKEY_TYPE_CONSTANTID:
402         case REPOKEY_TYPE_STR:
403         case REPOKEY_TYPE_DIRSTRARRAY:
404           return true;
405           break;
406       }
407       return false;
408     }
409
410     bool LookupAttr::iterator::solvAttrIdString() const
411     {
412       switch ( solvAttrType() )
413       {
414         case REPOKEY_TYPE_ID:
415         case REPOKEY_TYPE_IDARRAY:
416         case REPOKEY_TYPE_CONSTANTID:
417           return true;
418           break;
419       }
420       return false;
421     }
422
423     bool LookupAttr::iterator::solvAttrCheckSum() const
424     {
425       switch ( solvAttrType() )
426       {
427         case REPOKEY_TYPE_MD5:
428         case REPOKEY_TYPE_SHA1:
429         case REPOKEY_TYPE_SHA256:
430           return true;
431           break;
432       }
433       return false;
434     }
435
436     ///////////////////////////////////////////////////////////////////
437     namespace
438     {
439       enum SubType { ST_NONE,   // no sub-structure
440                      ST_FLEX,   // flexarray
441                      ST_SUB };  // inside sub-structure
442       SubType subType( const detail::DIWrap & dip )
443       {
444         if ( ! dip )
445           return ST_NONE;
446         if ( dip.get()->key->type == REPOKEY_TYPE_FLEXARRAY )
447           return ST_FLEX;
448         return dip.get()->kv.parent ? ST_SUB : ST_NONE;
449       }
450     }
451     ///////////////////////////////////////////////////////////////////
452
453     bool LookupAttr::iterator::solvAttrSubEntry() const
454     { return subType( _dip ) != ST_NONE; }
455
456     ///////////////////////////////////////////////////////////////////
457     // Iterate sub-structures.
458     ///////////////////////////////////////////////////////////////////
459
460     bool LookupAttr::iterator::subEmpty() const
461     { return( subBegin() == subEnd() ); }
462
463     LookupAttr::size_type LookupAttr::iterator::subSize() const
464     {
465       size_type c = 0;
466       for_( it, subBegin(), subEnd() )
467         ++c;
468       return c;
469     }
470
471     LookupAttr::iterator LookupAttr::iterator::subBegin() const
472     {
473       SubType subtype( subType( _dip ) );
474       if ( subtype == ST_NONE )
475         return subEnd();
476       // setup the new sub iterator with the remembered position
477       detail::DIWrap dip( 0, 0, 0 );
478       ::dataiterator_clonepos( dip.get(), _dip.get() );
479       switch ( subtype )
480       {
481         case ST_NONE:   // not reached
482           break;
483         case ST_FLEX:
484           ::dataiterator_seek( dip.get(), DI_SEEK_CHILD|DI_SEEK_STAY );
485           break;
486         case ST_SUB:
487           ::dataiterator_seek( dip.get(), DI_SEEK_REWIND|DI_SEEK_STAY );
488           break;
489       }
490       return iterator( dip ); // iterator takes over ownership!
491     }
492
493     LookupAttr::iterator LookupAttr::iterator::subEnd() const
494     {
495       return iterator();
496     }
497
498     LookupAttr::iterator LookupAttr::iterator::subFind( SolvAttr attr_r ) const
499     {
500       iterator it = subBegin();
501       if ( attr_r != sat::SolvAttr::allAttr )
502       {
503         while ( it != subEnd() && it.inSolvAttr() != attr_r )
504           ++it;
505       }
506       return it;
507     }
508
509     LookupAttr::iterator LookupAttr::iterator::subFind( const C_Str & attrname_r ) const
510     {
511       if ( attrname_r.empty() )
512         return subBegin();
513
514       SubType subtype( subType( _dip ) );
515       if ( subtype == ST_NONE )
516         return subBegin();
517
518       std::string subattr( inSolvAttr().asString() );
519       if ( subtype == ST_FLEX )
520       {
521         // append ":attrname"
522         subattr += ":";
523         subattr += attrname_r;
524       }
525       else
526       {
527         // replace "oldname" after ':' with "attrname"
528         std::string::size_type pos( subattr.rfind( ':' ) );
529         if ( pos != std::string::npos )
530         {
531           subattr.erase( pos+1 );
532           subattr += attrname_r;
533         }
534         else
535           subattr = attrname_r; // no ':' so replace all.
536       }
537       return subFind( SolvAttr( subattr ) );
538     }
539
540     ///////////////////////////////////////////////////////////////////
541     // attr value retrieval
542     ///////////////////////////////////////////////////////////////////
543
544     int LookupAttr::iterator::asInt() const
545     {
546       if ( _dip )
547       {
548         switch ( solvAttrType() )
549         {
550           case REPOKEY_TYPE_U32:
551           case REPOKEY_TYPE_NUM:
552           case REPOKEY_TYPE_CONSTANT:
553             return _dip->kv.num;
554             break;
555         }
556       }
557       return 0;
558     }
559
560     unsigned LookupAttr::iterator::asUnsigned() const
561     { return asInt(); }
562
563     unsigned long long LookupAttr::iterator::asUnsignedLL() const
564     {
565       if ( _dip )
566       {
567         switch ( solvAttrType() )
568         {
569           case REPOKEY_TYPE_U32:
570           case REPOKEY_TYPE_NUM:
571           case REPOKEY_TYPE_CONSTANT:
572             return SOLV_KV_NUM64(&_dip->kv);
573             break;
574         }
575       }
576       return 0;
577     }
578
579     bool LookupAttr::iterator::asBool() const
580     { return asInt(); }
581
582
583     const char * LookupAttr::iterator::c_str() const
584     {
585       if ( _dip )
586       {
587         switch ( solvAttrType() )
588         {
589           case REPOKEY_TYPE_ID:
590           case REPOKEY_TYPE_IDARRAY:
591           case REPOKEY_TYPE_CONSTANTID:
592             if ( _dip->data && _dip->data->localpool )
593               return ::stringpool_id2str( &_dip->data->spool, _dip->kv.id ); // in local pool
594             else
595               return IdString( _dip->kv.id ).c_str(); // in global pool
596             break;
597
598           case REPOKEY_TYPE_STR:
599             return _dip->kv.str;
600             break;
601
602           case REPOKEY_TYPE_DIRSTRARRAY:
603             // may or may not be stringified depending on SEARCH_FILES flag
604             return( _dip->flags & SEARCH_FILES
605                     ? _dip->kv.str
606                     : ::repodata_dir2str( _dip->data, _dip->kv.id, _dip->kv.str ) );
607             break;
608         }
609       }
610       return 0;
611     }
612
613     std::string LookupAttr::iterator::asString() const
614     {
615       if ( _dip )
616       {
617         switch ( solvAttrType() )
618         {
619           case REPOKEY_TYPE_ID:
620           case REPOKEY_TYPE_IDARRAY:
621           case REPOKEY_TYPE_CONSTANTID:
622             {
623               detail::IdType id = ::repodata_globalize_id( _dip->data, _dip->kv.id, 1 );
624               return ISRELDEP(id) ? Capability( id ).asString()
625                                   : IdString( id ).asString();
626             }
627             break;
628
629           case REPOKEY_TYPE_STR:
630           case REPOKEY_TYPE_DIRSTRARRAY:
631             {
632               const char * ret( c_str() );
633               return ret ? ret : "";
634             }
635             break;
636
637           case REPOKEY_TYPE_U32:
638           case REPOKEY_TYPE_NUM:
639           case REPOKEY_TYPE_CONSTANT:
640             return str::numstring( asInt() );
641             break;
642
643           case REPOKEY_TYPE_MD5:
644           case REPOKEY_TYPE_SHA1:
645           case REPOKEY_TYPE_SHA256:
646             {
647               return asCheckSum().asString();
648             }
649             break;
650
651           case REPOKEY_TYPE_FLEXARRAY:
652             {
653               std::ostringstream str;
654               str << "{" << endl;
655               for_( it, subBegin(), subEnd() )
656               {
657                 str << "  " << it.inSolvAttr() << " = " << it.asString() << endl;
658               }
659               str << "}";
660              return str.str();
661             }
662             break;
663         }
664       }
665       return std::string();
666     }
667
668     IdString LookupAttr::iterator::idStr() const
669     {
670       if ( _dip )
671       {
672         switch ( solvAttrType() )
673         {
674           case REPOKEY_TYPE_ID:
675           case REPOKEY_TYPE_IDARRAY:
676           case REPOKEY_TYPE_CONSTANTID:
677             return IdString( ::repodata_globalize_id( _dip->data, _dip->kv.id, 1 ) );
678             break;
679         }
680       }
681       return IdString();
682     }
683
684     CheckSum LookupAttr::iterator::asCheckSum() const
685     {
686       if ( _dip )
687       {
688         switch ( solvAttrType() )
689         {
690           case REPOKEY_TYPE_MD5:
691             return CheckSum::md5( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
692             break;
693
694           case REPOKEY_TYPE_SHA1:
695             return CheckSum::sha1( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
696             break;
697
698           case REPOKEY_TYPE_SHA224:
699             return CheckSum::sha224( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
700             break;
701
702           case REPOKEY_TYPE_SHA256:
703             return CheckSum::sha256( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
704             break;
705
706           case REPOKEY_TYPE_SHA384:
707             return CheckSum::sha384( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
708             break;
709
710           case REPOKEY_TYPE_SHA512:
711             return CheckSum::sha512( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
712             break;
713         }
714       }
715       return CheckSum();
716     }
717
718     ///////////////////////////////////////////////////////////////////
719     // internal stuff below
720     ///////////////////////////////////////////////////////////////////
721
722     LookupAttr::iterator::iterator()
723     : iterator_adaptor_( 0 )
724     {}
725
726     LookupAttr::iterator::iterator( const iterator & rhs )
727     : iterator_adaptor_( 0 )
728     , _dip( rhs._dip )
729     {
730       base_reference() = _dip.get();
731     }
732
733     LookupAttr::iterator::iterator( detail::DIWrap & dip_r )
734     : iterator_adaptor_( 0 )
735     {
736       _dip.swap( dip_r ); // take ownership!
737       base_reference() = _dip.get();
738       increment();
739     }
740
741     LookupAttr::iterator::~iterator()
742     {}
743
744     LookupAttr::iterator & LookupAttr::iterator::operator=( const iterator & rhs )
745     {
746       if ( &rhs != this )
747       {
748         _dip = rhs._dip;
749         base_reference() = _dip.get();
750       }
751       return *this;
752     }
753
754     ///////////////////////////////////////////////////////////////////
755
756     bool LookupAttr::iterator::dip_equal( const detail::CDataiterator & lhs, const detail::CDataiterator & rhs ) const
757     {
758       // Iterator equal is same position in same container.
759       // Here: same attribute in same solvable.
760       return( lhs.solvid == rhs.solvid && lhs.key->name == rhs.key->name );
761     }
762
763     detail::IdType LookupAttr::iterator::dereference() const
764     {
765       return _dip ? ::repodata_globalize_id( _dip->data, _dip->kv.id, 1 )
766                   : detail::noId;
767     }
768
769     void LookupAttr::iterator::increment()
770     {
771       if ( _dip )
772       {
773         if ( ! ::dataiterator_step( _dip.get() ) )
774         {
775           _dip.reset();
776           base_reference() = 0;
777         }
778         else
779         {
780           ::dataiterator_strdup( _dip.get() );
781         }
782       }
783     }
784
785     std::ostream & operator<<( std::ostream & str, const LookupAttr::iterator & obj )
786     {
787       const detail::CDataiterator * dip = obj.get();
788       if ( ! dip )
789         return str << "EndOfQuery";
790
791       if ( obj.inSolvable() )
792         str << obj.inSolvable();
793       else if ( obj.inRepo() )
794         str << obj.inRepo();
795
796       str << '<' << obj.inSolvAttr() << (obj.solvAttrSubEntry() ? ">(*" : ">(")
797           <<  IdString(obj.solvAttrType()) << ") = " << obj.asString();
798       return str;
799     }
800
801     template<> CheckSum LookupAttr::iterator::asType<CheckSum>() const
802     { return asCheckSum(); }
803
804     /////////////////////////////////////////////////////////////////
805   } // namespace sat
806   ///////////////////////////////////////////////////////////////////
807   /////////////////////////////////////////////////////////////////
808 } // namespace zypp
809 ///////////////////////////////////////////////////////////////////
810
811 std::ostream & operator<<( std::ostream & str, const zypp::sat::detail::CDataiterator * obj )
812 {
813   str << "detail::CDataiterator(";
814   if ( ! obj )
815   {
816     str << "NULL";
817   }
818   else
819   {
820     str << "|" << zypp::Repository(obj->repo);
821     str << "|" << zypp::sat::Solvable(obj->solvid);
822     str << "|" << zypp::IdString(obj->key->name);
823     str << "|" << zypp::IdString(obj->key->type);
824     str << "|" << obj->repodataid;
825     str << "|" << obj->repoid;
826   }
827   return str << ")";
828 }
829
830 ///////////////////////////////////////////////////////////////////