fixup Fix to build with libxml 2.12.x (fixes #505)
[platform/upstream/libzypp.git] / zypp / Locale.cc
index e9927bf..8949483 100644 (file)
 #include <iostream>
 #include <map>
 
-#include "zypp/Locale.h"
+#include <zypp/Locale.h>
+#include <zypp/ZConfig.h>
 
 using std::endl;
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
+  /** Wrap static codemap data. */
+  struct CodeMaps
+  {
+   /** Return IdString without trailing garbage. */
+    static IdString withoutTrash( IdString code_r )
+    {
+       boost::string_ref::size_type sep = trashStart( code_r );
+       if ( sep != boost::string_ref::npos )
+        code_r = IdString( code_r.c_str(), sep );
+       return code_r;
+    }
 
-  typedef std::map<std::string, std::string> OtherDefaultLanguage;
-  static OtherDefaultLanguage otherDefaultLanguage;
+    /** Return IdString without trailing garbage. */
+    static IdString withoutTrash( const std::string & code_r )
+    { return withoutTrash( boost::string_ref(code_r) ); }
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   CLASS NAME : Locale::Impl
-  //
-  /** Locale implementation. */
-  struct Locale::Impl
-  {
-    Impl()
-    {}
+    /** Return IdString without trailing garbage. */
+    static IdString withoutTrash( const char * code_r )
+    { return( code_r ? withoutTrash( boost::string_ref(code_r) ) : IdString::Null ); }
 
-    Impl( const std::string & code_r )
+    /** Return IdString from language/country codes. */
+    static IdString combineLC( LanguageCode language_r, CountryCode country_r )
     {
-      std::string t;
-      std::string::size_type sep = code_r.find_first_of( "@." );
-      if ( sep == std::string::npos ) {
-        t = code_r;
-      } else {
-        t = code_r.substr( 0, sep );
+      IdString ret;
+      if ( language_r )
+      {
+       if ( country_r )
+         ret = IdString( std::string(language_r) + "_" + country_r.c_str() );
+       else
+         ret = IdString(language_r);
       }
-
-      sep = t.find( '_' );
-      if ( sep == std::string::npos ) {
-        _language = LanguageCode( t );
-      } else {
-        _language = LanguageCode( t.substr( 0, sep ) );
-        _country = CountryCode( t.substr( sep+1 ) );
+      else
+      {
+       if ( country_r )
+         ret = IdString( "_" + std::string(country_r) );
+       else if ( ! ( IdString(language_r) || IdString(country_r) ) )
+         ret = IdString::Null;
+       // else IdString::Empty
       }
+      return ret;
     }
 
-    Impl( const LanguageCode & language_r,
-          const CountryCode & country_r )
-    : _language( language_r )
-    , _country( country_r )
-    {}
+    /** The singleton */
+    static CodeMaps & instance()
+    {
+      static CodeMaps _instance;
+      return _instance;
+    }
 
-    const LanguageCode & language() const
-    { return _language; }
+    LanguageCode language( IdString index_r )
+    { return getIndex( index_r )._l; }
 
-    const CountryCode & country() const
-    { return _country; }
+    CountryCode country( IdString index_r )
+    { return  getIndex( index_r )._c; }
 
-    std::string code() const
+    std::string name( IdString index_r )
     {
-      std::string ret( _language.code() );
-      if ( _country.hasCode() )
-        ret += "_" + _country.code();
+      const LC & lc( getIndex( index_r ) );
+      std::string ret( lc._l.name() );
+      if ( lc._c )
+      {
+       ret += " (";
+       ret += lc._c.name();
+       ret += ")";
+      }
       return ret;
     }
 
-    std::string name() const
+    Locale fallback( IdString index_r )
     {
-      std::string ret( _language.name() );
-      if ( _country.hasCode() )
-        ret += " (" + _country.name() + ")";
+      static const IdString special( "pt_BR" );
+      Locale ret;
+      if ( index_r == special )        // "pt_BR"->"en" - by now the only fallback exception
+       ret = Locale::enCode;
+      else
+      {
+       const LC & lc( getIndex( index_r ) );
+       if ( lc._c )
+         ret = lc._l;
+       else if ( lc._l && lc._l != LanguageCode::enCode )
+         ret = Locale::enCode;
+      }
       return ret;
     }
 
-    Locale fallback() const
+  private:
+    static IdString withoutTrash( boost::string_ref code_r )
     {
-      if (otherDefaultLanguage.size() == 0) {
-         // initial inserting map
-         otherDefaultLanguage["pt_BR"] = "en";
-      }
-
-      if (otherDefaultLanguage.find(code()) != otherDefaultLanguage.end())
-         return LanguageCode(otherDefaultLanguage[code()]);
-
-      if ( _country.hasCode() )
-        return _language;
+      boost::string_ref::size_type sep = trashStart( code_r );
+      if ( sep != boost::string_ref::npos )
+       code_r = code_r.substr( 0, sep );
+      return IdString( code_r );
+    }
 
-      if ( _language.hasCode() && _language != LanguageCode("en") )
-        return LanguageCode("en");
+    static boost::string_ref::size_type trashStart( boost::string_ref code_r )
+    { return code_r.find_first_of( "@." ); }
 
-      return Locale();
-    }
+    static boost::string_ref::size_type trashStart( IdString code_r )
+    { return trashStart( boost::string_ref(code_r.c_str()) ); }
 
   private:
+    struct LC {
+      LC()                                     {}
+      LC( LanguageCode l_r )                   : _l( l_r ) {}
+      LC( LanguageCode l_r, CountryCode c_r )  : _l( l_r ), _c( c_r ) {}
+      LanguageCode _l;
+      CountryCode  _c;
+    };
+    typedef std::unordered_map<IdString,LC> CodeMap;
+
+    /** Ctor initializes the code maps. */
+    CodeMaps()
+    : _codeMap( { { IdString::Null,  LC( LanguageCode(IdString::Null),  CountryCode(IdString::Null) )  }
+                , { IdString::Empty, LC( LanguageCode(IdString::Empty), CountryCode(IdString::Empty) ) } } )
+    {}
 
-    LanguageCode _language;
-    CountryCode _country;
-
-  public:
-    /** Offer default Impl. */
-    static shared_ptr<Impl> nullimpl()
+    /** Return \ref LC for \a index_r, creating it if necessary. */
+    const LC & getIndex( IdString index_r )
     {
-      static shared_ptr<Impl> _nullimpl( new Impl );
-      return _nullimpl;
+      auto it = _codeMap.find( index_r );
+      if ( it == _codeMap.end() )
+      {
+       CodeMap::value_type newval( index_r, LC() );
+
+       boost::string_ref str( index_r.c_str() );
+       boost::string_ref::size_type sep = str.find( '_' );
+       if ( sep == boost::string_ref::npos )
+         newval.second._l = LanguageCode( index_r );
+       else
+       {
+         // bsc#1064999: dup! Creating a new IdString may invalidate the IdString.c_str() stored in str.
+         std::string dup( str );
+         str = dup;
+         newval.second._l = LanguageCode( IdString(str.substr( 0, sep )) );
+         newval.second._c = CountryCode( IdString(str.substr( sep+1 )) );
+       }
+
+       it = _codeMap.insert( std::move(newval) ).first;
+      }
+      return it->second;
     }
-  };
-  ///////////////////////////////////////////////////////////////////
 
-  /** \relates Locale::Impl Stream output */
-  inline std::ostream & operator<<( std::ostream & str, const Locale::Impl & obj )
-  {
-    return str << "Locale::Impl";
-  }
+  private:
+    CodeMap _codeMap;
+  };
 
   ///////////////////////////////////////////////////////////////////
-  //
-  //   CLASS NAME : Locale
-  //
+  // class Locale
   ///////////////////////////////////////////////////////////////////
 
   const Locale Locale::noCode;
+  const LanguageCode LanguageCode::enCode("en");       // from in LanguageCode.cc as Locale::enCode depends on it
+  const Locale Locale::enCode( LanguageCode::enCode );
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::Locale
-  //   METHOD TYPE : Ctor
-  //
   Locale::Locale()
-  : _pimpl( Impl::nullimpl() )
   {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::Locale
-  //   METHOD TYPE : Ctor
-  //
-  Locale::Locale( IdString code_r )
-  : _pimpl( new Impl( code_r.asString() ) )
+  Locale::Locale( IdString str_r )
+  : _str( CodeMaps::withoutTrash( str_r ) )
   {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::Locale
-  //   METHOD TYPE : Ctor
-  //
-  Locale::Locale( const std::string & code_r )
-  : _pimpl( new Impl( code_r ) )
+  Locale::Locale( const std::string & str_r )
+  : _str( CodeMaps::withoutTrash( str_r ) )
   {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::Locale
-  //   METHOD TYPE : Ctor
-  //
-  Locale::Locale( const char * code_r )
-  : _pimpl( new Impl( C_Str(code_r).c_str() ) )
+  Locale::Locale( const char * str_r )
+  : _str( CodeMaps::withoutTrash( str_r ) )
   {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::Locale
-  //   METHOD TYPE : Ctor
-  //
-  Locale::Locale( const LanguageCode & language_r,
-                  const CountryCode & country_r )
-  : _pimpl( new Impl( language_r, country_r ) )
+  Locale::Locale( LanguageCode language_r, CountryCode country_r )
+  : _str( CodeMaps::combineLC( language_r, country_r ) )
   {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::~Locale
-  //   METHOD TYPE : Dtor
-  //
   Locale::~Locale()
   {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::
-  //   METHOD TYPE :
-  //
-  const LanguageCode & Locale::language() const
-  { return _pimpl->language(); }
-
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::
-  //   METHOD TYPE :
-  //
-  const CountryCode & Locale::country() const
-  { return _pimpl->country(); }
+  LanguageCode Locale::language() const
+  { return CodeMaps::instance().language( _str ); }
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::
-  //   METHOD TYPE :
-  //
-  std::string Locale::code() const
-  { return _pimpl->code(); }
+  CountryCode Locale::country() const
+  { return CodeMaps::instance().country( _str ); }
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : Locale::
-  //   METHOD TYPE :
-  //
   std::string Locale::name() const
-  { return _pimpl->name(); }
+  { return CodeMaps::instance().name( _str ); }
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //    METHOD NAME : Locale::
-  //    METHOD TYPE :
-  //
   Locale Locale::fallback() const
-  { return _pimpl->fallback(); }
-  /////////////////////////////////////////////////////////////////
+  { return CodeMaps::instance().fallback( _str ); }
+
+  ///////////////////////////////////////////////////////////////////
+
+  Locale Locale::bestMatch( const LocaleSet & avLocales_r, Locale requested_r )
+  {
+    if ( ! avLocales_r.empty() )
+    {
+      if ( ! requested_r )
+       requested_r = ZConfig::instance().textLocale();
+      for ( ; requested_r; requested_r = requested_r.fallback() )
+      {
+        if ( avLocales_r.count( requested_r ) )
+          return requested_r;
+      }
+    }
+    return Locale();
+  }
+
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////