1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/sat/Capability.cc
13 #include "zypp/base/Logger.h"
15 #include "zypp/base/String.h"
16 #include "zypp/base/Regex.h"
17 #include "zypp/base/Gettext.h"
18 #include "zypp/base/Exception.h"
20 #include "zypp/Arch.h"
22 #include "zypp/Edition.h"
23 #include "zypp/Capability.h"
25 #include "zypp/sat/detail/PoolImpl.h"
26 #include "zypp/sat/Pool.h"
27 #include "zypp/ResPool.h"
31 ///////////////////////////////////////////////////////////////////
33 { /////////////////////////////////////////////////////////////////
34 ///////////////////////////////////////////////////////////////////
36 { /////////////////////////////////////////////////////////////////
38 /** backward skip whitespace starting at pos_r */
39 inline std::string::size_type backskipWs( const std::string & str_r, std::string::size_type pos_r )
41 for ( ; pos_r != std::string::npos; --pos_r )
43 char ch = str_r[pos_r];
44 if ( ch != ' ' && ch != '\t' )
50 /** backward skip non-whitespace starting at pos_r */
51 inline std::string::size_type backskipNWs( const std::string & str_r, std::string::size_type pos_r )
53 for ( ; pos_r != std::string::npos; --pos_r )
55 char ch = str_r[pos_r];
56 if ( ch == ' ' || ch == '\t' )
62 /** Split any 'op edition' from str_r */
63 void splitOpEdition( std::string & str_r, Rel & op_r, Edition & ed_r )
67 std::string::size_type ch( str_r.size()-1 );
69 // check whether the one but last word is a valid Rel:
70 if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
72 std::string::size_type ee( ch );
73 if ( (ch = backskipNWs( str_r, ch )) != std::string::npos )
75 std::string::size_type eb( ch );
76 if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
78 std::string::size_type oe( ch );
79 ch = backskipNWs( str_r, ch ); // now before 'op'? begin
80 if ( op_r.parseFrom( str_r.substr( ch+1, oe-ch ) ) )
83 ed_r = Edition( str_r.substr( eb+1, ee-eb ) );
84 if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
85 ch = backskipWs( str_r, ch );
92 // HERE: Didn't find 'name op edition'
93 // As a convenience we check for an embeded 'op' (not surounded by WS).
94 // But just '[<=>]=?|!=' and not inside '()'.
95 ch = str_r.find_last_of( "<=>)" );
96 if ( ch != std::string::npos && str_r[ch] != ')' )
98 std::string::size_type oe( ch );
101 ch = str_r.find_first_not_of( " \t", oe+1 );
102 if ( ch != std::string::npos )
103 ed_r = Edition( str_r.substr( ch ) );
107 if ( str_r[oe] != '=' ) // '[<>]'
109 op_r = ( str_r[oe] == '<' ) ? Rel::LT : Rel::GT;
113 if ( ch != std::string::npos )
117 case '<': --ch; op_r = Rel::LE; break;
118 case '>': --ch; op_r = Rel::GE; break;
119 case '!': --ch; op_r = Rel::NE; break;
120 case '=': --ch; // fall through
121 default: op_r = Rel::EQ; break;
127 if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
128 ch = backskipWs( str_r, ch );
132 // HERE: It's a plain 'name'
135 /** Build \ref Capability from data. No parsing required.
137 sat::detail::IdType relFromStr( ::_Pool * pool_r,
139 const std::string & name_r,
141 const Edition & ed_r,
142 const ResKind & kind_r )
144 // First build the name, non-packages prefixed by kind
145 sat::Solvable::SplitIdent split( kind_r, name_r );
146 sat::detail::IdType nid( split.ident().id() );
148 if ( split.kind() == ResKind::srcpackage )
150 // map 'kind srcpackage' to 'arch src', the pseudo architecture
152 nid = ::pool_rel2id( pool_r, nid, IdString(ARCH_SRC).id(), REL_ARCH, /*create*/true );
155 // Extend name by architecture, if provided and not a srcpackage
156 if ( ! arch_r.empty() && kind_r != ResKind::srcpackage )
158 nid = ::pool_rel2id( pool_r, nid, arch_r.id(), REL_ARCH, /*create*/true );
161 // Extend 'op edition', if provided
162 if ( op_r != Rel::ANY && ed_r != Edition::noedition )
164 nid = ::pool_rel2id( pool_r, nid, ed_r.id(), op_r.bits(), /*create*/true );
170 /** Build \ref Capability from data, just parsing name for '[.arch]' and detect
171 * 'kind srcpackage' (will be mapped to arch \c src).
173 sat::detail::IdType relFromStr( ::_Pool * pool_r,
174 const std::string & name_r, Rel op_r, const Edition & ed_r,
175 const ResKind & kind_r )
177 static const Arch srcArch( IdString(ARCH_SRC).asString() );
178 static const std::string srcKindPrefix( ResKind::srcpackage.asString() + ':' );
180 // check for an embedded 'srcpackage:foo' to be mapped to 'foo' and 'ResKind::srcpackage'.
181 if ( kind_r.empty() && str::hasPrefix( name_r, srcKindPrefix ) )
183 return relFromStr( pool_r, Arch_empty, name_r.substr( srcKindPrefix.size() ), op_r, ed_r, ResKind::srcpackage );
186 Arch arch( Arch_empty );
187 std::string name( name_r );
189 std::string::size_type asep( name_r.rfind( "." ) );
190 if ( asep != std::string::npos )
192 Arch ext( name_r.substr( asep+1 ) );
193 if ( ext.isBuiltIn() || ext == srcArch )
200 return relFromStr( pool_r, arch, name, op_r, ed_r, kind_r );
203 /** Full parse from string, unless Capability::PARSED.
205 sat::detail::IdType relFromStr( ::_Pool * pool_r,
206 const Arch & arch_r, // parse from name if empty
207 const std::string & str_r, const ResKind & kind_r,
208 Capability::CtorFlag flag_r )
210 std::string name( str_r );
213 if ( flag_r == Capability::UNPARSED )
215 splitOpEdition( name, op, ed );
218 if ( arch_r.empty() )
219 return relFromStr( pool_r, name, op, ed, kind_r ); // parses for name[.arch]
221 return relFromStr( pool_r, arch_r, name, op, ed, kind_r );
224 /////////////////////////////////////////////////////////////////
226 ///////////////////////////////////////////////////////////////////
228 const Capability Capability::Null( STRID_NULL );
229 const Capability Capability::Empty( STRID_EMPTY );
231 /////////////////////////////////////////////////////////////////
233 Capability::Capability( const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
234 : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
237 Capability::Capability( const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
238 : _id( relFromStr( myPool().getPool(), Arch_empty, str_r.c_str(), prefix_r, flag_r ) )
241 Capability::Capability( const Arch & arch_r, const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
242 : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
245 Capability::Capability( const Arch & arch_r, const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
246 : _id( relFromStr( myPool().getPool(), arch_r, str_r.c_str(), prefix_r, flag_r ) )
249 Capability::Capability( const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
250 : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
253 Capability::Capability( const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
254 : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
257 Capability::Capability( const Arch & arch_r, const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
258 : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
261 Capability::Capability( const Arch & arch_r, const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
262 : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
265 ///////////////////////////////////////////////////////////////////
266 // Ctor from <name[.arch] op edition>.
267 ///////////////////////////////////////////////////////////////////
269 Capability::Capability( const std::string & name_r, const std::string & op_r, const std::string & ed_r, const ResKind & prefix_r )
270 : _id( relFromStr( myPool().getPool(), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
272 Capability::Capability( const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
273 : _id( relFromStr( myPool().getPool(), name_r, op_r, Edition(ed_r), prefix_r ) )
275 Capability::Capability( const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
276 : _id( relFromStr( myPool().getPool(), name_r, op_r, ed_r, prefix_r ) )
279 ///////////////////////////////////////////////////////////////////
280 // Ctor from <arch name op edition>.
281 ///////////////////////////////////////////////////////////////////
283 Capability::Capability( const std::string & arch_r, const std::string & name_r, const std::string & op_r, const std::string & ed_r, const ResKind & prefix_r )
284 : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
286 Capability::Capability( const std::string & arch_r, const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
287 : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, op_r, Edition(ed_r), prefix_r ) )
289 Capability::Capability( const std::string & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
290 : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, op_r, ed_r, prefix_r ) )
292 Capability::Capability( const Arch & arch_r, const std::string & name_r, const std::string & op_r, const std::string & ed_r, const ResKind & prefix_r )
293 : _id( relFromStr( myPool().getPool(), arch_r, name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
295 Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
296 : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, Edition(ed_r), prefix_r ) )
298 Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
299 : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, ed_r, prefix_r ) )
302 const char * Capability::c_str() const
303 { return( _id ? ::pool_dep2str( myPool().getPool(), _id ) : "" ); }
305 CapMatch Capability::_doMatch( sat::detail::IdType lhs, sat::detail::IdType rhs )
307 #warning MIGRATE TO SAT
310 return CapMatch::yes;
317 case CapDetail::NOCAP:
318 return( r.kind() == CapDetail::NOCAP ); // NOCAP matches NOCAP only
320 case CapDetail::EXPRESSION:
321 return CapMatch::irrelevant;
323 case CapDetail::NAMED:
324 case CapDetail::VERSIONED:
330 case CapDetail::NOCAP:
331 return CapMatch::no; // match case handled above
333 case CapDetail::EXPRESSION:
334 return CapMatch::irrelevant;
336 case CapDetail::NAMED:
337 case CapDetail::VERSIONED:
340 // comparing two simple caps:
341 if ( l.name() != r.name() )
344 // if both are arch restricted they must match
345 if ( l.arch() != r.arch()
346 && ! ( l.arch().empty() || r.arch().empty() ) )
349 // isNamed matches ANY edition:
350 if ( l.isNamed() || r.isNamed() )
351 return CapMatch::yes;
353 // both are versioned:
354 return overlaps( Edition::MatchRange( l.op(), l.ed() ),
355 Edition::MatchRange( r.op(), r.ed() ) );
358 bool Capability::isInterestingFileSpec( const char * name_r )
360 static str::smatch what;
361 static const str::regex filenameRegex(
362 "/(s?bin|lib(64)?|etc)/|^/usr/(games/|share/(dict/words|magic\\.mime)$)|^/opt/gnome/games/",
363 str::regex::nosubs );
365 return str::regex_match( name_r, what, filenameRegex );
368 Capability Capability::guessPackageSpec( const std::string & str_r, bool & rewrote_r )
370 Capability cap( str_r );
371 CapDetail detail( cap.detail() );
373 // str_r might be the form "libzypp-1.2.3-4.5(.arch)'
374 // correctly parsed as name capability by the ctor.
375 // TODO: Think about allowing glob char in name - for now don't process
376 if ( detail.isNamed() && !::strpbrk( detail.name().c_str(), "*?[{" )
377 && ::strrchr( detail.name().c_str(), '-' ) && sat::WhatProvides( cap ).empty() )
379 Arch origArch( detail.arch() ); // to support a trailing .arch
381 std::string guess( detail.name().asString() );
382 std::string::size_type pos( guess.rfind( '-' ) );
385 Capability guesscap( origArch, guess );
386 detail = guesscap.detail();
388 ResPool pool( ResPool::instance() );
389 // require name part matching a pool items name (not just provides!)
390 if ( pool.byIdentBegin( detail.name() ) != pool.byIdentEnd( detail.name() ) )
396 // try the one but last '-'
400 if ( (pos = guess.rfind( '-', pos-1 )) != std::string::npos )
404 guesscap = Capability( origArch, guess );
405 detail = guesscap.detail();
407 // require name part matching a pool items name (not just provides!)
408 if ( pool.byIdentBegin( detail.name() ) != pool.byIdentEnd( detail.name() ) )
421 Capability Capability::guessPackageSpec( const std::string & str_r )
424 return guessPackageSpec( str_r, dummy );
427 /******************************************************************
429 ** FUNCTION NAME : operator<<
430 ** FUNCTION TYPE : std::ostream &
432 std::ostream & operator<<( std::ostream & str, const Capability & obj )
434 return str << obj.detail();
437 std::ostream & dumpOn( std::ostream & str, const Capability & obj )
439 return str << obj.detail();
442 ///////////////////////////////////////////////////////////////////
444 // CLASS NAME : CapDetail
446 ///////////////////////////////////////////////////////////////////
448 void CapDetail::_init()
450 // : _kind( NOCAP ), _lhs( id_r ), _rhs( 0 ), _flag( 0 ), _archIfSimple( 0 )
452 if ( _lhs == sat::detail::emptyId || _lhs == sat::detail::noId )
455 if ( ! ISRELDEP(_lhs) )
457 // this is name without arch!
462 ::Reldep * rd = GETRELDEP( myPool().getPool(), _lhs );
467 if ( Rel::isRel( _flag ) )
470 // Check for name.arch...
471 if ( ! ISRELDEP(_lhs) )
472 return; // this is name without arch!
473 rd = GETRELDEP( myPool().getPool(), _lhs );
474 if ( rd->flags != CAP_ARCH )
475 return; // this is not name.arch
476 // This is name.arch:
478 _archIfSimple = rd->evr;
480 else if ( rd->flags == CAP_ARCH )
483 // This is name.arch:
485 _archIfSimple = rd->evr;
492 // map back libsolvs pseudo arch 'src' to kind srcpackage
493 if ( _archIfSimple == ARCH_SRC )
495 _lhs = IdString( (ResKind::srcpackage.asString() + ":" + IdString(_lhs).c_str()).c_str() ).id();
500 /******************************************************************
502 ** FUNCTION NAME : operator<<
503 ** FUNCTION TYPE : std::ostream &
505 std::ostream & operator<<( std::ostream & str, const CapDetail & obj )
507 static const char archsep = '.';
508 switch ( obj.kind() )
510 case CapDetail::NOCAP:
511 return str << "<NoCap>";
513 case CapDetail::NAMED:
516 str << archsep << obj.arch();
519 case CapDetail::VERSIONED:
522 str << archsep << obj.arch();
523 return str << " " << obj.op() << " " << obj.ed();
525 case CapDetail::EXPRESSION:
526 switch ( obj.capRel() )
528 case CapDetail::REL_NONE:
529 case CapDetail::CAP_AND:
530 case CapDetail::CAP_OR:
531 case CapDetail::CAP_WITH:
532 case CapDetail::CAP_ARCH:
533 return str << obj.lhs().detail() << " " << obj.capRel() << " " << obj.rhs().detail();
535 case CapDetail::CAP_NAMESPACE:
536 return str << obj.lhs().detail() << "(" << obj.rhs().detail() << ")";
540 return str << "<UnknownCap>";
543 std::ostream & operator<<( std::ostream & str, CapDetail::Kind obj )
547 case CapDetail::NOCAP: return str << "NoCap"; break;
548 case CapDetail::NAMED: return str << "NamedCap"; break;
549 case CapDetail::VERSIONED: return str << "VersionedCap"; break;
550 case CapDetail::EXPRESSION: return str << "CapExpression"; break;
552 return str << "UnknownCap";
555 std::ostream & operator<<( std::ostream & str, CapDetail::CapRel obj )
559 case CapDetail::REL_NONE: return str << "NoCapRel"; break;
560 case CapDetail::CAP_AND: return str << "&"; break; // AND
561 case CapDetail::CAP_OR: return str << "|"; break; // OR
562 case CapDetail::CAP_WITH: return str << "+"; break; // WITH
563 case CapDetail::CAP_NAMESPACE: return str << "NAMESPACE"; break;
564 case CapDetail::CAP_ARCH: return str << "ARCH"; break;
566 return str << "UnknownCapRel";
569 /////////////////////////////////////////////////////////////////
571 ///////////////////////////////////////////////////////////////////