Imported Upstream version 15.0.0
[platform/upstream/libzypp.git] / zypp / Capability.cc
index 5cbbdb0..dc75eaa 100644 (file)
 #include "zypp/base/Gettext.h"
 #include "zypp/base/Exception.h"
 
+#include "zypp/Arch.h"
 #include "zypp/Rel.h"
 #include "zypp/Edition.h"
 #include "zypp/Capability.h"
 
 #include "zypp/sat/detail/PoolImpl.h"
 #include "zypp/sat/Pool.h"
+#include "zypp/ResPool.h"
 
 using std::endl;
 
@@ -33,157 +35,324 @@ namespace zypp
   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,
-                                    const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & kind_r )
+                                    const Arch & arch_r,
+                                    const std::string & name_r,
+                                    Rel op_r,
+                                    const Edition & ed_r,
+                                    const ResKind & kind_r )
     {
-      sat::detail::IdType nid( sat::detail::noId );
-      if ( ! kind_r || kind_r == ResKind::package )
+      // First build the name, non-packages prefixed by kind
+      sat::Solvable::SplitIdent split( kind_r, name_r );
+      sat::detail::IdType nid( split.ident().id() );
+
+      if ( split.kind() == ResKind::srcpackage )
       {
-        nid = IdString( name_r ).id();
+        // map 'kind srcpackage' to 'arch src', the pseudo architecture
+        // libsolv uses.
+        nid = ::pool_rel2id( pool_r, nid, IdString(ARCH_SRC).id(), REL_ARCH, /*create*/true );
       }
-      else
+
+      // Extend name by architecture, if provided and not a srcpackage
+      if ( ! arch_r.empty() && kind_r != ResKind::srcpackage )
       {
-        // non-packages prefixed by kind
-        nid = IdString( str::form( "%s:%s",
-                        kind_r.c_str(),
-                                     name_r.c_str() ) ).id();
+        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.idStr().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,
-                                      const std::string & str_r, const ResKind & kind_r, Capability::CtorFlag flag_r )
+                                    const std::string & name_r, Rel op_r, const Edition & ed_r,
+                                    const ResKind & kind_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;
+      static const Arch srcArch( IdString(ARCH_SRC).asString() );
+      static const std::string srcKindPrefix( ResKind::srcpackage.asString() + ':' );
 
-      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 ) )
+      // check for an embedded 'srcpackage:foo' to be mapped to 'foo' and 'ResKind::srcpackage'.
+      if ( kind_r.empty() && str::hasPrefix( name_r, srcKindPrefix ) )
       {
-        try
-        {
-          Rel     cop( what[3] );
-          Edition ced( what[5] );
-          name = what[1];
-          op = cop;
-          ed = ced;
-        }
-        catch ( Exception & excpt )
+        return relFromStr( pool_r, Arch_empty, name_r.substr( srcKindPrefix.size() ), op_r, ed_r, ResKind::srcpackage );
+      }
+
+      Arch arch( Arch_empty );
+      std::string name( name_r );
+
+      std::string::size_type asep( name_r.rfind( "." ) );
+      if ( asep != std::string::npos )
+      {
+        Arch ext( name_r.substr( asep+1 ) );
+        if ( ext.isBuiltIn() || ext == srcArch )
         {
-          // So they don't make valid 'op edition'
-          ZYPP_CAUGHT( excpt );
-          DBG << "Trying named relation for: " << str_r << endl;
+          arch = ext;
+          name.erase( asep );
         }
       }
-      //else
-      // not a versioned relation
 
-      return relFromStr( pool_r, name, op, ed, kind_r );
+      return relFromStr( pool_r, arch, name, op_r, ed_r, kind_r );
     }
 
-    // By now restrict matching to plain 'name [op edition]'
-    struct CapHelp : protected sat::detail::PoolMember
+    /** Full parse from string, unless Capability::PARSED.
+    */
+    sat::detail::IdType relFromStr( ::_Pool * pool_r,
+                                    const Arch & arch_r, // parse from name if empty
+                                    const std::string & str_r, const ResKind & kind_r,
+                                    Capability::CtorFlag flag_r )
     {
-      CapHelp( sat::detail::IdType id_r )
-      : _name( id_r )
+      std::string name( str_r );
+      Rel         op;
+      Edition     ed;
+      if ( flag_r == Capability::UNPARSED )
       {
-        if ( ISRELDEP(id_r) )
-        {
-          ::Reldep * rd = GETRELDEP( myPool().getPool(), id_r );
-          if ( ! Rel::isRel( rd->flags ) || ISRELDEP(rd->name) || ISRELDEP(rd->evr) )
-            _op = Rel::NONE;
-          else
-          {
-            _name = IdString( rd->name );
-            _op   = Rel( rd->flags );
-            _ed   = Edition( rd->evr );
-          }
-        }
+        splitOpEdition( name, op, ed );
       }
 
-      IdString _name;
-      Rel      _op;
-      Edition  _ed;
-    };
+      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 );
+    }
 
     /////////////////////////////////////////////////////////////////
   } // namespace
   ///////////////////////////////////////////////////////////////////
 
   const Capability Capability::Null( STRID_NULL );
