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>
22 #include <boost/utility/string_ref.hpp>
24 #include "zypp/base/Easy.h"
25 #include "zypp/base/PtrTypes.h"
26 #include "zypp/base/Function.h"
28 ///////////////////////////////////////////////////////////////////
29 namespace boost { namespace logic { class tribool; } }
30 namespace zypp { typedef boost::logic::tribool TriBool; }
31 ///////////////////////////////////////////////////////////////////
33 ///////////////////////////////////////////////////////////////////
36 /** Request a human readable (translated) string representation of Tp [Tp.asUserString()]
37 * Classes may implement a default as member function.
40 std::string asUserString( const Tp & val_r )
41 { return val_r.asUserString(); }
44 ///////////////////////////////////////////////////////////////////
46 ///////////////////////////////////////////////////////////////////
48 { /////////////////////////////////////////////////////////////////
50 /** Convenience \c char* constructible from \c std::string and \c char*,
51 * it maps \c (char*)0 to an empty string.
54 * bool hasPrefix( const std::string & str_r, const std::string & prefix_r )
55 * { return( ::strncmp( str_r.c_str(), prefix_r.c_str(), prefix_r.size() ) == 0 ); }
58 * Called with a plain \c char* as argument, the \c std::string is created form
59 * for nothing. The implementation actually does not use the \c std::string.
61 * Best would be to implement \c hasPrefix for each combination of \c char*
62 * and \c std::string arguments:
65 * bool hasPrefix( const std::string & str_r, const std::string & prefix_r )
66 * { return( ::strncmp( str_r.c_str(), prefix_r.c_str(), prefix_r.size() ) == 0 ); }
68 * bool hasPrefix( const std::string & str_r, const char * prefix_r )
69 * { return( !prefix_r || ::strncmp( str_r.c_str(), prefix_r, ::strlen(prefix_r) ) == 0 ); }
71 * bool hasPrefix( const char * str_r, const std::string & prefix_r )
72 * { return( str_r ? ::strncmp( str_r, prefix_r.c_str(), prefix_r.size() ) == 0 : prefix_r.empty() ); }
74 * bool hasPrefix( const char * str_r, const char * prefix_r )
75 * { return( str && prefix_r ? ::strncmp( str_r, prefix_r, ::strlen(prefix_r) ) == 0
76 * : !((str_r && *str_r) || (prefix_r && *prefix_r)); }
79 * This is where \ref C_Str can help. Constructible from \c std::string and \c char*,
80 * it \e reduces the \c std::string to it's \c char*. At the same time it converts
81 * \c (char*)0 into an \c "" string.
84 * bool hasPrefix( const C_Str & str_r, const C_Str & prefix_r )
85 * { return( ::strncmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
88 * \todo Check whether to replace by boost::string_ref
93 typedef std::string::size_type size_type;
96 C_Str() : _val( 0 ), _sze( 0 ) {}
97 C_Str( char * c_str_r ) : _val( c_str_r ), _sze( std::string::npos ) {}
98 C_Str( const char * c_str_r ) : _val( c_str_r ), _sze( std::string::npos ) {}
99 C_Str( const std::string & str_r ) : _val( str_r.c_str() ), _sze( str_r.size() ) {}
100 C_Str( const boost::string_ref & str_r ) : _val( str_r.data() ), _sze( str_r.size() ) {}
103 bool isNull() const { return !_val; }
104 bool empty() const { return !(_val && *_val); }
105 size_type size() const
107 if ( _sze == std::string::npos )
108 { _sze = _val ? ::strlen( _val ) : 0; }
112 operator const char *() const { return c_str(); }
113 const char * c_str() const { return _val ? _val : ""; }
116 const char *const _val;
117 mutable size_type _sze;
120 /** \relates C_Str Stream output */
121 inline std::ostream & operator<<( std::ostream & str, const C_Str & obj )
122 { return str << obj.c_str(); }
124 ///////////////////////////////////////////////////////////////////
125 /** String related utilities and \ref ZYPP_STR_REGEX.
126 \see \ref ZYPP_STR_REGEX
130 { /////////////////////////////////////////////////////////////////
132 ///////////////////////////////////////////////////////////////////
134 * Global asString() that works with std::string too
136 inline const std::string & asString( const std::string & t )
139 #ifndef SWIG // Swig treats it as syntax error
140 inline std::string && asString( std::string && t )
141 { return std::move(t); }
144 inline std::string asString( const char * t )
145 { return t == nullptr ? std::string() : t; }
147 inline std::string asString( char * t )
148 { return t == nullptr ? std::string() : t; }
151 inline std::string asString( const Tp &t )
152 { return t.asString(); }
155 inline std::string asString( const intrusive_ptr<Tp> &p )
156 { return p->asString(); }
159 inline std::string asString( const weak_ptr<Tp> &p )
160 { return p->asString(); }
163 inline std::string asString( const bool &t )
164 { return t ? "true" : "false"; }
166 ///////////////////////////////////////////////////////////////////
167 /** Printf style construction of std::string. */
168 std::string form( const char * format, ... )
169 __attribute__ ((format (printf, 1, 2)));
171 ///////////////////////////////////////////////////////////////////
172 /** Return string describing the \a error_r code.
173 * Like ::strerror, but the numerical value is included in
174 * the string as well.
176 std::string strerror( int errno_r );
178 ///////////////////////////////////////////////////////////////////
179 /** Assert \c free called for allocated <tt>char *</tt>.
183 * vasprintf( &safe._buf, format, ap );
184 * return safe.asString();
192 SafeBuf() : _buf( 0 ) {}
193 ~SafeBuf() { if ( _buf ) free( _buf ); }
194 std::string asString() const
195 { return _buf ? std::string(_buf) : std::string(); }
198 ///////////////////////////////////////////////////////////////////
200 /// \brief Convenient building of std::string via \ref std::ostringstream
201 /// Basically a \ref std::ostringstream autoconvertible to \ref std::string
202 /// for building string arguments.
204 /// void fnc( const std::string & txt_r );
205 /// fnc( str::Str() << "Hello " << 13 );
207 /// std::string txt( str::Str() << 45 );
209 ///////////////////////////////////////////////////////////////////
213 Str & operator<<( Tp && val )
214 { _str << std::forward<Tp>(val); return *this; }
216 Str & operator<<( std::ostream& (*iomanip)( std::ostream& ) )
217 { _str << iomanip; return *this; }
219 operator std::string() const { return _str.str(); }
220 std::string asString() const { return _str.str(); }
221 std::string str() const { return _str.str(); }
223 const std::ostream & stream() const { return _str; }
224 std::ostream & stream() { return _str; }
226 void clear() { _str.str( std::string() ); }
229 std::ostringstream _str;
232 /** \relates Str Stream output */
233 inline std::ostream & operator<<( std::ostream & str, const Str & obj )
234 { return str << obj.str(); }
236 ///////////////////////////////////////////////////////////////////
238 /// \brief Convenient building of std::string with \ref boost::format.
239 /// Basically a \ref boost::format autoconvertible to \ref std::string
240 /// for building string arguments.
242 /// void fnc( const std::string & txt_r );
243 /// fnc( str::Format("Hello %1%") % 13 );
245 /// std::string txt( str::Format("Hello %1%") % 13 );
247 ///////////////////////////////////////////////////////////////////
251 Format( const std::string & format_r ) : _fmter( format_r ) {}
254 Format & operator%( Tp && arg )
255 { _fmter % std::forward<Tp>(arg); return *this; }
257 operator std::string() const { return _fmter.str(); }
258 std::string asString() const { return _fmter.str(); }
259 std::string str() const { return _fmter.str(); }
261 const boost::format & fmter() const { return _fmter; }
262 boost::format & fmter() { return _fmter; }
265 boost::format _fmter;
268 /** \relates Format Stream output */
269 inline std::ostream & operator<<( std::ostream & str, const Format & obj )
270 { return str << obj.fmter(); }
272 ///////////////////////////////////////////////////////////////////
274 /// \brief \ref Format with (N)o (A)rgument (C)heck.
275 /// It won't complain about missing or excess arguments. Sometimes
276 /// usefull when dealing with translations or classes providing a
277 /// default formater.
278 ///////////////////////////////////////////////////////////////////
279 struct FormatNAC : public Format
281 FormatNAC() { relax(); }
282 FormatNAC( const std::string & format_r ) : Format( format_r ) { relax(); }
287 using namespace boost::io;
288 _fmter.exceptions( all_error_bits ^ ( too_many_args_bit | too_few_args_bit ) );
291 ///////////////////////////////////////////////////////////////////
292 /** \name String representation of number.
294 * Optional second argument sets the minimal string width (' ' padded).
295 * Negative values will cause the number to be left adjusted within the string.
297 * Default width is 0.
299 * numstring(42) -> "42"
300 * numstring(42, 4) -> " 42"
301 * numstring(42,-4) -> "42 "
305 inline std::string numstring( char n, int w = 0 ) { return form( "%*hhd", w, n ); }
306 inline std::string numstring( unsigned char n, int w = 0 ) { return form( "%*hhu", w, n ); }
307 inline std::string numstring( short n, int w = 0 ) { return form( "%*hd", w, n ); }
308 inline std::string numstring( unsigned short n, int w = 0 ) { return form( "%*hu", w, n ); }
309 inline std::string numstring( int n, int w = 0 ) { return form( "%*d", w, n ); }
310 inline std::string numstring( unsigned n, int w = 0 ) { return form( "%*u", w, n ); }
311 inline std::string numstring( long n, int w = 0 ) { return form( "%*ld", w, n ); }
312 inline std::string numstring( unsigned long n, int w = 0 ) { return form( "%*lu", w, n ); }
313 inline std::string numstring( long long n, int w = 0 ) { return form( "%*lld", w, n ); }
314 inline std::string numstring( unsigned long long n, int w = 0 ) { return form( "%*llu", w, n ); }
316 template<> inline std::string asString( const char & t ) { return numstring( t ); }
317 template<> inline std::string asString( const unsigned char & t ) { return numstring( t ); }
318 template<> inline std::string asString( const short & t ) { return numstring( t ); }
319 template<> inline std::string asString( const unsigned short & t ) { return numstring( t ); }
320 template<> inline std::string asString( const int & t ) { return numstring( t ); }
321 template<> inline std::string asString( const unsigned & t ) { return numstring( t ); }
322 template<> inline std::string asString( const long & t ) { return numstring( t ); }
323 template<> inline std::string asString( const unsigned long & t ) { return numstring( t ); }
324 template<> inline std::string asString( const long long & t ) { return numstring( t ); }
325 template<> inline std::string asString( const unsigned long long & t ) { return numstring( t ); }
328 ///////////////////////////////////////////////////////////////////
329 /** \name String representation of number as hex value with leading '0x'.
330 * Optional second argument sets the minimal
331 * string width (0 padded). Negative values will cause the number to be left adjusted
332 * within the string. Default width is 10 (4 for char).
334 * hexstring(42) -> "0x0000002a"
335 * hexstring(42, 4) -> "0x2a"
336 * hexstring(42,-4) -> "0x2a"
340 inline std::string hexstring( char n, int w = 4 ) { return form( "%#0*hhx", w, n ); }
341 inline std::string hexstring( unsigned char n, int w = 4 ) { return form( "%#0*hhx", w, n ); }
342 inline std::string hexstring( short n, int w = 10 ){ return form( "%#0*hx", w, n ); }
343 inline std::string hexstring( unsigned short n, int w = 10 ){ return form( "%#0*hx", w, n ); }
344 inline std::string hexstring( int n, int w = 10 ){ return form( "%#0*x", w, n ); }
345 inline std::string hexstring( unsigned n, int w = 10 ){ return form( "%#0*x", w, n ); }
346 inline std::string hexstring( long n, int w = 10 ){ return form( "%#0*lx", w, n ); }
347 inline std::string hexstring( unsigned long n, int w = 10 ){ return form( "%#0*lx", w, n ); }
348 inline std::string hexstring( long long n, int w = 0 ) { return form( "%#0*llx", w, n ); }
349 inline std::string hexstring( unsigned long long n, int w = 0 ) { return form( "%#0*llx", w, n ); }
352 ///////////////////////////////////////////////////////////////////
353 /** \name String representation of number as octal value with leading '0'.
354 * Optional second argument sets the minimal
355 * string width (0 padded). Negative values will cause the number to be left adjusted
356 * within the string. Default width is 5 (4 for char).
358 * octstring(42) -> "00052"
359 * octstring(42, 4) -> "0052"
360 * octstring(42,-4) -> "052 "
364 inline std::string octstring( char n, int w = 4 ) { return form( "%#0*hho", w, n ); }
365 inline std::string octstring( unsigned char n, int w = 4 ) { return form( "%#0*hho", w, n ); }
366 inline std::string octstring( short n, int w = 5 ) { return form( "%#0*ho", w, n ); }
367 inline std::string octstring( unsigned short n, int w = 5 ) { return form( "%#0*ho", w, n ); }
368 inline std::string octstring( int n, int w = 5 ) { return form( "%#0*o", w, n ); }
369 inline std::string octstring( unsigned n, int w = 5 ) { return form( "%#0*o", w, n ); }
370 inline std::string octstring( long n, int w = 5 ) { return form( "%#0*lo", w, n ); }
371 inline std::string octstring( unsigned long n, int w = 5 ) { return form( "%#0*lo", w, n ); }
372 inline std::string octstring( long long n, int w = 0 ) { return form( "%#0*llo", w, n ); }
373 inline std::string octstring( unsigned long long n, int w = 0 ) { return form( "%#0*llo", w, n ); }
377 ///////////////////////////////////////////////////////////////////
378 /** String representation of number as bit-string with leading '0's. */
379 template <typename TInt>
380 std::string binstring( TInt val_r )
382 constexpr unsigned bits = sizeof(TInt)*8;
383 std::string ret( bits, ' ' );
385 for ( unsigned pos = bits; pos > 0; )
386 { --pos; ret[pos] = ((val_r & bit)?'1':'0'); bit = bit<<1; }
390 ///////////////////////////////////////////////////////////////////
391 /** Parsing numbers from string.
394 /** String to integer type determined by template arg.
395 * \note Only specializations are defined.
397 * time_t t = strtonum<time_t>( "42" );
400 template<typename TInt>
401 TInt strtonum( const C_Str & str );
404 inline short strtonum( const C_Str & str ) { return ::strtol ( str, NULL, 0 ); }
406 inline int strtonum( const C_Str & str ) { return ::strtol ( str, NULL, 0 ); }
408 inline long strtonum( const C_Str & str ) { return ::strtol ( str, NULL, 0 ); }
410 inline long long strtonum( const C_Str & str ) { return ::strtoll ( str, NULL, 0 ); }
413 inline unsigned short strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
415 inline unsigned strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
417 inline unsigned long strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
419 inline unsigned long long strtonum( const C_Str & str ) { return ::strtoull( str, NULL, 0 ); }
421 /** String to integer type detemined 2nd function arg \a i.
423 * time_t t; strtonum( "42", t );
426 template<typename TInt>
427 inline TInt strtonum( const C_Str & str, TInt & i )
428 { return i = strtonum<TInt>( str ); }
431 ///////////////////////////////////////////////////////////////////
432 /** Parsing boolean from string.
435 /** Return \c true if str is <tt>1, true, yes, on</tt> (or a nonzero number). */
436 bool strToTrue( const C_Str & str );
438 /** Return \c false if str is <tt>0, false, no, off</tt>. */
439 bool strToFalse( const C_Str & str );
441 /** Parse \c str into a bool depending on the default value.
442 * If the \c default is true, look for a legal \c false string.
443 * If the \c default is false, look for a legal \c true string.
445 inline bool strToBool( const C_Str & str, bool default_r )
446 { return( default_r ? strToFalse( str ) : strToTrue( str ) ); }
448 /** Parse \c str into a bool if it's a legal \c true or \c false string.
449 * If \c str is not a recognized \c true or \c false string, \a return_r
452 inline bool strToBoolNodefault( const C_Str & str, bool & return_r )
454 if ( strToTrue( str ) ) return (return_r = true);
455 if ( !strToFalse( str ) ) return (return_r = false);
459 /** Parse \c str into a bool if it's a legal \c true or \c false string; else \c indterminate. */
460 TriBool strToTriBool( const C_Str & str );
465 * \short Return a string with all occurrences of \c from_r replaced with \c to_r.
467 std::string gsub( const std::string & str_r, const std::string & from_r, const std::string & to_r );
469 /** \overload A function is called on demand to compute each replacement value.
471 std::string gsubFun( const std::string & str_r, const std::string & from_r, function<std::string()> to_r );
474 * \short Replace all occurrences of \c from_r with \c to_r in \c str_r (inplace).
475 * A reference to \c str_r is also returned for convenience.
477 std::string & replaceAll( std::string & str_r, const std::string & from_r, const std::string & to_r );
479 /** \overload A function is called on demand to compute each replacement value.
481 std::string & replaceAllFun( std::string & str_r, const std::string & from_r, function<std::string()> to_r );
483 /** Enhance readability: insert gaps at regular distance
486 * Key Fingerprint: 22C07BA534178CD02EFE22AAB88B2FD43DBDC284
488 * Key Fingerprint: 22C07BA5 34178CD0 2EFE22AA B88B2FD4 3DBDC284
490 * Key Fingerprint: 22C0 7BA5 3417 8CD0 2EFE 22AA B88B 2FD4 3DBD C284
492 * Key Fingerprint: 22C0-7BA5-3417-8CD0-2EFE-22AA-B88B-2FD4-3DBD-C284
495 inline std::string gapify( std::string inp_r, std::string::size_type gap_r = 1, char gapchar = ' ' )
497 if ( gap_r && inp_r.size() > gap_r )
499 inp_r.reserve( inp_r.size() + (inp_r.size()-1)/gap_r );
500 for ( std::string::size_type pos = gap_r; pos < inp_r.size(); pos += gap_r+1 )
501 inp_r.insert( pos, 1, gapchar );
506 ///////////////////////////////////////////////////////////////////
509 /** Split \a line_r into words.
510 * Any sequence of characters in \a sepchars_r is treated as
511 * delimiter. The words are passed to OutputIterator \a result_r.
513 * std::vector<std::string> words;
514 * str::split( "some line", std::back_inserter(words) )
518 template<class TOutputIterator>
519 unsigned split( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = " \t" )
521 const char * beg = line_r;
522 const char * cur = beg;
523 // skip leading sepchars
524 while ( *cur && ::strchr( sepchars_r, *cur ) )
527 for ( beg = cur; *beg; beg = cur, ++result_r, ++ret )
530 while( *cur && !::strchr( sepchars_r, *cur ) )
533 *result_r = std::string( beg, cur-beg );
535 while ( *cur && ::strchr( sepchars_r, *cur ) )
541 /** Split \a line_r into words with respect to escape delimeters.
542 * Any sequence of characters in \a sepchars_r is treated as
543 * delimiter if not inside \c "" or \c '' or escaped by \c \.
545 * \li A non-quoted backslash (\) preserves the literal value of the next character.
546 * \li Enclosing characters in single quotes preserves the literal value of each
547 * character within the quotes. A single quote may not occur between single
548 * quotes, even when preceded by a backslash.
549 * \li Enclosing characters in double quotes preserves the literal value of all
550 * characters within the quotes, with the exception of \c \. The backslash
551 * retains its special meaning only when followed by \c " or \c \.
553 * The words are passed to OutputIterator \a result_r.
555 * \see \ref splitEscaped
558 * std::vector<std::string> words;
559 * str::splitEscaped( "some line", std::back_inserter(words) )
563 * example splitted strings
564 * normal line -> 2 elements ( "normal", "line" )
565 * escaped\ line -> 1 element(escaped line)
566 * "quoted line" -> 1 element same as above
567 * 'quoted line' -> 1 element same as above
568 * "escaped quote\"" -> 1 element (escaped quote")
570 * \param line_r The string to parse.
572 * \param sepchars_r String of separator characters.
573 * \param withEmpty Whether to include empty fields between separators in the result.
577 template<class TOutputIterator>
578 unsigned splitEscaped( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = " \t", bool withEmpty = false)
580 const char * beg = line_r;
581 const char * cur = beg;
584 // skip leading sepchars
585 while ( *cur && ::strchr( sepchars_r, *cur ) )
595 // there were only sepchars in the string
596 if (!*cur && withEmpty)
602 // after the leading sepchars
603 enum class Quote { None, Slash, Single, Double, DoubleSlash };
604 std::vector<char> buf;
605 Quote quoting = Quote::None;
606 for ( beg = cur; *beg; beg = cur, ++result_r, ++ret )
608 // read next value until unquoted sepchar
610 quoting = Quote::None;
617 case '\\': quoting = Quote::Slash; break;
618 case '\'': quoting = Quote::Single; break;
619 case '"': quoting = Quote::Double; break;
620 default: buf.push_back( *cur ); break;
625 buf.push_back( *cur );
626 quoting = Quote::None;
632 case '\'': quoting = Quote::None; break;
633 default: buf.push_back( *cur ); break;
640 case '\"': quoting = Quote::None; break;
641 case '\\': quoting = Quote::DoubleSlash; break;
642 default: buf.push_back( *cur ); break;
646 case Quote::DoubleSlash:
649 case '\"': /*fallthrough*/
650 case '\\': buf.push_back( *cur ); break;
652 buf.push_back( '\\' );
653 buf.push_back( *cur );
656 quoting = Quote::Double;
660 } while ( *cur && ( quoting != Quote::None || !::strchr( sepchars_r, *cur ) ) );
661 *result_r = std::string( buf.begin(), buf.end() );
665 if ( *cur && ::strchr( sepchars_r, *cur ) )
667 while ( *cur && ::strchr( sepchars_r, *cur ) )
676 // the last was a separator => one more field
677 if ( !*cur && withEmpty && ::strchr( sepchars_r, *(cur-1) ) )
686 /** Split \a line_r into fields.
687 * Any single character in \a sepchars_r is treated as a
688 * field separator unless \-escaped. The words are passed
695 * ":a" -> words 2 ||a|
696 * "a:" -> words 2 |a||
697 * ":a:" -> words 3 ||a||
702 * std::vector<std::string> words;
703 * str::split( "some line", std::back_inserter(words) )
707 template<class TOutputIterator>
708 unsigned splitFields( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = ":" )
710 const char * beg = line_r;
711 const char * cur = beg;
713 for ( beg = cur; *beg; beg = cur, ++result_r )
716 while( *cur && !::strchr( sepchars_r, *cur ) )
718 if ( *cur == '\\' && *(cur+1) )
723 *result_r = std::string( beg, cur-beg );
729 if ( ! *cur ) // ending with sepchar
731 *result_r = std::string(); // add final empty field
741 * Split \a line_r into fields handling also escaped separators.
744 * \see splitEscaped()
746 template<class TOutputIterator>
747 unsigned splitFieldsEscaped( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = ":" )
749 return splitEscaped( line_r, result_r, sepchars_r, true /* withEmpty */ );
754 ///////////////////////////////////////////////////////////////////
757 /** Join strings using separator \a sep_r (defaults to BLANK). */
758 template <class TIterator>
759 std::string join( TIterator begin, TIterator end, const C_Str & sep_r = " " )
762 for ( TIterator iter = begin; iter != end; ++ iter )
766 res += asString(*iter);
771 /** Join strings using separator \a sep_r (defaults to BLANK). */
772 template <class TContainer>
773 std::string join( const TContainer & cont_r, const C_Str & sep_r = " " )
774 { return join( cont_r.begin(), cont_r.end(), sep_r ); }
776 /** Join strings using separator \a sep_r, quoting or escaping the values.
777 * Separator defaults to BLANK. Use \ref splitEscaped to restore the
780 template <class TIterator>
781 std::string joinEscaped( TIterator begin, TIterator end, const char sep_r = ' ' )
783 std::vector<char> buf;
784 for ( TIterator iter = begin; iter != end; ++ iter )
787 buf.push_back( sep_r );
791 // empty string goes ""
792 buf.push_back( '"' );
793 buf.push_back( '"' );
797 std::string toadd( asString(*iter) );
798 for_( ch, toadd.begin(), toadd.end() )
805 buf.push_back( '\\' );
806 buf.push_back( *ch );
810 buf.push_back( '\\' );
811 buf.push_back( *ch );
816 return std::string( buf.begin(), buf.end() );
821 ///////////////////////////////////////////////////////////////////
824 /** Indent by string [" "] optionally wrap.
825 * Prints nothing for an empty string. Asserts a trainling '\n' on
826 * the last line. Optionally wrap lines at ' ' at a given length.
828 inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, const std::string & indent_r = " ", unsigned maxWitdh_r = 0 )
832 if ( indent_r.size() >= maxWitdh_r )
833 maxWitdh_r = 0; // nonsense: indent larger than line witdh
835 maxWitdh_r -= indent_r.size();
838 for ( const char * e = text_r.c_str(), * s = e; *e; s = ++e )
840 for ( ; *e && *e != '\n'; ++e ) ;/*searching*/
842 if ( maxWitdh_r && width > maxWitdh_r )
846 for ( e = s+width; e > s && *e != ' '; --e ) ;/*searching*/
848 width = e-s; // on a ' ', replaced by '\n'
850 e = s+width-1; // cut line;
853 str.write( s, width );
855 if ( !*e ) // on '\0'
860 /** \overload Indent by number of chars [' '] optionally wrap. */
861 inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, unsigned indent_r, char indentch_r = ' ', unsigned maxWitdh_r = 0 )
862 { return printIndented( str, text_r, std::string( indent_r, indentch_r ), maxWitdh_r ); }
863 /** \overload Indent by number of chars [' '] wrap. */
864 inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, unsigned indent_r, unsigned maxWitdh_r, char indentch_r = ' ' )
865 { return printIndented( str, text_r, std::string( indent_r, indentch_r ), maxWitdh_r ); }
867 /** Prefix lines by string computed by function taking line begin/end [std::string(const char*, const char*)]
868 * Prints nothing for an empty string. Asserts a trainling '\n' on the last line.
870 inline std::ostream & autoPrefix( std::ostream & str, const std::string & text_r, function<std::string(const char*, const char*)> fnc_r )
872 for ( const char * e = text_r.c_str(); *e; ++e )
875 for ( ; *e && *e != '\n'; ++e ) /*searching*/;
876 str << fnc_r( s, e );
879 if ( !*e ) // on '\0'
884 /** \overload Prefix lines by string generated by function [std::string()] */
885 inline std::ostream & autoPrefix0( std::ostream & str, const std::string & text_r, function<std::string()> fnc_r )
887 auto wrap = [&fnc_r]( const char*, const char* )-> std::string {
890 return autoPrefix( str, text_r, wrap );
893 ///////////////////////////////////////////////////////////////////
897 * Escape desired character \a c using a backslash.
899 * For use when printing \a c separated values, and where
900 * \ref joinEscaped() is too heavy.
902 std::string escape( const C_Str & str_r, const char c = ' ' );
904 /** Escape \a next_r and append it to \a str_r using separator \a sep_r. */
905 inline void appendEscaped( std::string & str_r, const C_Str & next_r, const char sep_r = ' ' )
907 if ( ! str_r.empty() )
909 if ( next_r.empty() )
912 str_r += escape( next_r, sep_r );
918 ///////////////////////////////////////////////////////////////////
919 ///////////////////////////////////////////////////////////////////
921 * Encode all characters other than [a-zA-Z0-9] as %XX.
922 * This includes the % character itself, which becomes %25.
925 /** Encode all characters other than [a-zA-Z0-9] as %XX.
926 * This includes the % character itself, which becomes %25.
928 std::string hexencode( const C_Str & str_r );
929 /** Decode hexencoded %XX sequences. */
930 std::string hexdecode( const C_Str & str_r );
932 ///////////////////////////////////////////////////////////////////
934 /** \name Case conversion. */
936 /** Return lowercase version of \a s
939 std::string toLower( const std::string & s );
940 std::string toLower( std::string && s );
942 inline std::string toLower( const char * s )
943 { return( s ? toLower( std::string(s) ) : std::string() ); }
945 /** Return uppercase version of \a s
948 std::string toUpper( const std::string & s );
949 std::string toUpper( std::string && s );
951 inline std::string toUpper( const char * s )
952 { return( s ? toUpper( std::string(s) ) : std::string() ); }
956 /** \name Case insensitive comparison. */
958 inline int compareCI( const C_Str & lhs, const C_Str & rhs )
959 { return ::strcasecmp( lhs, rhs ); }
962 /** \name Locate substring. */
964 /** Locate substring case sensitive. */
965 inline bool contains( const C_Str & str_r, const C_Str & val_r )
966 { return ::strstr( str_r, val_r ); }
967 /** Locate substring case insensitive. */
968 inline bool containsCI( const C_Str & str_r, const C_Str & val_r )
969 { return ::strcasestr( str_r, val_r ); }
972 ///////////////////////////////////////////////////////////////////
973 /** \name Trimming whitepace.
974 * \todo optimize l/r trim.
977 /** To define how to trim. */
982 TRIM = (L_TRIM|R_TRIM)
985 std::string trim( const std::string & s, const Trim trim_r = TRIM );
986 std::string trim( std::string && s, const Trim trim_r = TRIM );
988 inline std::string ltrim( const std::string & s )
989 { return trim( s, L_TRIM ); }
990 inline std::string ltrim( std::string && s )
991 { return trim( std::move(s), L_TRIM ); }
993 inline std::string rtrim( const std::string & s )
994 { return trim( s, R_TRIM ); }
995 inline std::string rtrim( std::string && s )
996 { return trim( std::move(s), R_TRIM ); }
999 std::string stripFirstWord( std::string & line, const bool ltrim_first = true );
1001 std::string stripLastWord( std::string & line, const bool rtrim_first = true );
1003 /** Return stream content up to (but not returning) the next newline.
1004 * \see \ref receiveUpTo
1006 std::string getline( std::istream & str, bool trim = false );
1008 /** Return stream content up to (but not returning) the next newline.
1009 * \see \ref receiveUpTo
1011 std::string getline( std::istream & str, const Trim trim_r );
1013 /** Return stream content up to the next ocurrence of \c delim_r or EOF
1014 * \c delim_r, if found, is always read from the stream. Whether it is
1015 * also returned in the string depends on \c returnDelim_r.
1016 * If the stream status is \c good, \c delim_r was found in the stream.
1017 * If we reached EOF while looking for \c delim_r, \c eof is set; and
1018 * also \c fail, if we did not read any data before.
1020 std::string receiveUpTo( std::istream & str, const char delim_r, bool returnDelim_r = false );
1022 ///////////////////////////////////////////////////////////////////
1024 /** \name String prefix/suffix handling.
1027 /** Return whether \a str_r has prefix \a prefix_r. */
1028 inline bool hasPrefix( const C_Str & str_r, const C_Str & prefix_r )
1029 { return( ::strncmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
1030 /** \overload Case insensitive */
1031 inline bool hasPrefixCI( const C_Str & str_r, const C_Str & prefix_r )
1032 { return( ::strncasecmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
1034 /** Strip a \a prefix_r from \a str_r and return the resulting string. */
1035 inline std::string stripPrefix( const C_Str & str_r, const C_Str & prefix_r )
1036 { return( hasPrefix( str_r, prefix_r ) ? str_r + prefix_r.size() : str_r.c_str() ); }
1037 /** \overload Case insensitive */
1038 inline std::string stripPrefixCI( const C_Str & str_r, const C_Str & prefix_r )
1039 { return( hasPrefixCI( str_r, prefix_r ) ? str_r + prefix_r.size() : str_r.c_str() ); }
1041 /** Return whether \a str_r has suffix \a suffix_r. */
1042 inline bool hasSuffix( const C_Str & str_r, const C_Str & suffix_r )
1043 { return( str_r.size() >= suffix_r.size() && ::strncmp( str_r + str_r.size() - suffix_r.size() , suffix_r, suffix_r.size() ) == 0 ); }
1044 /** \overload Case insensitive */
1045 inline bool hasSuffixCI( const C_Str & str_r, const C_Str & suffix_r )
1046 { return( str_r.size() >= suffix_r.size() && ::strncasecmp( str_r + str_r.size() - suffix_r.size() , suffix_r, suffix_r.size() ) == 0 ); }
1048 /** Strip a \a suffix_r from \a str_r and return the resulting string. */
1049 inline std::string stripSuffix( const C_Str & str_r, const C_Str & suffix_r )
1051 if ( hasSuffix( str_r, suffix_r ) )
1052 return std::string( str_r, str_r.size() - suffix_r.size() );
1053 return str_r.c_str();
1055 /** \overload Case insensitive */
1056 inline std::string stripSuffixCI( const C_Str & str_r, const C_Str & suffix_r )
1058 if ( hasSuffixCI( str_r, suffix_r ) )
1059 return std::string( str_r, str_r.size() - suffix_r.size() );
1060 return str_r.c_str();
1063 /** Return size of the common prefix of \a lhs and \a rhs. */
1064 inline std::string::size_type commonPrefix( const C_Str & lhs, const C_Str & rhs )
1066 const char * lp = lhs.c_str();
1067 const char * rp = rhs.c_str();
1068 std::string::size_type ret = 0;
1069 while ( *lp == *rp && *lp != '\0' )
1070 { ++lp, ++rp, ++ret; }
1073 /** \overload Case insensitive */
1074 inline std::string::size_type commonPrefixCI( const C_Str & lhs, const C_Str & rhs )
1076 const char * lp = lhs.c_str();
1077 const char * rp = rhs.c_str();
1078 std::string::size_type ret = 0;
1079 while ( tolower(*lp) == tolower(*rp) && *lp != '\0' )
1080 { ++lp, ++rp, ++ret; }
1085 /** alias for \ref hasPrefix */
1086 inline bool startsWith( const C_Str & str_r, const C_Str & prefix_r )
1087 { return hasPrefix( str_r, prefix_r ); }
1088 /** \overload Case insensitive */
1089 inline bool startsWithCI( const C_Str & str_r, const C_Str & prefix_r )
1090 { return hasPrefixCI( str_r, prefix_r ); }
1092 /** alias for \ref hasSuffix */
1093 inline bool endsWith( const C_Str & str_r, const C_Str & prefix_r )
1094 { return hasSuffix( str_r, prefix_r ); }
1095 /** \overload Case insensitive */
1096 inline bool endsWithCI( const C_Str & str_r, const C_Str & prefix_r )
1097 { return hasSuffixCI( str_r, prefix_r ); }
1100 ///////////////////////////////////////////////////////////////////
1102 // drag into zypp:: namespace
1103 using str::asString;
1106 ///////////////////////////////////////////////////////////////////
1107 #endif // ZYPP_BASE_STRING_H