libyui-ncurses  2.44.1
/usr/src/RPM/BUILD/libyui-ncurses-2.44.1/src/NCstring.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019    File:       NCstring.cc
00020 
00021    Author:     Gabriele Strattner <gs@suse.de>
00022 
00023 /-*/
00024 
00025 #include <errno.h>
00026 #include <iconv.h>
00027 #include <malloc.h>
00028 
00029 #define  YUILogComponent "ncurses"
00030 #include <yui/YUILog.h>
00031 #include "NCstring.h"
00032 
00033 
00034 // The default encoding is UTF-8. For real terminals this may be
00035 // changed with setConsoleFont().
00036 
00037 std::string     NCstring::termEncoding( "UTF-8" );
00038 
00039 
00040 
00041 
00042 
00043 
00044 NCstring:: NCstring()
00045         : hotk( 0 )
00046         , hotp( std::wstring::npos )
00047         , wstr( L"" )
00048 
00049 {
00050 }
00051 
00052 
00053 
00054 NCstring::NCstring( const NCstring & nstr )
00055         : hotk( nstr.hotk )
00056         , hotp( nstr.hotp )
00057         , wstr( nstr.wstr )
00058 {
00059 }
00060 
00061 
00062 
00063 NCstring::NCstring( const std::wstring & widestr )
00064         : hotk( 0 )
00065         , hotp( std::wstring::npos )
00066         , wstr( widestr )
00067 {
00068 }
00069 
00070 
00071 
00072 NCstring::NCstring( const std::string & str )
00073         : hotk( 0 )
00074         , hotp( std::wstring::npos )
00075 {
00076     bool ok = RecodeToWchar( str, "UTF-8", &wstr );
00077 
00078     if ( !ok )
00079     {
00080         yuiError() << "ERROR: RecodeToWchar() failed" << std::endl;
00081     }
00082 }
00083 
00084 
00085 
00086 NCstring::NCstring( const char * cstr )
00087         : hotk( 0 )
00088         , hotp( std::wstring::npos )
00089 {
00090     bool ok = RecodeToWchar( cstr, "UTF-8", &wstr );
00091 
00092     if ( !ok )
00093     {
00094         yuiError() << "ERROR: RecodeToWchar() failed" << std::endl;
00095     }
00096 }
00097 
00098 
00099 
00100 std::ostream & operator<<( std::ostream & STREAM, const NCstring & OBJ )
00101 {
00102     return STREAM <<  OBJ.Str() ;
00103 }
00104 
00105 
00106 
00107 NCstring & NCstring::operator=( const NCstring & nstr )
00108 {
00109     if ( &nstr != this )
00110     {
00111         hotk      = nstr.hotk;
00112         hotp      = nstr.hotp;
00113         wstr      = nstr.wstr;
00114     }
00115 
00116     return *this;
00117 }
00118 
00119 
00120 
00121 NCstring & NCstring::operator+=( const NCstring & nstr )
00122 {
00123     wstr.append( nstr.wstr );
00124     return *this;
00125 }
00126 
00127 static iconv_t fromwchar_cd     = ( iconv_t )( -1 );
00128 static std::string  to_name             = "";
00129 
00130 
00131 
00132 bool NCstring::RecodeFromWchar( const std::wstring & in, const std::string & to_encoding, std::string* out )
00133 {
00134     iconv_t cd = ( iconv_t )( -1 );
00135     static bool complained = false;
00136     *out = "";
00137 
00138     if ( in.length() == 0 )
00139         return true;
00140 
00141     // iconv_open not yet called
00142     if ( fromwchar_cd == ( iconv_t )( -1 )
00143          || to_name != to_encoding )
00144     {
00145         if ( fromwchar_cd != ( iconv_t )( -1 ) )
00146         {
00147             iconv_close( fromwchar_cd );
00148         }
00149 
00150         fromwchar_cd = iconv_open( to_encoding.c_str(), "WCHAR_T" );
00151 
00152         yuiDebug() << "iconv_open( " << to_encoding.c_str() << ", \"WCHAR_T\" )" << std::endl;
00153 
00154         if ( fromwchar_cd == ( iconv_t )( -1 ) )
00155         {
00156             if ( !complained )
00157             {
00158                 yuiError() << "ERROR: iconv_open failed" << std::endl;
00159                 complained = true;
00160             }
00161 
00162             return false;
00163         }
00164         else
00165         {
00166             to_name = to_encoding;
00167         }
00168     }
00169 
00170     cd = fromwchar_cd;          // set iconv handle
00171 
00172     size_t in_len = in.length() * sizeof( std::wstring::value_type );   // number of in bytes
00173     char* in_ptr = ( char * )in.data();
00174 
00175     size_t tmp_size = ( in_len * sizeof( char ) ) * 2;
00176     // tmp buffer size: in_len bytes * 2, that means 1 wide charatcer (4 Byte) can be transformed
00177     // into an encoding which needs at most 8 Byte for one character (should be enough)
00178 
00179     char* tmp = ( char* ) malloc( tmp_size + sizeof( char ) );
00180 
00181     do
00182     {
00183 
00184         char *tmp_ptr = tmp;
00185         size_t tmp_len = tmp_size;
00186         *(( char* ) tmp_ptr ) = '\0';
00187 
00188         size_t iconv_ret = iconv( cd, &in_ptr, &in_len, &tmp_ptr, &tmp_len );
00189 
00190         *(( char* ) tmp_ptr ) = '\0';
00191         *out += std::string( tmp );
00192 
00193         if ( iconv_ret == ( size_t )( -1 ) )
00194         {
00195             if ( !complained )
00196             {
00197                 yuiError() << "ERROR iconv: " << errno << std::endl;
00198                 complained = true;
00199             }
00200 
00201             if ( errno == EINVAL || errno == EILSEQ )
00202             {
00203                 *out += '?';
00204             }
00205 
00206             in_ptr += sizeof( std::wstring::value_type );
00207 
00208             in_len -= sizeof( std::wstring::value_type );
00209         }
00210 
00211     }
00212     while ( in_len != 0 );
00213 
00214     free( tmp );
00215 
00216     return true;
00217 }
00218 
00219 static iconv_t towchar_cd       = ( iconv_t )( -1 );
00220 static std::string  from_name   = "";
00221 
00222 
00223 
00224 bool NCstring::RecodeToWchar( const std::string& in, const std::string &from_encoding, std::wstring* out )
00225 {
00226     iconv_t cd = ( iconv_t )( -1 );
00227     static bool complained = false;
00228     *out = L"";
00229 
00230     if ( in.length() == 0 )
00231         return true;
00232 
00233     // iconv_open not yet called
00234     if ( towchar_cd == ( iconv_t )( -1 )
00235          || from_name != from_encoding )
00236     {
00237         if ( towchar_cd != ( iconv_t )( -1 ) )
00238         {
00239             iconv_close( towchar_cd );
00240         }
00241 
00242         towchar_cd = iconv_open( "WCHAR_T", from_encoding.c_str() );
00243 
00244         yuiDebug() << "iconv_open( \"WCHAR_T\", " << from_encoding.c_str() << " )" << std::endl;
00245 
00246         if ( towchar_cd == ( iconv_t )( -1 ) )
00247         {
00248             if ( !complained )
00249             {
00250                 yuiError() << "Error: RecodeToWchar iconv_open() failed" << std::endl;
00251                 complained = true;
00252             }
00253 
00254             return false;
00255         }
00256         else
00257         {
00258             from_name = from_encoding;
00259         }
00260     }
00261 
00262     cd = towchar_cd;            // set iconv handle
00263 
00264     size_t in_len = in.length();                // number of bytes of input std::string
00265     char* in_ptr = const_cast <char*>( in.c_str() );
00266 
00267     size_t tmp_size = in_len * sizeof( wchar_t );       // buffer size: at most in_len wide characters
00268     char* tmp = ( char* ) malloc( tmp_size + sizeof( wchar_t ) );               // + L'\0'
00269 
00270     do
00271     {
00272 
00273         size_t tmp_len = tmp_size;
00274         char* tmp_ptr = tmp;
00275 
00276         size_t iconv_ret = iconv( cd, &in_ptr, &in_len, &tmp_ptr, &tmp_len );
00277 
00278         *(( wchar_t* ) tmp_ptr ) = L'\0';
00279 
00280         *out += std::wstring(( wchar_t* ) tmp );
00281 
00282         if ( iconv_ret == ( size_t )( -1 ) )
00283         {
00284             if ( !complained )
00285             {
00286                 // EILSEQ       84      Illegal byte sequence.
00287                 // EINVAL       22      Invalid argument
00288                 // E2BIG        7       Argument list too long
00289                 yuiError() << "ERROR iconv: " << errno << std::endl;
00290                 complained = true;
00291             }
00292 
00293             if ( errno == EINVAL || errno == EILSEQ )
00294             {
00295                 *out += L'?';
00296             }
00297 
00298             in_ptr++;
00299 
00300             in_len--;
00301         }
00302 
00303     }
00304     while ( in_len != 0 );
00305 
00306     free( tmp );
00307 
00308     return true;
00309 }
00310 
00311 
00312 
00313 std::string NCstring::Str() const
00314 {
00315     std::string utf8str;
00316     RecodeFromWchar( wstr, "UTF-8", &utf8str );
00317 
00318     return utf8str;
00319 }
00320 
00321 
00322 
00323 void NCstring::getHotkey( ) const
00324 {
00325 
00326     hotp = std::wstring::npos;
00327     const wchar_t shortcutMarker = L'&';
00328     const wchar_t replacementShortcutMarker = L'_';
00329 
00330     // I'm not really happy with using replacement markers and copying the std::string
00331     // but is there an other way?
00332     // If hotkey is looked up before un-escaping, its position won't be up-to-date anymore
00333     // as chars got deleted from the std::string
00334     // And vice versa: if un-escaping is done before looking up hotkey position, it's no
00335     // longer possible to tell hotkey marker and regular & (previous &&) apart (this is
00336     // the 'Foo&&Bar&Geeez' case) fB.
00337 
00338     bool have_shortcut = false;
00339     std::wstring::size_type len = wstr.length();
00340     std::wstring newstr;
00341     newstr.reserve( len );
00342 
00343     for (std::wstring::iterator it = wstr.begin(); it != wstr.end(); it++) {
00344         if ( *it == shortcutMarker &&
00345              (it + 1 != wstr.end()) ) {
00346 
00347             // double && un-escaping - bnc#559226
00348             // foo&&bar => foo&bar
00349             if ( *(it+1) == shortcutMarker) {
00350                 newstr += shortcutMarker;  // add only one &
00351                 it++; // .. and jump forth to skip the 2nd one
00352             }
00353             // regular hotkey &X
00354             else {
00355                 // take the first one only (we can't do multiple hotkeys per 1 line
00356                 // so we just discard the rest, argh)
00357                 if ( !have_shortcut) {
00358                     newstr += replacementShortcutMarker;
00359                     have_shortcut = true;
00360                 }
00361             }
00362         }
00363         else
00364            newstr += *it;
00365     }
00366 
00367     wstr = newstr;
00368 
00369     std::wstring::size_type tpos = wstr.find_first_of( replacementShortcutMarker );
00370 
00371     if ( tpos != std::wstring::npos && tpos != wstr.size() - 1 )
00372     {
00373         size_t realpos = 0, t;
00374 
00375         for ( t = 0; t < tpos; t++ )
00376             realpos += wcwidth( wstr[t] );
00377 
00378         wstr.erase( tpos, 1 );
00379 
00380         hotk = wstr[tpos];
00381 
00382         hotp = realpos;
00383     }
00384 
00385 }
00386 
00387 
00388 
00389 bool NCstring::setTerminalEncoding( const std::string & encoding )
00390 {
00391     if ( termEncoding != encoding )
00392     {
00393         yuiMilestone() << "Terminal encoding SET to: " << encoding << std::endl;
00394         termEncoding = encoding;
00395         return true;
00396     }
00397     else
00398     {
00399         return false;
00400     }
00401 }
 All Classes Functions Variables