+  const Capability Capability::Empty( STRID_EMPTY );
 
   /////////////////////////////////////////////////////////////////
 
   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 ) )
   {}
 
+  ///////////////////////////////////////////////////////////////////
+  // Ctor from <name[.arch] op edition>.
+  ///////////////////////////////////////////////////////////////////
 
   Capability::Capability( const std::string & name_r, const std::string & op_r, const std::string & ed_r, const ResKind & prefix_r )
   : _id( relFromStr( myPool().getPool(), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
   {}
-
   Capability::Capability( const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
   : _id( relFromStr( myPool().getPool(), name_r, op_r, Edition(ed_r), prefix_r ) )
   {}
-
   Capability::Capability( const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
   : _id( relFromStr( myPool().getPool(), name_r, op_r, ed_r, prefix_r ) )
   {}
 
-  const char * Capability::c_str() const
-  { return ::dep2str( myPool().getPool(), _id ); }
+  ///////////////////////////////////////////////////////////////////
+  // Ctor from <arch name op edition>.
+  ///////////////////////////////////////////////////////////////////
 
-  std::string Capability::string() const
-  { return ::dep2str( myPool().getPool(), _id ); }
+  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 )
+  : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
+  {}
+  Capability::Capability( const std::string & arch_r, const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
+  : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, op_r, Edition(ed_r), prefix_r ) )
+  {}
+  Capability::Capability( const std::string & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
+  : _id( relFromStr( myPool().getPool(), Arch(arch_r), name_r, op_r, ed_r, prefix_r ) )
+  {}
+  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 )
+  : _id( relFromStr( myPool().getPool(), arch_r, name_r, Rel(op_r), Edition(ed_r), prefix_r ) )
+  {}
+  Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const std::string & ed_r, const ResKind & prefix_r )
+  : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, Edition(ed_r), prefix_r ) )
+  {}
+  Capability::Capability( const Arch & arch_r, const std::string & name_r, Rel op_r, const Edition & ed_r, const ResKind & prefix_r )
+  : _id( relFromStr( myPool().getPool(), arch_r, name_r, op_r, ed_r, prefix_r ) )
+  {}
+
+  const char * Capability::c_str() const
+  { return( _id ? ::pool_dep2str( myPool().getPool(), _id ) : "" ); }
 
-  bool Capability::_doMatch( sat::detail::IdType lhs,  sat::detail::IdType rhs )
+  CapMatch Capability::_doMatch( sat::detail::IdType lhs,  sat::detail::IdType rhs )
   {
 #warning MIGRATE TO SAT
 #warning TESTCASE
     if ( lhs == rhs )
-      return true;
+      return CapMatch::yes;
 
-    CapHelp l( lhs );
-    if ( l._op == Rel::NONE )
-      return false;
+    CapDetail l( lhs );
+    CapDetail r( rhs );
 
-    CapHelp r( rhs );
-    if ( r._op == Rel::NONE )
-      return false;
-
-    if ( l._name != r._name )
-      return false;
-
-    if ( l._op == Rel::ANY || r._op == Rel::ANY )
-      return true;
+    switch ( l.kind() )
+    {
+      case CapDetail::NOCAP:
+        return( r.kind() == CapDetail::NOCAP ); // NOCAP matches NOCAP only
+        break;
+      case CapDetail::EXPRESSION:
+        return CapMatch::irrelevant;
+        break;
+      case CapDetail::NAMED:
+      case CapDetail::VERSIONED:
+        break;
+    }
 
-    return overlaps( Edition::MatchRange( l._op, l._ed ),
-                     Edition::MatchRange( r._op, r._ed ) );
+    switch ( r.kind() )
+    {
+      case CapDetail::NOCAP:
+        return CapMatch::no; // match case handled above
+        break;
+      case CapDetail::EXPRESSION:
+        return CapMatch::irrelevant;
+        break;
+      case CapDetail::NAMED:
+      case CapDetail::VERSIONED:
+        break;
+    }
+    // comparing two simple caps:
+    if ( l.name() != r.name() )
+      return CapMatch::no;
+
+    // if both are arch restricted they must match
+    if ( l.arch() != r.arch()
+         && ! ( l.arch().empty() || r.arch().empty() ) )
+      return CapMatch::no;
+
+    // isNamed matches ANY edition:
+    if ( l.isNamed() || r.isNamed() )
+      return CapMatch::yes;
+
+    // both are versioned:
+    return overlaps( Edition::MatchRange( l.op(), l.ed() ),
+                     Edition::MatchRange( r.op(), r.ed() ) );
   }
 
   bool Capability::isInterestingFileSpec( const char * name_r )
