1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/String.h
12 #ifndef ZYPP_BASE_STRING_H
13 #define ZYPP_BASE_STRING_H
21 #include <boost/format.hpp>
23 #include "zypp/base/Easy.h"
24 #include "zypp/base/PtrTypes.h"
25 #include "zypp/base/Function.h"
28 ///////////////////////////////////////////////////////////////////
31 /** A formater with (N)o (A)rgument (C)heck.
32 * It won't complain about missing or excess arguments. Sometimes
33 * usefull when dealing with translations or classes providing a
36 inline format formatNAC( const std::string & string_r ) {
37 using namespace boost::io;
38 format fmter( string_r );
39 fmter.exceptions( all_error_bits ^ ( too_many_args_bit | too_few_args_bit ) );
43 ///////////////////////////////////////////////////////////////////
45 ///////////////////////////////////////////////////////////////////
47 { /////////////////////////////////////////////////////////////////
49 /** Convenience \c char* constructible from \c std::string and \c char*,
50 * it maps \c (char*)0 to an empty string.
53 * bool hasPrefix( const std::string & str_r, const std::string & prefix_r )
54 * { return( ::strncmp( str_r.c_str(), prefix_r.c_str(), prefix_r.size() ) == 0 ); }
57 * Called with a plain \c char* as argument, the \c std::string is created form
58 * for nothing. The implementation actually does not use the \c std::string.
60 * Best would be to implement \c hasPrefix for each combination of \c char*
61 * and \c std::string arguments:
64 * bool hasPrefix( const std::string & str_r, const std::string & prefix_r )
65 * { return( ::strncmp( str_r.c_str(), prefix_r.c_str(), prefix_r.size() ) == 0 ); }
67 * bool hasPrefix( const std::string & str_r, const char * prefix_r )
68 * { return( !prefix_r || ::strncmp( str_r.c_str(), prefix_r, ::strlen(prefix_r) ) == 0 ); }
70 * bool hasPrefix( const char * str_r, const std::string & prefix_r )
71 * { return( str_r ? ::strncmp( str_r, prefix_r.c_str(), prefix_r.size() ) == 0 : prefix_r.empty() ); }
73 * bool hasPrefix( const char * str_r, const char * prefix_r )
74 * { return( str && prefix_r ? ::strncmp( str_r, prefix_r, ::strlen(prefix_r) ) == 0
75 * : !((str_r && *str_r) || (prefix_r && *prefix_r)); }
78 * This is where \ref C_Str can help. Constructible from \c std::string and \c char*,
79 * it \e reduces the \c std::string to it's \c char*. At the same time it converts
80 * \c (char*)0 into an \c "" string.
83 * bool hasPrefix( const C_Str & str_r, const C_Str & prefix_r )
84 * { return( ::strncmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
90 typedef std::string::size_type size_type;
93 C_Str() : _val( 0 ), _sze( 0 ) {}
94 C_Str( char * c_str_r ) : _val( c_str_r ), _sze( std::string::npos ) {}
95 C_Str( const char * c_str_r ) : _val( c_str_r ), _sze( std::string::npos ) {}
96 C_Str( const std::string & str_r ) : _val( str_r.c_str() ), _sze( str_r.size() ) {}
99 bool isNull() const { return !_val; }
100 bool empty() const { return !(_val && *_val); }
101 size_type size() const
103 if ( _sze == std::string::npos )
104 { _sze = _val ? ::strlen( _val ) : 0; }
108 operator const char *() const { return c_str(); }
109 const char * c_str() const { return _val ? _val : ""; }
112 const char *const _val;
113 mutable size_type _sze;
116 /** \relates C_Str Stream output */
117 inline std::ostream & operator<<( std::ostream & str, const C_Str & obj )
118 { return str << obj.c_str(); }
120 ///////////////////////////////////////////////////////////////////
121 /** String related utilities and \ref ZYPP_STR_REGEX.
122 \see \ref ZYPP_STR_REGEX
125 { /////////////////////////////////////////////////////////////////
127 ///////////////////////////////////////////////////////////////////
129 * Global asString() that works with std::string too
131 inline std::string asString( const std::string &t )
134 #ifndef SWIG // Swig treats it as syntax error
135 inline std::string asString( std::string && t )
136 { return std::move(t); }
139 inline std::string asString( const char * t )
142 inline std::string asString( char * t )
146 inline std::string asString( const _T &t )
147 { return t.asString(); }
150 inline std::string asString( const intrusive_ptr<_T> &p )
151 { return p->asString(); }
154 inline std::string asString( const weak_ptr<_T> &p )
155 { return p->asString(); }
158 inline std::string asString( const bool &t )
159 { return t ? "+" : "-"; }
161 ///////////////////////////////////////////////////////////////////
162 /** Printf style construction of std::string. */
163 std::string form( const char * format, ... )
164 __attribute__ ((format (printf, 1, 2)));
166 ///////////////////////////////////////////////////////////////////
167 /** Return string describing the \a error_r code.
168 * Like ::strerror, but the numerical value is included in
169 * the string as well.
171 std::string strerror( int errno_r );
173 ///////////////////////////////////////////////////////////////////
174 /** Assert \c free called for allocated <tt>char *</tt>.
178 * vasprintf( &safe._buf, format, ap );
179 * return safe.asString();
187 SafeBuf() : _buf( 0 ) {}
188 ~SafeBuf() { if ( _buf ) free( _buf ); }
189 std::string asString() const
190 { return _buf ? std::string(_buf) : std::string(); }
193 ///////////////////////////////////////////////////////////////////
194 /** Convenient building of std::string via std::ostream::operator<<.
195 * Basically this is an \ref ostringstream which is autocenvertible
196 * into a \ref string.
198 * void fnc( const std::string & txt_r );
199 * fnc( str::Str() << "Hello " << 13 );
201 * std::string txt( str::Str() << 45 );
207 Str & operator<<( const _Tp & val )
208 { _str << val; return *this; }
210 operator std::string() const
211 { return _str.str(); }
213 std::ostream & stream()
216 std::ostringstream _str;
219 ///////////////////////////////////////////////////////////////////
220 /** \name String representation of number.
222 * Optional second argument sets the minimal string width (' ' padded).
223 * Negative values will cause the number to be left adjusted within the string.
225 * Default width is 0.
227 * numstring(42) -> "42"
228 * numstring(42, 4) -> " 42"
229 * numstring(42,-4) -> "42 "
233 inline std::string numstring( char n, int w = 0 ) { return form( "%*hhd", w, n ); }
234 inline std::string numstring( unsigned char n, int w = 0 ) { return form( "%*hhu", w, n ); }
235 inline std::string numstring( short n, int w = 0 ) { return form( "%*hd", w, n ); }
236 inline std::string numstring( unsigned short n, int w = 0 ) { return form( "%*hu", w, n ); }
237 inline std::string numstring( int n, int w = 0 ) { return form( "%*d", w, n ); }
238 inline std::string numstring( unsigned n, int w = 0 ) { return form( "%*u", w, n ); }
239 inline std::string numstring( long n, int w = 0 ) { return form( "%*ld", w, n ); }
240 inline std::string numstring( unsigned long n, int w = 0 ) { return form( "%*lu", w, n ); }
241 inline std::string numstring( long long n, int w = 0 ) { return form( "%*lld", w, n ); }
242 inline std::string numstring( unsigned long long n, int w = 0 ) { return form( "%*llu", w, n ); }
244 template<> inline std::string asString( const char & t ) { return numstring( t ); }
245 template<> inline std::string asString( const unsigned char & t ) { return numstring( t ); }
246 template<> inline std::string asString( const short & t ) { return numstring( t ); }
247 template<> inline std::string asString( const unsigned short & t ) { return numstring( t ); }
248 template<> inline std::string asString( const int & t ) { return numstring( t ); }
249 template<> inline std::string asString( const unsigned & t ) { return numstring( t ); }
250 template<> inline std::string asString( const long & t ) { return numstring( t ); }
251 template<> inline std::string asString( const unsigned long & t ) { return numstring( t ); }
252 template<> inline std::string asString( const long long & t ) { return numstring( t ); }
253 template<> inline std::string asString( const unsigned long long & t ) { return numstring( t ); }
256 ///////////////////////////////////////////////////////////////////
257 /** \name String representation of number as hex value with leading '0x'.
258 * Optional second argument sets the minimal
259 * string width (0 padded). Negative values will cause the number to be left adjusted
260 * within the string. Default width is 10 (4 for char).
262 * hexstring(42) -> "0x0000002a"
263 * hexstring(42, 4) -> "0x2a"
264 * hexstring(42,-4) -> "0x2a"
268 inline std::string hexstring( char n, int w = 4 ) { return form( "%#0*hhx", w, n ); }
269 inline std::string hexstring( unsigned char n, int w = 4 ) { return form( "%#0*hhx", w, n ); }
270 inline std::string hexstring( short n, int w = 10 ){ return form( "%#0*hx", w, n ); }
271 inline std::string hexstring( unsigned short n, int w = 10 ){ return form( "%#0*hx", w, n ); }
272 inline std::string hexstring( int n, int w = 10 ){ return form( "%#0*x", w, n ); }
273 inline std::string hexstring( unsigned n, int w = 10 ){ return form( "%#0*x", w, n ); }
274 inline std::string hexstring( long n, int w = 10 ){ return form( "%#0*lx", w, n ); }
275 inline std::string hexstring( unsigned long n, int w = 10 ){ return form( "%#0*lx", w, n ); }
276 inline std::string hexstring( long long n, int w = 0 ) { return form( "%#0*llx", w, n ); }
277 inline std::string hexstring( unsigned long long n, int w = 0 ) { return form( "%#0*llx", w, n ); }
280 ///////////////////////////////////////////////////////////////////
281 /** \name String representation of number as octal value with leading '0'.
282 * Optional second argument sets the minimal
283 * string width (0 padded). Negative values will cause the number to be left adjusted
284 * within the string. Default width is 5 (4 for char).
286 * octstring(42) -> "00052"
287 * octstring(42, 4) -> "0052"
288 * octstring(42,-4) -> "052 "
292 inline std::string octstring( char n, int w = 4 ) { return form( "%#0*hho", w, n ); }
293 inline std::string octstring( unsigned char n, int w = 4 ) { return form( "%#0*hho", w, n ); }
294 inline std::string octstring( short n, int w = 5 ) { return form( "%#0*ho", w, n ); }
295 inline std::string octstring( unsigned short n, int w = 5 ) { return form( "%#0*ho", w, n ); }
296 inline std::string octstring( int n, int w = 5 ) { return form( "%#0*o", w, n ); }
297 inline std::string octstring( unsigned n, int w = 5 ) { return form( "%#0*o", w, n ); }
298 inline std::string octstring( long n, int w = 5 ) { return form( "%#0*lo", w, n ); }
299 inline std::string octstring( unsigned long n, int w = 5 ) { return form( "%#0*lo", w, n ); }
300 inline std::string octstring( long long n, int w = 0 ) { return form( "%#0*llo", w, n ); }
301 inline std::string octstring( unsigned long long n, int w = 0 ) { return form( "%#0*llo", w, n ); }
304 ///////////////////////////////////////////////////////////////////
305 /** Parsing numbers from string.
308 /** String to integer type determined by template arg.
309 * \note Only specializations are defined.
311 * time_t t = strtonum<time_t>( "42" );
314 template<typename _It>
315 _It strtonum( const C_Str & str );
318 inline short strtonum( const C_Str & str ) { return ::strtol ( str, NULL, 0 ); }
320 inline int strtonum( const C_Str & str ) { return ::strtol ( str, NULL, 0 ); }
322 inline long strtonum( const C_Str & str ) { return ::strtol ( str, NULL, 0 ); }
324 inline long long strtonum( const C_Str & str ) { return ::strtoll ( str, NULL, 0 ); }
327 inline unsigned short strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
329 inline unsigned strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
331 inline unsigned long strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
333 inline unsigned long long strtonum( const C_Str & str ) { return ::strtoull( str, NULL, 0 ); }
335 /** String to integer type detemined 2nd function arg \a i.
337 * time_t t; strtonum( "42", t );
340 template<typename _It>
341 inline _It strtonum( const C_Str & str, _It & i )
342 { return i = strtonum<_It>( str ); }
345 ///////////////////////////////////////////////////////////////////
346 /** Parsing boolean from string.
349 /** Return \c true if str is <tt>1, true, yes, on</tt> (or a nonzero number). */
350 bool strToTrue( const C_Str & str );
352 /** Return \c false if str is <tt>0, false, no, off</tt>. */
353 bool strToFalse( const C_Str & str );
355 /** Parse \c str into a bool depending on the default value.
356 * If the \c default is true, look for a legal \c false string.
357 * If the \c default is false, look for a legal \c true string.
359 inline bool strToBool( const C_Str & str, bool default_r )
360 { return( default_r ? strToFalse( str ) : strToTrue( str ) ); }
362 /** Parse \c str into a bool if it's a legal \c true or \c false string.
363 * If \c str is not a recognized \c true or \c false string, \a return_r
366 inline bool strToBoolNodefault( const C_Str & str, bool & return_r )
368 if ( strToTrue( str ) ) return (return_r = true);
369 if ( !strToFalse( str ) ) return (return_r = false);
376 * \short Return a string with all occurrences of \c from_r replaced with \c to_r.
378 std::string gsub( const std::string & str_r, const std::string & from_r, const std::string & to_r );
380 /** \overload A function is called on demand to compute each replacement value.
382 std::string gsubFun( const std::string & str_r, const std::string & from_r, function<std::string()> to_r );
385 * \short Replace all occurrences of \c from_r with \c to_r in \c str_r (inplace).
386 * A reference to \c str_r is also returned for convenience.
388 std::string & replaceAll( std::string & str_r, const std::string & from_r, const std::string & to_r );
390 /** \overload A function is called on demand to compute each replacement value.
392 std::string & replaceAllFun( std::string & str_r, const std::string & from_r, function<std::string()> to_r );
395 ///////////////////////////////////////////////////////////////////
398 /** Split \a line_r into words.
399 * Any sequence of characters in \a sepchars_r is treated as
400 * delimiter. The words are passed to OutputIterator \a result_r.
402 * std::vector<std::string> words;
403 * str::split( "some line", std::back_inserter(words) )
407 template<class _OutputIterator>
408 unsigned split( const C_Str & line_r,
409 _OutputIterator result_r,
410 const C_Str & sepchars_r = " \t" )
412 const char * beg = line_r;
413 const char * cur = beg;
414 // skip leading sepchars
415 while ( *cur && ::strchr( sepchars_r, *cur ) )
418 for ( beg = cur; *beg; beg = cur, ++result_r, ++ret )
421 while( *cur && !::strchr( sepchars_r, *cur ) )
424 *result_r = std::string( beg, cur-beg );
426 while ( *cur && ::strchr( sepchars_r, *cur ) )
432 /** Split \a line_r into words with respect to escape delimeters.
433 * Any sequence of characters in \a sepchars_r is treated as
434 * delimiter if not inside "" or "" or escaped by \, but not \\.
435 * The words are passed to OutputIterator \a result_r.
437 * \see \ref splitEscaped
440 * std::vector<std::string> words;
441 * str::splitEscaped( "some line", std::back_inserter(words) )
445 * example splitted strings
446 * normal line -> 2 elements ( "normal", "line" )
447 * escaped\ line -> 1 element( "escaped line" )
448 * "quoted line" -> 1 element same as above
449 * 'quoted line' -> 1 element same as above
450 * "escaped quote\'" -> 1 element ( "escaped quote'" )
452 * \param line_r The string to parse.
454 * \param sepchars_r String of separator characters.
455 * \param withEmpty Whether to include empty fields between separators in the result.
459 template<class _OutputIterator>
460 unsigned splitEscaped( const C_Str & line_r,
461 _OutputIterator result_r,
462 const C_Str & sepchars_r = " \t",
463 bool withEmpty = false)
465 const char * beg = line_r;
466 const char * cur = beg;
469 // skip leading sepchars
470 while ( *cur && ::strchr( sepchars_r, *cur ) )
480 // there were only sepchars in the string
481 if (!*cur && withEmpty)
487 // after the leading sepchars
488 for ( beg = cur; *beg; beg = cur, ++result_r, ++ret )
490 if ( *cur == '"' || *cur == '\'' )
492 char closeChar = *cur;
497 while ( *cur && *cur != closeChar)
501 return ret; //TODO parsing exception no closing quote
504 const char * esc = cur-1;
505 while ( esc != beg && *esc == '\\' )
510 cont = (escCount % 2 == 1); // find some non escaped escape char
514 std::string s( beg+1, cur-beg-2 ); //without quotes
515 //transform escaped escape
516 replaceAll( s, "\\\\", "\\" );
517 //transform escaped quotes (only same as open
518 char tmpn[2] = { closeChar, 0 };
519 char tmpo[3] = { '\\', closeChar, 0 };
520 replaceAll( s, tmpo, tmpn );
527 while( *cur && !::strchr( sepchars_r, *cur ) )
529 //ignore char after backslash
537 std::string s( beg, cur-beg );
538 //transform escaped escape
539 replaceAll( s, "\\\\", "\\" );
541 const char *delimeter = sepchars_r;
544 std::string ds("\\");
545 const char tmp[2] = { *delimeter, '\0' };
546 std::string del(tmp);
548 replaceAll( s, ds, del );
555 if ( *cur && ::strchr( sepchars_r, *cur ) )
557 while ( *cur && ::strchr( sepchars_r, *cur ) )
566 // the last was a separator => one more field
567 if ( !*cur && withEmpty && ::strchr( sepchars_r, *(cur-1) ) )
576 /** Split \a line_r into fields.
577 * Any single character in \a sepchars_r is treated as a
578 * field separator. The words are passed to OutputIterator
584 * ":a" -> words 2 ||a|
585 * "a:" -> words 2 |a||
586 * ":a:" -> words 3 ||a||
591 * std::vector<std::string> words;
592 * str::split( "some line", std::back_inserter(words) )
596 template<class _OutputIterator>
597 unsigned splitFields( const C_Str & line_r,
598 _OutputIterator result_r,
599 const C_Str & sepchars_r = ":" )
601 const char * beg = line_r;
602 const char * cur = beg;
604 for ( beg = cur; *beg; beg = cur, ++result_r )
607 while( *cur && !::strchr( sepchars_r, *cur ) )
610 *result_r = std::string( beg, cur-beg );
616 if ( ! *cur ) // ending with sepchar
618 *result_r = std::string(); // add final empty field
628 * Split \a line_r into fields handling also escaped separators.
631 * \see splitEscaped()
633 template<class _OutputIterator>
634 unsigned splitFieldsEscaped( const C_Str & line_r,
635 _OutputIterator result_r,
636 const C_Str & sepchars_r = ":" )
639 splitEscaped( line_r, result_r, sepchars_r, true /* withEmpty */ );
644 ///////////////////////////////////////////////////////////////////
647 /** Join strings using separator \a sep_r (defaults to BLANK). */
648 template <class _Iterator>
649 std::string join( _Iterator begin, _Iterator end,
650 const C_Str & sep_r = " " )
653 for ( _Iterator iter = begin; iter != end; ++ iter )
657 res += asString(*iter);
662 /** Join strings using separator \a sep_r (defaults to BLANK). */
663 template <class _Container>
664 std::string join( const _Container & cont_r,
665 const C_Str & sep_r = " " )
666 { return join( cont_r.begin(), cont_r.end(), sep_r ); }
668 /** Join strings using separator \a sep_r, quoting or escaping the values.
669 * Separator defaults to BLANK. Use \ref splitEscaped to restore the
672 template <class _Iterator>
673 std::string joinEscaped( _Iterator begin, _Iterator end,
674 const char sep_r = ' ' )
676 std::vector<char> buf;
677 for ( _Iterator iter = begin; iter != end; ++ iter )
680 buf.push_back( sep_r );
684 // empty string goes ""
685 buf.push_back( '"' );
686 buf.push_back( '"' );
690 std::string toadd( asString(*iter) );
691 for_( ch, toadd.begin(), toadd.end() )
698 buf.push_back( '\\' );
699 buf.push_back( *ch );
703 buf.push_back( '\\' );
704 buf.push_back( *ch );
709 return std::string( buf.begin(), buf.end() );
714 ///////////////////////////////////////////////////////////////////
718 * Escape desired character \a c using a backslash.
720 * For use when printing \a c separated values, and where
721 * \ref joinEscaped() is too heavy.
723 std::string escape( const C_Str & str_r, const char c = ' ' );
725 /** Escape \a next_r and append it to \a str_r using separator \a sep_r. */
726 inline void appendEscaped( std::string & str_r, const C_Str & next_r, const char sep_r = ' ' )
728 if ( ! str_r.empty() )
730 if ( next_r.empty() )
733 str_r += escape( next_r, sep_r );
739 ///////////////////////////////////////////////////////////////////
740 ///////////////////////////////////////////////////////////////////
742 * Encode all characters other than [a-zA-Z0-9] as %XX.
743 * This includes the % character itself, which becomes %25.
746 /** Encode all characters other than [a-zA-Z0-9] as %XX.
747 * This includes the % character itself, which becomes %25.
749 std::string hexencode( const C_Str & str_r );
750 /** Decode hexencoded %XX sequences. */
751 std::string hexdecode( const C_Str & str_r );
753 ///////////////////////////////////////////////////////////////////
755 /** \name Case conversion. */
757 /** Return lowercase version of \a s
760 std::string toLower( const std::string & s );
762 inline std::string toLower( const char * s )
763 { return( s ? toLower( std::string(s) ) : std::string() ); }
765 /** Return uppercase version of \a s
768 std::string toUpper( const std::string & s );
770 inline std::string toUpper( const char * s )
771 { return( s ? toUpper( std::string(s) ) : std::string() ); }
775 /** \name Case insensitive comparison. */
777 inline int compareCI( const C_Str & lhs, const C_Str & rhs )
778 { return ::strcasecmp( lhs, rhs ); }
781 /** \name Locate substring. */
783 /** Locate substring case sensitive. */
784 inline bool contains( const C_Str & str_r, const C_Str & val_r )
785 { return ::strstr( str_r, val_r ); }
786 /** Locate substring case insensitive. */
787 inline bool containsCI( const C_Str & str_r, const C_Str & val_r )
788 { return ::strcasestr( str_r, val_r ); }
791 ///////////////////////////////////////////////////////////////////
792 /** \name Trimming whitepace.
793 * \todo optimize l/r trim.
796 /** To define how to trim. */
801 TRIM = (L_TRIM|R_TRIM)
804 std::string trim( const std::string & s, const Trim trim_r = TRIM );
806 inline std::string ltrim( const std::string & s )
807 { return trim( s, L_TRIM ); }
809 inline std::string rtrim( const std::string & s )
810 { return trim( s, R_TRIM ); }
813 std::string stripFirstWord( std::string & line, const bool ltrim_first );
815 std::string stripLastWord( std::string & line, const bool rtrim_first );
817 /** Return stream content up to (but not returning) the next newline.
818 * \see \ref receiveUpTo
820 std::string getline( std::istream & str, bool trim = false );
822 /** Return stream content up to (but not returning) the next newline.
823 * \see \ref receiveUpTo
825 std::string getline( std::istream & str, const Trim trim_r );
827 /** Return stream content up to the next ocurrence of \c delim_r or EOF
828 * \c delim_r, if found, is always read from the stream. Whether it is
829 * also returned in the string depends on \c returnDelim_r.
830 * If the stream status is \c good, \c delim_r was found in the stream.
831 * If we reached EOF while looking for \c delim_r, \c eof is set; and
832 * also \c fail, if we did not read any data before.
834 std::string receiveUpTo( std::istream & str, const char delim_r, bool returnDelim_r = false );
836 ///////////////////////////////////////////////////////////////////
838 /** \name String prefix/suffix handling.
841 /** Return whether \a str_r has prefix \a prefix_r. */
842 inline bool hasPrefix( const C_Str & str_r, const C_Str & prefix_r )
843 { return( ::strncmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
845 /** Strip a \a prefix_r from \a str_r and return the resulting string. */
846 inline std::string stripPrefix( const C_Str & str_r, const C_Str & prefix_r )
847 { return( hasPrefix( str_r, prefix_r ) ? str_r + prefix_r.size() : str_r.c_str() ); }
849 /** Return whether \a str_r has suffix \a suffix_r. */
850 inline bool hasSuffix( const C_Str & str_r, const C_Str & suffix_r )
851 { return( str_r.size() >= suffix_r.size() && ::strncmp( str_r + str_r.size() - suffix_r.size() , suffix_r, suffix_r.size() ) == 0 ); }
853 /** Strip a \a suffix_r from \a str_r and return the resulting string. */
854 inline std::string stripSuffix( const C_Str & str_r, const C_Str & suffix_r )
856 if ( hasSuffix( str_r, suffix_r ) )
857 return std::string( str_r, str_r.size() - suffix_r.size() );
858 return str_r.c_str();
860 /** Return size of the common prefix of \a lhs and \a rhs. */
861 inline std::string::size_type commonPrefix( const C_Str & lhs, const C_Str & rhs )
863 const char * lp = lhs.c_str();
864 const char * rp = rhs.c_str();
865 std::string::size_type ret = 0;
866 while ( *lp == *rp && *lp != '\0' )
867 { ++lp, ++rp, ++ret; }
871 /** alias for \ref hasPrefix */
872 inline bool startsWith( const C_Str & str_r, const C_Str & prefix_r )
873 { return hasPrefix( str_r, prefix_r ); }
874 /** alias for \ref hasSuffix */
875 inline bool endsWith( const C_Str & str_r, const C_Str & prefix_r )
876 { return hasSuffix( str_r, prefix_r ); }
878 /////////////////////////////////////////////////////////////////
880 ///////////////////////////////////////////////////////////////////
881 /////////////////////////////////////////////////////////////////
883 ///////////////////////////////////////////////////////////////////
884 #endif // ZYPP_BASE_STRING_H