0bf8cdfe2de14366f9d5cf3435fee5f886bb7e22
[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_NUM:
387         case REPOKEY_TYPE_CONSTANT:
388           return true;
389           break;
390       }
391       return false;
392     }
393
394     bool LookupAttr::iterator::solvAttrString() const
395     {
396       switch ( solvAttrType() )
397       {
398         case REPOKEY_TYPE_ID:
399         case REPOKEY_TYPE_IDARRAY:
400         case REPOKEY_TYPE_CONSTANTID:
401         case REPOKEY_TYPE_STR:
402         case REPOKEY_TYPE_DIRSTRARRAY:
403           return true;
404           break;
405       }
406       return false;
407     }
408
409     bool LookupAttr::iterator::solvAttrIdString() const
410     {
411       switch ( solvAttrType() )
412       {
413         case REPOKEY_TYPE_ID:
414         case REPOKEY_TYPE_IDARRAY:
415         case REPOKEY_TYPE_CONSTANTID:
416           return true;
417           break;
418       }
419       return false;
420     }
421
422     bool LookupAttr::iterator::solvAttrCheckSum() const
423     {
424       switch ( solvAttrType() )
425       {
426         case REPOKEY_TYPE_MD5:
427         case REPOKEY_TYPE_SHA1:
428         case REPOKEY_TYPE_SHA256:
429           return true;
430           break;
431       }
432       return false;
433     }
434
435     ///////////////////////////////////////////////////////////////////
436     namespace
437     {
438       enum SubType { ST_NONE,   // no sub-structure
439                      ST_FLEX,   // flexarray
440                      ST_SUB };  // inside sub-structure
441       SubType subType( const detail::DIWrap & dip )
442       {
443         if ( ! dip )
444           return ST_NONE;
445         if ( dip.get()->key->type == REPOKEY_TYPE_FLEXARRAY )
446           return ST_FLEX;
447         return dip.get()->kv.parent ? ST_SUB : ST_NONE;
448       }
449     }
450     ///////////////////////////////////////////////////////////////////
451
452     bool LookupAttr::iterator::solvAttrSubEntry() const
453     { return subType( _dip ) != ST_NONE; }
454
455     ///////////////////////////////////////////////////////////////////
456     // Iterate sub-structures.
457     ///////////////////////////////////////////////////////////////////
458
459     bool LookupAttr::iterator::subEmpty() const
460     { return( subBegin() == subEnd() ); }
461
462     LookupAttr::size_type LookupAttr::iterator::subSize() const
463     {
464       size_type c = 0;
465       for_( it, subBegin(), subEnd() )
466         ++c;
467       return c;
468     }
469
470     LookupAttr::iterator LookupAttr::iterator::subBegin() const
471     {
472       SubType subtype( subType( _dip ) );
473       if ( subtype == ST_NONE )
474         return subEnd();
475       // setup the new sub iterator with the remembered position
476       detail::DIWrap dip( 0, 0, 0 );
477       ::dataiterator_clonepos( dip.get(), _dip.get() );
478       switch ( subtype )
479       {
480         case ST_NONE:   // not reached
481           break;
482         case ST_FLEX:
483           ::dataiterator_seek( dip.get(), DI_SEEK_CHILD|DI_SEEK_STAY );
484           break;
485         case ST_SUB:
486           ::dataiterator_seek( dip.get(), DI_SEEK_REWIND|DI_SEEK_STAY );
487           break;
488       }
489       return iterator( dip ); // iterator takes over ownership!
490     }
491
492     LookupAttr::iterator LookupAttr::iterator::subEnd() const
493     {
494       return iterator();
495     }
496
497     LookupAttr::iterator LookupAttr::iterator::subFind( SolvAttr attr_r ) const
498     {
499       iterator it = subBegin();
500       if ( attr_r != sat::SolvAttr::allAttr )
501       {
502         while ( it != subEnd() && it.inSolvAttr() != attr_r )
503           ++it;
504       }
505       return it;
506     }
507
508     LookupAttr::iterator LookupAttr::iterator::subFind( const C_Str & attrname_r ) const
509     {
510       if ( attrname_r.empty() )
511         return subBegin();
512
513       SubType subtype( subType( _dip ) );
514       if ( subtype == ST_NONE )
515         return subBegin();
516
517       std::string subattr( inSolvAttr().asString() );
518       if ( subtype == ST_FLEX )
519       {
520         // append ":attrname"
521         subattr += ":";
522         subattr += attrname_r;
523       }
524       else
525       {
526         // replace "oldname" after ':' with "attrname"
527         std::string::size_type pos( subattr.rfind( ':' ) );
528         if ( pos != std::string::npos )
529         {
530           subattr.erase( pos+1 );
531           subattr += attrname_r;
532         }
533         else
534           subattr = attrname_r; // no ':' so replace all.
535       }
536       return subFind( SolvAttr( subattr ) );
537     }
538
539     ///////////////////////////////////////////////////////////////////
540     // attr value retrieval
541     ///////////////////////////////////////////////////////////////////
542
543     int LookupAttr::iterator::asInt() const
544     {
545       if ( _dip )
546       {
547         switch ( solvAttrType() )
548         {
549           case REPOKEY_TYPE_NUM:
550           case REPOKEY_TYPE_CONSTANT:
551             return _dip->kv.num;
552             break;
553         }
554       }
555       return 0;
556     }
557
558     unsigned LookupAttr::iterator::asUnsigned() const
559     { return asInt(); }
560
561     unsigned long long LookupAttr::iterator::asUnsignedLL() const
562     {
563       if ( _dip )
564       {
565         switch ( solvAttrType() )
566         {
567           case REPOKEY_TYPE_NUM:
568           case REPOKEY_TYPE_CONSTANT:
569             return SOLV_KV_NUM64(&_dip->kv);
570             break;
571         }
572       }
573       return 0;
574     }
575
576     bool LookupAttr::iterator::asBool() const
577     { return asInt(); }
578
579
580     const char * LookupAttr::iterator::c_str() const
581     {
582       if ( _dip )
583       {
584         switch ( solvAttrType() )
585         {
586           case REPOKEY_TYPE_ID:
587           case REPOKEY_TYPE_IDARRAY:
588           case REPOKEY_TYPE_CONSTANTID:
589             if ( _dip->data && _dip->data->localpool )
590               return ::stringpool_id2str( &_dip->data->spool, _dip->kv.id ); // in local pool
591             else
592               return IdString( _dip->kv.id ).c_str(); // in global pool
593             break;
594
595           case REPOKEY_TYPE_STR:
596             return _dip->kv.str;
597             break;
598
599           case REPOKEY_TYPE_DIRSTRARRAY:
600             // may or may not be stringified depending on SEARCH_FILES flag
601             return( _dip->flags & SEARCH_FILES
602                     ? _dip->kv.str
603                     : ::repodata_dir2str( _dip->data, _dip->kv.id, _dip->kv.str ) );
604             break;
605         }
606       }
607       return 0;
608     }
609
610     std::string LookupAttr::iterator::asString() const
611     {
612       if ( _dip )
613       {
614         switch ( solvAttrType() )
615         {
616           case REPOKEY_TYPE_ID:
617           case REPOKEY_TYPE_IDARRAY:
618           case REPOKEY_TYPE_CONSTANTID:
619             {
620               detail::IdType id = ::repodata_globalize_id( _dip->data, _dip->kv.id, 1 );
621               return ISRELDEP(id) ? Capability( id ).asString()
622                                   : IdString( id ).asString();
623             }
624             break;
625
626           case REPOKEY_TYPE_STR:
627           case REPOKEY_TYPE_DIRSTRARRAY:
628             {
629               const char * ret( c_str() );
630               return ret ? ret : "";
631             }
632             break;
633
634           case REPOKEY_TYPE_NUM:
635           case REPOKEY_TYPE_CONSTANT:
636             return str::numstring( asInt() );
637             break;
638
639           case REPOKEY_TYPE_MD5:
640           case REPOKEY_TYPE_SHA1:
641           case REPOKEY_TYPE_SHA256:
642             {
643               return asCheckSum().asString();
644             }
645             break;
646
647           case REPOKEY_TYPE_FLEXARRAY:
648             {
649               std::ostringstream str;
650               str << "{" << endl;
651               for_( it, subBegin(), subEnd() )
652               {
653                 str << "  " << it.inSolvAttr() << " = " << it.asString() << endl;
654               }
655               str << "}";
656              return str.str();
657             }
658             break;
659         }
660       }
661       return std::string();
662     }
663
664     IdString LookupAttr::iterator::idStr() const
665     {
666       if ( _dip )
667       {
668         switch ( solvAttrType() )
669         {
670           case REPOKEY_TYPE_ID:
671           case REPOKEY_TYPE_IDARRAY:
672           case REPOKEY_TYPE_CONSTANTID:
673             return IdString( ::repodata_globalize_id( _dip->data, _dip->kv.id, 1 ) );
674             break;
675         }
676       }
677       return IdString();
678     }
679
680     CheckSum LookupAttr::iterator::asCheckSum() const
681     {
682       if ( _dip )
683       {
684         switch ( solvAttrType() )
685         {
686           case REPOKEY_TYPE_MD5:
687             return CheckSum::md5( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
688             break;
689
690           case REPOKEY_TYPE_SHA1:
691             return CheckSum::sha1( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
692             break;
693
694           case REPOKEY_TYPE_SHA224:
695             return CheckSum::sha224( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
696             break;
697
698           case REPOKEY_TYPE_SHA256:
699             return CheckSum::sha256( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
700             break;
701
702           case REPOKEY_TYPE_SHA384:
703             return CheckSum::sha384( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
704             break;
705
706           case REPOKEY_TYPE_SHA512:
707             return CheckSum::sha512( ::repodata_chk2str( _dip->data, solvAttrType(), (unsigned char *)_dip->kv.str ) );
708             break;
709         }
710       }
711       return CheckSum();
712     }
713
714     ///////////////////////////////////////////////////////////////////
715     // internal stuff below
716     ///////////////////////////////////////////////////////////////////
717
718     LookupAttr::iterator::iterator()
719     : iterator_adaptor_( 0 )
720     {}
721
722     LookupAttr::iterator::iterator( const iterator & rhs )
723     : iterator_adaptor_( 0 )
724     , _dip( rhs._dip )
725     {
726       base_reference() = _dip.get();
727     }
728
729     LookupAttr::iterator::iterator( detail::DIWrap & dip_r )
730     : iterator_adaptor_( 0 )
731     {
732       _dip.swap( dip_r ); // take ownership!
733       base_reference() = _dip.get();
734       increment();
735     }
736
737     LookupAttr::iterator::~iterator()
738     {}
739
740     LookupAttr::iterator & LookupAttr::iterator::operator=( const iterator & rhs )
741     {
742       if ( &rhs != this )
743       {
744         _dip = rhs._dip;
745         base_reference() = _dip.get();
746       }
747       return *this;
748     }
749
750     ///////////////////////////////////////////////////////////////////
751
752     bool LookupAttr::iterator::dip_equal( const detail::CDataiterator & lhs, const detail::CDataiterator & rhs ) const
753     {
754       // Iterator equal is same position in same container.
755       // Here: same attribute in same solvable.
756       return( lhs.solvid == rhs.solvid && lhs.key->name == rhs.key->name );
757     }
758
759     detail::IdType LookupAttr::iterator::dereference() const
760     {
761       return _dip ? ::repodata_globalize_id( _dip->data, _dip->kv.id, 1 )
762                   : detail::noId;
763     }
764
765     void LookupAttr::iterator::increment()
766     {
767       if ( _dip )
768       {
769         if ( ! ::dataiterator_step( _dip.get() ) )
770         {
771           _dip.reset();
772           base_reference() = 0;
773         }
774         else
775         {
776           ::dataiterator_strdup( _dip.get() );
777         }
778       }
779     }
780
781     std::ostream & operator<<( std::ostream & str, const LookupAttr::iterator & obj )
782     {
783       const detail::CDataiterator * dip = obj.get();
784       if ( ! dip )
785         return str << "EndOfQuery";
786
787       if ( obj.inSolvable() )
788         str << obj.inSolvable();
789       else if ( obj.inRepo() )
790         str << obj.inRepo();
791
792       str << '<' << obj.inSolvAttr() << (obj.solvAttrSubEntry() ? ">(*" : ">(")
793           <<  IdString(obj.solvAttrType()) << ") = " << obj.asString();
794       return str;
795     }
796
797     template<> CheckSum LookupAttr::iterator::asType<CheckSum>() const
798     { return asCheckSum(); }
799
800     /////////////////////////////////////////////////////////////////
801   } // namespace sat
802   ///////////////////////////////////////////////////////////////////
803   /////////////////////////////////////////////////////////////////
804 } // namespace zypp
805 ///////////////////////////////////////////////////////////////////
806
807 std::ostream & operator<<( std::ostream & str, const zypp::sat::detail::CDataiterator * obj )
808 {
809   str << "detail::CDataiterator(";
810   if ( ! obj )
811   {
812     str << "NULL";
813   }
814   else
815   {
816     str << "|" << zypp::Repository(obj->repo);
817     str << "|" << zypp::sat::Solvable(obj->solvid);
818     str << "|" << zypp::IdString(obj->key->name);
819     str << "|" << zypp::IdString(obj->key->type);
820     str << "|" << obj->repodataid;
821     str << "|" << obj->repoid;
822   }
823   return str << ")";
824 }
825
826 ///////////////////////////////////////////////////////////////////