@@ -191,11 +360,68 @@ namespace zypp
     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.
+    if ( detail.isNamed() && ::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<<
@@ -203,7 +429,139 @@ namespace zypp
   */
   std::ostream & operator<<( std::ostream & str, const Capability & obj )
   {
-    return str << obj.c_str();
+    return str << obj.detail();
+  }
+
+  std::ostream & dumpOn( std::ostream & str, const Capability & obj )
+  {
+    return str << obj.detail();
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //   CLASS NAME : CapDetail
+  //
+  ///////////////////////////////////////////////////////////////////
+
+  void CapDetail::_init()
+  {
+    // : _kind( NOCAP ), _lhs( id_r ), _rhs( 0 ), _flag( 0 ), _archIfSimple( 0 )
+
+    if ( _lhs == sat::detail::emptyId || _lhs == sat::detail::noId )
+      return; // NOCAP
+
+    if ( ! ISRELDEP(_lhs) )
+    {
+      // this is name without arch!
+      _kind = NAMED;
+      return;
+    }
+
+    ::Reldep * rd = GETRELDEP( myPool().getPool(), _lhs );
+    _lhs  = rd->name;
+    _rhs  = rd->evr;
+    _flag = rd->flags;
+
+    if ( Rel::isRel( _flag ) )
+    {
+      _kind = VERSIONED;
+      // Check for name.arch...
+      if ( ! ISRELDEP(_lhs) )
+        return; // this is name without arch!
+      rd = GETRELDEP( myPool().getPool(), _lhs );
+      if ( rd->flags != CAP_ARCH )
+        return; // this is not name.arch
+      // This is name.arch:
+      _lhs = rd->name;
+      _archIfSimple = rd->evr;
+    }
+    else if ( rd->flags == CAP_ARCH )
+    {
+      _kind = NAMED;
+      // This is name.arch:
+      _lhs = rd->name;
+      _archIfSimple = rd->evr;
+    }
+    else
+    {
+      _kind = EXPRESSION;
+      return;
+    }
+    // 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();
+      _archIfSimple = 0;
+    }
+  }
+
+  /******************************************************************
+  **
+  **   FUNCTION NAME : operator<<
+  **   FUNCTION TYPE : std::ostream &
+  */
+  std::ostream & operator<<( std::ostream & str, const CapDetail & obj )
+  {
+    static const char archsep = '.';
+    switch ( obj.kind() )
+    {
+      case CapDetail::NOCAP:
+        return str << "<NoCap>";
+        break;
+      case CapDetail::NAMED:
+        str << obj.name();
+        if ( obj.hasArch() )
+          str << archsep << obj.arch();
+        return str;
+        break;
+      case CapDetail::VERSIONED:
+        str << obj.name();
+        if ( obj.hasArch() )
+          str << archsep << obj.arch();
+        return str << " " << obj.op() << " " << obj.ed();
+        break;
+      case CapDetail::EXPRESSION:
+        switch ( obj.capRel() )
+        {
+          case CapDetail::REL_NONE:
+          case CapDetail::CAP_AND:
+          case CapDetail::CAP_OR:
+          case CapDetail::CAP_WITH:
+          case CapDetail::CAP_ARCH:
+            return str << obj.lhs().detail() << " " << obj.capRel() << " " << obj.rhs().detail();
+            break;
+          case CapDetail::CAP_NAMESPACE:
+            return str << obj.lhs().detail() << "(" << obj.rhs().detail() << ")";
+        }
+        break;
+    }
+    return str <<  "<UnknownCap>";
+  }
+
+  std::ostream & operator<<( std::ostream & str, CapDetail::Kind obj )
+  {
+    switch ( obj )
+    {
+      case CapDetail::NOCAP:      return str << "NoCap"; break;
+      case CapDetail::NAMED:      return str << "NamedCap"; break;
+      case CapDetail::VERSIONED:  return str << "VersionedCap"; break;
+      case CapDetail::EXPRESSION: return str << "CapExpression"; break;
+    }
+    return str << "UnknownCap";
+  }
+
+  std::ostream & operator<<( std::ostream & str, CapDetail::CapRel obj )
+  {
+    switch ( obj )
+    {
+      case CapDetail::REL_NONE:      return str << "NoCapRel"; break;
+      case CapDetail::CAP_AND:       return str << "&"; break; // AND
+      case CapDetail::CAP_OR:        return str << "|"; break; // OR
+      case CapDetail::CAP_WITH:      return str << "+"; break; // WITH
+      case CapDetail::CAP_NAMESPACE: return str << "NAMESPACE"; break;
+      case CapDetail::CAP_ARCH:      return str << "ARCH"; break;
+   }
+    return str << "UnknownCapRel";
   }
 
   /////////////////////////////////////////////////////////////////