#include "zypp/sat/detail/PoolImpl.h"
#include "zypp/sat/Pool.h"
+#include "zypp/ResPool.h"
using std::endl;
///////////////////////////////////////////////////////////////////
namespace
{ /////////////////////////////////////////////////////////////////
+
+ /** backward skip whitespace starting at pos_r */
+ inline std::string::size_type backskipWs( const std::string & str_r, std::string::size_type pos_r )
+ {
+ for ( ; pos_r != std::string::npos; --pos_r )
+ {
+ char ch = str_r[pos_r];
+ if ( ch != ' ' && ch != '\t' )
+ break;
+ }
+ return pos_r;
+ }
+
+ /** backward skip non-whitespace starting at pos_r */
+ inline std::string::size_type backskipNWs( const std::string & str_r, std::string::size_type pos_r )
+ {
+ for ( ; pos_r != std::string::npos; --pos_r )
+ {
+ char ch = str_r[pos_r];
+ if ( ch == ' ' || ch == '\t' )
+ break;
+ }
+ return pos_r;
+ }
+
+ /** Split any 'op edition' from str_r */
+ void splitOpEdition( std::string & str_r, Rel & op_r, Edition & ed_r )
+ {
+ if ( str_r.empty() )
+ return;
+ std::string::size_type ch( str_r.size()-1 );
+
+ // check whether the one but last word is a valid Rel:
+ if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
+ {
+ std::string::size_type ee( ch );
+ if ( (ch = backskipNWs( str_r, ch )) != std::string::npos )
+ {
+ std::string::size_type eb( ch );
+ if ( (ch = backskipWs( str_r, ch )) != std::string::npos )
+ {
+ std::string::size_type oe( ch );
+ ch = backskipNWs( str_r, ch ); // now before 'op'? begin
+ if ( op_r.parseFrom( str_r.substr( ch+1, oe-ch ) ) )
+ {
+ // found a legal 'op'
+ ed_r = Edition( str_r.substr( eb+1, ee-eb ) );
+ if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
+ ch = backskipWs( str_r, ch );
+ str_r.erase( ch+1 );
+ return;
+ }
+ }
+ }
+ }
+ // HERE: Didn't find 'name op edition'
+ // As a convenience we check for an embeded 'op' (not surounded by WS).
+ // But just '[<=>]=?|!=' and not inside '()'.
+ ch = str_r.find_last_of( "<=>)" );
+ if ( ch != std::string::npos && str_r[ch] != ')' )
+ {
+ std::string::size_type oe( ch );
+
+ // do edition first:
+ ch = str_r.find_first_not_of( " \t", oe+1 );
+ if ( ch != std::string::npos )
+ ed_r = Edition( str_r.substr( ch ) );
+
+ // now finish op:
+ ch = oe-1;
+ if ( str_r[oe] != '=' ) // '[<>]'
+ {
+ op_r = ( str_r[oe] == '<' ) ? Rel::LT : Rel::GT;
+ }
+ else
+ { // '?='
+ if ( ch != std::string::npos )
+ {
+ switch ( str_r[ch] )
+ {
+ case '<': --ch; op_r = Rel::LE; break;
+ case '>': --ch; op_r = Rel::GE; break;
+ case '!': --ch; op_r = Rel::NE; break;
+ case '=': --ch; // fall through
+ default: op_r = Rel::EQ; break;
+ }
+ }
+ }
+
+ // finally name:
+ if ( ch != std::string::npos ) // 'op' is not at str_r begin, so skip WS
+ ch = backskipWs( str_r, ch );
+ str_r.erase( ch+1 );
+ return;
+ }
+ // HERE: It's a plain 'name'
+ }
+
/** Build \ref Capability from data. No parsing required.
*/
- sat::detail::IdType relFromStr( ::_Pool * pool_r,
+ sat::detail::IdType relFromStr( sat::detail::CPool * pool_r,
const Arch & arch_r,
const std::string & name_r,
Rel op_r,
const ResKind & kind_r )
{
// First build the name, non-packages prefixed by kind
- sat::detail::IdType nid( sat::detail::noId );
- if ( ! kind_r || kind_r == ResKind::package )
- {
- nid = IdString( name_r ).id();
- }
- else if ( kind_r == ResKind::srcpackage )
+ sat::Solvable::SplitIdent split( kind_r, name_r );
+ sat::detail::IdType nid( split.ident().id() );
+
+ if ( split.kind() == ResKind::srcpackage )
{
// map 'kind srcpackage' to 'arch src', the pseudo architecture
- // satsolver uses.
- nid = IdString( name_r ).id();
- nid = ::rel2id( pool_r, nid, IdString(ARCH_SRC).id(), REL_ARCH, /*create*/true );
+ // libsolv uses.
+ nid = ::pool_rel2id( pool_r, nid, IdString(ARCH_SRC).id(), REL_ARCH, /*create*/true );
}
- else
- {
- nid = IdString( str::form( "%s:%s",
- kind_r.c_str(),
- name_r.c_str() ) ).id();
- }
-
// Extend name by architecture, if provided and not a srcpackage
if ( ! arch_r.empty() && kind_r != ResKind::srcpackage )
{
- nid = ::rel2id( pool_r, nid, arch_r.id(), REL_ARCH, /*create*/true );
+ nid = ::pool_rel2id( pool_r, nid, arch_r.id(), REL_ARCH, /*create*/true );
}
// Extend 'op edition', if provided
if ( op_r != Rel::ANY && ed_r != Edition::noedition )
{
- nid = ::rel2id( pool_r, nid, ed_r.id(), op_r.bits(), /*create*/true );
+ nid = ::pool_rel2id( pool_r, nid, ed_r.id(), op_r.bits(), /*create*/true );
}
return nid;
/** Build \ref Capability from data, just parsing name for '[.arch]' and detect
* 'kind srcpackage' (will be mapped to arch \c src).
*/
- sat::detail::IdType relFromStr( ::_Pool * pool_r,
+ sat::detail::IdType relFromStr( sat::detail::CPool * pool_r,
const std::string & name_r, Rel op_r, const Edition & ed_r,
const ResKind & kind_r )
{
/** Full parse from string, unless Capability::PARSED.
*/
- sat::detail::IdType relFromStr( ::_Pool * pool_r,
+ sat::detail::IdType relFromStr( sat::detail::CPool * pool_r,
+ const Arch & arch_r, // parse from name if empty
const std::string & str_r, const ResKind & kind_r,
Capability::CtorFlag flag_r )
{
- // strval_r has at least two words which could make 'op edition'?
- // improve regex!
- static const str::regex rx( "(.*[^ \t])([ \t]+)([^ \t]+)([ \t]+)([^ \t]+)" );
- static str::smatch what;
-
std::string name( str_r );
Rel op;
Edition ed;
- if ( flag_r == Capability::UNPARSED
- && str_r.find(' ') != std::string::npos
- && str::regex_match( str_r, what, rx ) )
+ if ( flag_r == Capability::UNPARSED )
{
- try
- {
- Rel cop( what[3] );
- Edition ced( what[5] );
- name = what[1];
- op = cop;
- ed = ced;
- }
- catch ( Exception & excpt )
- {
- // So they don't make valid 'op edition'
- ZYPP_CAUGHT( excpt );
- DBG << "Trying named relation for: " << str_r << endl;
- }
+ splitOpEdition( name, op, ed );
}
- //else
- // not a versioned relation
- return relFromStr( pool_r, name, op, ed, kind_r ); // parses for name[.arch]
+ if ( arch_r.empty() )
+ return relFromStr( pool_r, name, op, ed, kind_r ); // parses for name[.arch]
+ // else
+ return relFromStr( pool_r, arch_r, name, op, ed, kind_r );
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
Capability::Capability( const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
- : _id( relFromStr( myPool().getPool(), str_r, prefix_r, flag_r ) )
+ : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
{}
Capability::Capability( const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
- : _id( relFromStr( myPool().getPool(), str_r.c_str(), prefix_r, flag_r ) )
+ : _id( relFromStr( myPool().getPool(), Arch_empty, str_r.c_str(), prefix_r, flag_r ) )
+ {}
+
+ Capability::Capability( const Arch & arch_r, const char * str_r, const ResKind & prefix_r, CtorFlag flag_r )
+ : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
+ {}
+
+ Capability::Capability( const Arch & arch_r, const std::string & str_r, const ResKind & prefix_r, CtorFlag flag_r )
+ : _id( relFromStr( myPool().getPool(), arch_r, str_r.c_str(), prefix_r, flag_r ) )
{}
Capability::Capability( const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
- : _id( relFromStr( myPool().getPool(), str_r, prefix_r, flag_r ) )
+ : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
{}
Capability::Capability( const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
- : _id( relFromStr( myPool().getPool(), str_r, prefix_r, flag_r ) )
+ : _id( relFromStr( myPool().getPool(), Arch_empty, str_r, prefix_r, flag_r ) )
+ {}
+
+ Capability::Capability( const Arch & arch_r, const char * str_r, CtorFlag flag_r, const ResKind & prefix_r )
+ : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
+ {}
+
+ Capability::Capability( const Arch & arch_r, const std::string & str_r, CtorFlag flag_r, const ResKind & prefix_r )
+ : _id( relFromStr( myPool().getPool(), arch_r, str_r, prefix_r, flag_r ) )
{}
///////////////////////////////////////////////////////////////////
: _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, ed_r, prefix_r ) )
{}
+ ///////////////////////////////////////////////////////////////////
+ // Ctor creating a namespace: capability.
+ ///////////////////////////////////////////////////////////////////
+
+ Capability::Capability( ResolverNamespace namespace_r, IdString value_r )
+ : _id( ::pool_rel2id( myPool().getPool(), asIdString(namespace_r).id(), (value_r.empty() ? STRID_NULL : value_r.id() ), REL_NAMESPACE, /*create*/true ) )
+ {}
+
+
const char * Capability::c_str() const
- { return( _id ? ::dep2str( myPool().getPool(), _id ) : "" ); }
+ { return( _id ? ::pool_dep2str( myPool().getPool(), _id ) : "" ); }
CapMatch Capability::_doMatch( sat::detail::IdType lhs, sat::detail::IdType rhs )
{
static str::smatch what;
static const str::regex filenameRegex(
"/(s?bin|lib(64)?|etc)/|^/usr/(games/|share/(dict/words|magic\\.mime)$)|^/opt/gnome/games/",
- str::regex::optimize|str::regex::nosubs );
+ str::regex::nosubs );
return str::regex_match( name_r, what, filenameRegex );
}
+ Capability Capability::guessPackageSpec( const std::string & str_r, bool & rewrote_r )
+ {
+ Capability cap( str_r );
+ CapDetail detail( cap.detail() );
+
+ // str_r might be the form "libzypp-1.2.3-4.5(.arch)'
+ // correctly parsed as name capability by the ctor.
+ // TODO: Think about allowing glob char in name - for now don't process
+ if ( detail.isNamed() && !::strpbrk( detail.name().c_str(), "*?[{" )
+ && ::strrchr( detail.name().c_str(), '-' ) && sat::WhatProvides( cap ).empty() )
+ {
+ Arch origArch( detail.arch() ); // to support a trailing .arch
+
+ std::string guess( detail.name().asString() );
+ std::string::size_type pos( guess.rfind( '-' ) );
+ guess[pos] = '=';
+
+ Capability guesscap( origArch, guess );
+ detail = guesscap.detail();
+
+ ResPool pool( ResPool::instance() );
+ // require name part matching a pool items name (not just provides!)
+ if ( pool.byIdentBegin( detail.name() ) != pool.byIdentEnd( detail.name() ) )
+ {
+ rewrote_r = true;
+ return guesscap;
+ }
+
+ // try the one but last '-'
+ if ( pos )
+ {
+ guess[pos] = '-';
+ if ( (pos = guess.rfind( '-', pos-1 )) != std::string::npos )
+ {
+ guess[pos] = '=';
+
+ guesscap = Capability( origArch, guess );
+ detail = guesscap.detail();
+
+ // require name part matching a pool items name (not just provides!)
+ if ( pool.byIdentBegin( detail.name() ) != pool.byIdentEnd( detail.name() ) )
+ {
+ rewrote_r = true;
+ return guesscap;
+ }
+ }
+ }
+ }
+
+ rewrote_r = false;
+ return cap;
+ }
+
+ Capability Capability::guessPackageSpec( const std::string & str_r )
+ {
+ bool dummy;
+ return guessPackageSpec( str_r, dummy );
+ }
+
/******************************************************************
**
** FUNCTION NAME : operator<<
_kind = EXPRESSION;
return;
}
- // map back satsolvers pseudo arch 'src' to kind srcpackage
+ // map back libsolvs pseudo arch 'src' to kind srcpackage
if ( _archIfSimple == ARCH_SRC )
{
_lhs = IdString( (ResKind::srcpackage.asString() + ":" + IdString(_lhs).c_str()).c_str() ).id();