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.
241 /// \note It won't complain about malformed or incomplete format
242 /// strings. Usefull when dealing with translations or classes
243 /// providing a default formater.
245 /// void fnc( const std::string & txt_r );
246 /// fnc( str::Format("Hello %1%") % 13 );
248 /// std::string txt( str::Format("Hello %1%") % 13 );
250 ///////////////////////////////////////////////////////////////////
253 Format() { _fmter.exceptions( boost::io::no_error_bits ); }
254 Format( const std::string & format_r ) : Format() { _fmter.parse( format_r ); }
257 Format & operator%( Tp && arg )
258 { _fmter % std::forward<Tp>(arg); return *this; }
260 operator std::string() const { return _fmter.str(); }
261 std::string asString() const { return _fmter.str(); }
262 std::string str() const { return _fmter.str(); }
264 const boost::format & fmter() const { return _fmter; }
265 boost::format & fmter() { return _fmter; }
268 boost::format _fmter;
271 /** \relates Format Stream output */
272 inline std::ostream & operator<<( std::ostream & str, const Format & obj )
273 { return str << obj.fmter(); }
275 /** \name String representation of number.
277 * Optional second argument sets the minimal string width (' ' padded).
278 * Negative values will cause the number to be left adjusted within the string.
280 * Default width is 0.
282 * numstring(42) -> "42"
283 * numstring(42, 4) -> " 42"
284 * numstring(42,-4) -> "42 "
288 inline std::string numstring( char n, int w = 0 ) { return form( "%*hhd", w, n ); }
289 inline std::string numstring( unsigned char n, int w = 0 ) { return form( "%*hhu", w, n ); }
290 inline std::string numstring( short n, int w = 0 ) { return form( "%*hd", w, n ); }
291 inline std::string numstring( unsigned short n, int w = 0 ) { return form( "%*hu", w, n ); }
292 inline std::string numstring( int n, int w = 0 ) { return form( "%*d", w, n ); }
293 inline std::string numstring( unsigned n, int w = 0 ) { return form( "%*u", w, n ); }
294 inline std::string numstring( long n, int w = 0 ) { return form( "%*ld", w, n ); }
295 inline std::string numstring( unsigned long n, int w = 0 ) { return form( "%*lu", w, n ); }
296 inline std::string numstring( long long n, int w = 0 ) { return form( "%*lld", w, n ); }
297 inline std::string numstring( unsigned long long n, int w = 0 ) { return form( "%*llu", w, n ); }
299 template<> inline std::string asString( const char & t ) { return numstring( t ); }
300 template<> inline std::string asString( const unsigned char & t ) { return numstring( t ); }
301 template<> inline std::string asString( const short & t ) { return numstring( t ); }
302 template<> inline std::string asString( const unsigned short & t ) { return numstring( t ); }
303 template<> inline std::string asString( const int & t ) { return numstring( t ); }
304 template<> inline std::string asString( const unsigned & t ) { return numstring( t ); }
305 template<> inline std::string asString( const long & t ) { return numstring( t ); }
306 template<> inline std::string asString( const unsigned long & t ) { return numstring( t ); }
307 template<> inline std::string asString( const long long & t ) { return numstring( t ); }
308 template<> inline std::string asString( const unsigned long long & t ) { return numstring( t ); }
311 ///////////////////////////////////////////////////////////////////
312 /** \name String representation of number as hex value with leading '0x'.
313 * Optional second argument sets the minimal
314 * string width (0 padded). Negative values will cause the number to be left adjusted
315 * within the string. Default width is 10 (4 for char).
317 * hexstring(42) -> "0x0000002a"
318 * hexstring(42, 4) -> "0x2a"
319 * hexstring(42,-4) -> "0x2a"
323 inline std::string hexstring( char n, int w = 4 ) { return form( "%#0*hhx", w, n ); }
324 inline std::string hexstring( unsigned char n, int w = 4 ) { return form( "%#0*hhx", w, n ); }
325 inline std::string hexstring( short n, int w = 10 ){ return form( "%#0*hx", w, n ); }
326 inline std::string hexstring( unsigned short n, int w = 10 ){ return form( "%#0*hx", w, n ); }
327 inline std::string hexstring( int n, int w = 10 ){ return form( "%#0*x", w, n ); }
328 inline std::string hexstring( unsigned n, int w = 10 ){ return form( "%#0*x", w, n ); }
329 inline std::string hexstring( long n, int w = 10 ){ return form( "%#0*lx", w, n ); }
330 inline std::string hexstring( unsigned long n, int w = 10 ){ return form( "%#0*lx", w, n ); }
331 inline std::string hexstring( long long n, int w = 0 ) { return form( "%#0*llx", w, n ); }
332 inline std::string hexstring( unsigned long long n, int w = 0 ) { return form( "%#0*llx", w, n ); }
335 ///////////////////////////////////////////////////////////////////
336 /** \name String representation of number as octal value with leading '0'.
337 * Optional second argument sets the minimal
338 * string width (0 padded). Negative values will cause the number to be left adjusted
339 * within the string. Default width is 5 (4 for char).
341 * octstring(42) -> "00052"
342 * octstring(42, 4) -> "0052"
343 * octstring(42,-4) -> "052 "
347 inline std::string octstring( char n, int w = 4 ) { return form( "%#0*hho", w, n ); }
348 inline std::string octstring( unsigned char n, int w = 4 ) { return form( "%#0*hho", w, n ); }
349 inline std::string octstring( short n, int w = 5 ) { return form( "%#0*ho", w, n ); }
350 inline std::string octstring( unsigned short n, int w = 5 ) { return form( "%#0*ho", w, n ); }
351 inline std::string octstring( int n, int w = 5 ) { return form( "%#0*o", w, n ); }
352 inline std::string octstring( unsigned n, int w = 5 ) { return form( "%#0*o", w, n ); }
353 inline std::string octstring( long n, int w = 5 ) { return form( "%#0*lo", w, n ); }
354 inline std::string octstring( unsigned long n, int w = 5 ) { return form( "%#0*lo", w, n ); }
355 inline std::string octstring( long long n, int w = 0 ) { return form( "%#0*llo", w, n ); }
356 inline std::string octstring( unsigned long long n, int w = 0 ) { return form( "%#0*llo", w, n ); }
360 ///////////////////////////////////////////////////////////////////
361 /** String representation of number as bit-string with leading '0's. */
362 template <typename TInt>
363 std::string binstring( TInt val_r )
365 constexpr unsigned bits = sizeof(TInt)*8;
366 std::string ret( bits, ' ' );
368 for ( unsigned pos = bits; pos > 0; )
369 { --pos; ret[pos] = ((val_r & bit)?'1':'0'); bit = bit<<1; }
373 ///////////////////////////////////////////////////////////////////
374 /** Parsing numbers from string.
377 /** String to integer type determined by template arg.
378 * \note Only specializations are defined.
380 * time_t t = strtonum<time_t>( "42" );
383 template<typename TInt>
384 TInt strtonum( const C_Str & str );
387 inline short strtonum( const C_Str & str ) { return ::strtol ( str, NULL, 0 ); }
389 inline int strtonum( const C_Str & str ) { return ::strtol ( str, NULL, 0 ); }
391 inline long strtonum( const C_Str & str ) { return ::strtol ( str, NULL, 0 ); }
393 inline long long strtonum( const C_Str & str ) { return ::strtoll ( str, NULL, 0 ); }
396 inline unsigned short strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
398 inline unsigned strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
400 inline unsigned long strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
402 inline unsigned long long strtonum( const C_Str & str ) { return ::strtoull( str, NULL, 0 ); }
404 /** String to integer type detemined 2nd function arg \a i.
406 * time_t t; strtonum( "42", t );
409 template<typename TInt>
410 inline TInt strtonum( const C_Str & str, TInt & i )
411 { return i = strtonum<TInt>( str ); }
414 ///////////////////////////////////////////////////////////////////
415 /** Parsing boolean from string.
418 /** Return \c true if str is <tt>1, true, yes, on, always</tt> (or a nonzero number). */
419 bool strToTrue( const C_Str & str );
421 /** Return \c false if str is <tt>0, false, no, off, never</tt>. */
422 bool strToFalse( const C_Str & str );
424 /** Parse \c str into a bool depending on the default value.
425 * If the \c default is true, look for a legal \c false string.
426 * If the \c default is false, look for a legal \c true string.
428 inline bool strToBool( const C_Str & str, bool default_r )
429 { return( default_r ? strToFalse( str ) : strToTrue( str ) ); }
431 /** Parse \c str into a bool if it's a legal \c true or \c false string.
432 * If \c str is not a recognized \c true or \c false string, \a return_r
435 inline bool strToBoolNodefault( const C_Str & str, bool & return_r )
437 if ( strToTrue( str ) ) return (return_r = true);
438 if ( !strToFalse( str ) ) return (return_r = false);
442 /** Parse \c str into a bool if it's a legal \c true or \c false string; else \c indterminate. */
443 TriBool strToTriBool( const C_Str & str );
448 * \short Return a string with all occurrences of \c from_r replaced with \c to_r.
450 std::string gsub( const std::string & str_r, const std::string & from_r, const std::string & to_r );
452 /** \overload A function is called on demand to compute each replacement value.
454 std::string gsubFun( const std::string & str_r, const std::string & from_r, function<std::string()> to_r );
457 * \short Replace all occurrences of \c from_r with \c to_r in \c str_r (inplace).
458 * A reference to \c str_r is also returned for convenience.
460 std::string & replaceAll( std::string & str_r, const std::string & from_r, const std::string & to_r );
462 /** \overload A function is called on demand to compute each replacement value.
464 std::string & replaceAllFun( std::string & str_r, const std::string & from_r, function<std::string()> to_r );
466 /** Enhance readability: insert gaps at regular distance
469 * Key Fingerprint: 22C07BA534178CD02EFE22AAB88B2FD43DBDC284
471 * Key Fingerprint: 22C07BA5 34178CD0 2EFE22AA B88B2FD4 3DBDC284
473 * Key Fingerprint: 22C0 7BA5 3417 8CD0 2EFE 22AA B88B 2FD4 3DBD C284
475 * Key Fingerprint: 22C0-7BA5-3417-8CD0-2EFE-22AA-B88B-2FD4-3DBD-C284
478 inline std::string gapify( std::string inp_r, std::string::size_type gap_r = 1, char gapchar = ' ' )
480 if ( gap_r && inp_r.size() > gap_r )
482 inp_r.reserve( inp_r.size() + (inp_r.size()-1)/gap_r );
483 for ( std::string::size_type pos = gap_r; pos < inp_r.size(); pos += gap_r+1 )
484 inp_r.insert( pos, 1, gapchar );
489 ///////////////////////////////////////////////////////////////////
492 /** Split \a line_r into words.
493 * Any sequence of characters in \a sepchars_r is treated as
494 * delimiter. The words are passed to OutputIterator \a result_r.
496 * std::vector<std::string> words;
497 * str::split( "some line", std::back_inserter(words) )
501 template<class TOutputIterator>
502 unsigned split( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = " \t" )
504 const char * beg = line_r;
505 const char * cur = beg;
506 // skip leading sepchars
507 while ( *cur && ::strchr( sepchars_r, *cur ) )
510 for ( beg = cur; *beg; beg = cur, ++result_r, ++ret )
513 while( *cur && !::strchr( sepchars_r, *cur ) )
516 *result_r = std::string( beg, cur-beg );
518 while ( *cur && ::strchr( sepchars_r, *cur ) )
524 /** Split \a line_r into words with respect to escape delimeters.
525 * Any sequence of characters in \a sepchars_r is treated as
526 * delimiter if not inside \c "" or \c '' or escaped by \c \.
528 * \li A non-quoted backslash (\) preserves the literal value of the next character.
529 * \li Enclosing characters in single quotes preserves the literal value of each
530 * character within the quotes. A single quote may not occur between single
531 * quotes, even when preceded by a backslash.
532 * \li Enclosing characters in double quotes preserves the literal value of all
533 * characters within the quotes, with the exception of \c \. The backslash
534 * retains its special meaning only when followed by \c " or \c \.
536 * The words are passed to OutputIterator \a result_r.
538 * \see \ref splitEscaped
541 * std::vector<std::string> words;
542 * str::splitEscaped( "some line", std::back_inserter(words) )
546 * example splitted strings
547 * normal line -> 2 elements ( "normal", "line" )
548 * escaped\ line -> 1 element(escaped line)
549 * "quoted line" -> 1 element same as above
550 * 'quoted line' -> 1 element same as above
551 * "escaped quote\"" -> 1 element (escaped quote")
553 * \param line_r The string to parse.
555 * \param sepchars_r String of separator characters.
556 * \param withEmpty Whether to include empty fields between separators in the result.
560 template<class TOutputIterator>
561 unsigned splitEscaped( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = " \t", bool withEmpty = false)
563 const char * beg = line_r;
564 const char * cur = beg;
567 // skip leading sepchars
568 while ( *cur && ::strchr( sepchars_r, *cur ) )
578 // there were only sepchars in the string
579 if (!*cur && withEmpty)
585 // after the leading sepchars
586 enum class Quote { None, Slash, Single, Double, DoubleSlash };
587 std::vector<char> buf;
588 Quote quoting = Quote::None;
589 for ( beg = cur; *beg; beg = cur, ++result_r, ++ret )
591 // read next value until unquoted sepchar
593 quoting = Quote::None;
600 case '\\': quoting = Quote::Slash; break;
601 case '\'': quoting = Quote::Single; break;
602 case '"': quoting = Quote::Double; break;
603 default: buf.push_back( *cur ); break;
608 buf.push_back( *cur );
609 quoting = Quote::None;
615 case '\'': quoting = Quote::None; break;
616 default: buf.push_back( *cur ); break;
623 case '\"': quoting = Quote::None; break;
624 case '\\': quoting = Quote::DoubleSlash; break;
625 default: buf.push_back( *cur ); break;
629 case Quote::DoubleSlash:
632 case '\"': /*fallthrough*/
633 case '\\': buf.push_back( *cur ); break;
635 buf.push_back( '\\' );
636 buf.push_back( *cur );
639 quoting = Quote::Double;
643 } while ( *cur && ( quoting != Quote::None || !::strchr( sepchars_r, *cur ) ) );
644 *result_r = std::string( buf.begin(), buf.end() );
648 if ( *cur && ::strchr( sepchars_r, *cur ) )
650 while ( *cur && ::strchr( sepchars_r, *cur ) )
659 // the last was a separator => one more field
660 if ( !*cur && withEmpty && ::strchr( sepchars_r, *(cur-1) ) )
669 /** Split \a line_r into fields.
670 * Any single character in \a sepchars_r is treated as a
671 * field separator unless \-escaped. The words are passed
678 * ":a" -> words 2 ||a|
679 * "a:" -> words 2 |a||
680 * ":a:" -> words 3 ||a||
685 * std::vector<std::string> words;
686 * str::split( "some line", std::back_inserter(words) )
690 template<class TOutputIterator>
691 unsigned splitFields( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = ":" )
693 const char * beg = line_r;
694 const char * cur = beg;
696 for ( beg = cur; *beg; beg = cur, ++result_r )
699 while( *cur && !::strchr( sepchars_r, *cur ) )
701 if ( *cur == '\\' && *(cur+1) )
706 *result_r = std::string( beg, cur-beg );
712 if ( ! *cur ) // ending with sepchar
714 *result_r = std::string(); // add final empty field
724 * Split \a line_r into fields handling also escaped separators.
727 * \see splitEscaped()
729 template<class TOutputIterator>
730 unsigned splitFieldsEscaped( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = ":" )
732 return splitEscaped( line_r, result_r, sepchars_r, true /* withEmpty */ );
737 ///////////////////////////////////////////////////////////////////
740 /** Join strings using separator \a sep_r (defaults to BLANK). */
741 template <class TIterator>
742 std::string join( TIterator begin, TIterator end, const C_Str & sep_r = " " )
745 for ( TIterator iter = begin; iter != end; ++ iter )
749 res += asString(*iter);
754 /** Join strings using separator \a sep_r (defaults to BLANK). */
755 template <class TContainer>
756 std::string join( const TContainer & cont_r, const C_Str & sep_r = " " )
757 { return join( cont_r.begin(), cont_r.end(), sep_r ); }
759 /** Join strings using separator \a sep_r, quoting or escaping the values.
760 * Separator defaults to BLANK. Use \ref splitEscaped to restore the
763 template <class TIterator>
764 std::string joinEscaped( TIterator begin, TIterator end, const char sep_r = ' ' )
766 std::vector<char> buf;
767 for ( TIterator iter = begin; iter != end; ++ iter )
770 buf.push_back( sep_r );
774 // empty string goes ""
775 buf.push_back( '"' );
776 buf.push_back( '"' );
780 std::string toadd( asString(*iter) );
781 for_( ch, toadd.begin(), toadd.end() )
788 buf.push_back( '\\' );
789 buf.push_back( *ch );
793 buf.push_back( '\\' );
794 buf.push_back( *ch );
799 return std::string( buf.begin(), buf.end() );
804 ///////////////////////////////////////////////////////////////////
807 /** Indent by string [" "] optionally wrap.
808 * Prints nothing for an empty string. Asserts a trainling '\n' on
809 * the last line. Optionally wrap lines at ' ' at a given length.
811 inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, const std::string & indent_r = " ", unsigned maxWitdh_r = 0 )
815 if ( indent_r.size() >= maxWitdh_r )
816 maxWitdh_r = 0; // nonsense: indent larger than line witdh
818 maxWitdh_r -= indent_r.size();
821 for ( const char * e = text_r.c_str(), * s = e; *e; s = ++e )
823 for ( ; *e && *e != '\n'; ++e ) ;/*searching*/
825 if ( maxWitdh_r && width > maxWitdh_r )
829 for ( e = s+width; e > s && *e != ' '; --e ) ;/*searching*/
831 width = e-s; // on a ' ', replaced by '\n'
833 e = s+width-1; // cut line;
836 str.write( s, width );
838 if ( !*e ) // on '\0'
843 /** \overload Indent by number of chars [' '] optionally wrap. */
844 inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, unsigned indent_r, char indentch_r = ' ', unsigned maxWitdh_r = 0 )
845 { return printIndented( str, text_r, std::string( indent_r, indentch_r ), maxWitdh_r ); }
846 /** \overload Indent by number of chars [' '] wrap. */
847 inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, unsigned indent_r, unsigned maxWitdh_r, char indentch_r = ' ' )
848 { return printIndented( str, text_r, std::string( indent_r, indentch_r ), maxWitdh_r ); }
850 /** Prefix lines by string computed by function taking line begin/end [std::string(const char*, const char*)]
851 * Prints nothing for an empty string. Asserts a trainling '\n' on the last line.
853 inline std::ostream & autoPrefix( std::ostream & str, const std::string & text_r, function<std::string(const char*, const char*)> fnc_r )
855 for ( const char * e = text_r.c_str(); *e; ++e )
858 for ( ; *e && *e != '\n'; ++e ) /*searching*/;
859 str << fnc_r( s, e );
862 if ( !*e ) // on '\0'
867 /** \overload Prefix lines by string generated by function [std::string()] */
868 inline std::ostream & autoPrefix0( std::ostream & str, const std::string & text_r, function<std::string()> fnc_r )
870 auto wrap = [&fnc_r]( const char*, const char* )-> std::string {
873 return autoPrefix( str, text_r, wrap );
876 ///////////////////////////////////////////////////////////////////
880 * Escape desired character \a c using a backslash.
882 * For use when printing \a c separated values, and where
883 * \ref joinEscaped() is too heavy.
885 std::string escape( const C_Str & str_r, const char c = ' ' );
887 /** Escape \a next_r and append it to \a str_r using separator \a sep_r. */
888 inline void appendEscaped( std::string & str_r, const C_Str & next_r, const char sep_r = ' ' )
890 if ( ! str_r.empty() )
892 if ( next_r.empty() )
895 str_r += escape( next_r, sep_r );
898 /** Return \a str_r with '\'-escaped chars occurring in \a special_r (and '\'). */
899 std::string bEscape( std::string str_r, const C_Str & special_r );
901 /** Escape plain STRING \a str_r for use in a regex (not anchored by "^" or "$"). */
902 std::string rxEscapeStr( std::string str_r );
904 /** Escape GLOB \a str_r for use in a regex (not anchored by "^" or "$"). */
905 std::string rxEscapeGlob( std::string str_r );
910 ///////////////////////////////////////////////////////////////////
911 ///////////////////////////////////////////////////////////////////
913 * Encode all characters other than [a-zA-Z0-9] as %XX.
914 * This includes the % character itself, which becomes %25.
917 /** Encode all characters other than [a-zA-Z0-9] as %XX.
918 * This includes the % character itself, which becomes %25.
920 std::string hexencode( const C_Str & str_r );
921 /** Decode hexencoded %XX sequences. */
922 std::string hexdecode( const C_Str & str_r );
924 ///////////////////////////////////////////////////////////////////
926 /** \name Case conversion. */
928 /** Return lowercase version of \a s
931 std::string toLower( const std::string & s );
932 std::string toLower( std::string && s );
934 inline std::string toLower( const char * s )
935 { return( s ? toLower( std::string(s) ) : std::string() ); }
937 /** Return uppercase version of \a s
940 std::string toUpper( const std::string & s );
941 std::string toUpper( std::string && s );
943 inline std::string toUpper( const char * s )
944 { return( s ? toUpper( std::string(s) ) : std::string() ); }
948 /** \name Case insensitive comparison. */
950 inline int compareCI( const C_Str & lhs, const C_Str & rhs )
951 { return ::strcasecmp( lhs, rhs ); }
954 /** \name Locate substring. */
956 /** Locate substring case sensitive. */
957 inline bool contains( const C_Str & str_r, const C_Str & val_r )
958 { return ::strstr( str_r, val_r ); }
959 /** Locate substring case insensitive. */
960 inline bool containsCI( const C_Str & str_r, const C_Str & val_r )
961 { return ::strcasestr( str_r, val_r ); }
964 ///////////////////////////////////////////////////////////////////
965 /** \name Trimming whitepace.
966 * \todo optimize l/r trim.
969 /** To define how to trim. */
974 TRIM = (L_TRIM|R_TRIM)
977 std::string trim( const std::string & s, const Trim trim_r = TRIM );
978 std::string trim( std::string && s, const Trim trim_r = TRIM );
980 inline std::string ltrim( const std::string & s )
981 { return trim( s, L_TRIM ); }
982 inline std::string ltrim( std::string && s )
983 { return trim( std::move(s), L_TRIM ); }
985 inline std::string rtrim( const std::string & s )
986 { return trim( s, R_TRIM ); }
987 inline std::string rtrim( std::string && s )
988 { return trim( std::move(s), R_TRIM ); }
991 std::string stripFirstWord( std::string & line, const bool ltrim_first = true );
993 std::string stripLastWord( std::string & line, const bool rtrim_first = true );
995 /** Return stream content up to (but not returning) the next newline.
996 * \see \ref receiveUpTo
998 std::string getline( std::istream & str, bool trim = false );
1000 /** Return stream content up to (but not returning) the next newline.
1001 * \see \ref receiveUpTo
1003 std::string getline( std::istream & str, const Trim trim_r );
1005 /** Return stream content up to the next ocurrence of \c delim_r or EOF
1006 * \c delim_r, if found, is always read from the stream. Whether it is
1007 * also returned in the string depends on \c returnDelim_r.
1008 * If the stream status is \c good, \c delim_r was found in the stream.
1009 * If we reached EOF while looking for \c delim_r, \c eof is set; and
1010 * also \c fail, if we did not read any data before.
1012 std::string receiveUpTo( std::istream & str, const char delim_r, bool returnDelim_r = false );
1014 ///////////////////////////////////////////////////////////////////
1016 /** \name String prefix/suffix handling.
1019 /** Return whether \a str_r has prefix \a prefix_r. */
1020 inline bool hasPrefix( const C_Str & str_r, const C_Str & prefix_r )
1021 { return( ::strncmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
1022 /** \overload Case insensitive */
1023 inline bool hasPrefixCI( const C_Str & str_r, const C_Str & prefix_r )
1024 { return( ::strncasecmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
1026 /** Strip a \a prefix_r from \a str_r and return the resulting string. */
1027 inline std::string stripPrefix( const C_Str & str_r, const C_Str & prefix_r )
1028 { return( hasPrefix( str_r, prefix_r ) ? str_r + prefix_r.size() : str_r.c_str() ); }
1029 /** \overload Case insensitive */
1030 inline std::string stripPrefixCI( const C_Str & str_r, const C_Str & prefix_r )
1031 { return( hasPrefixCI( str_r, prefix_r ) ? str_r + prefix_r.size() : str_r.c_str() ); }
1033 /** Return whether \a str_r has suffix \a suffix_r. */
1034 inline bool hasSuffix( const C_Str & str_r, const C_Str & suffix_r )
1035 { return( str_r.size() >= suffix_r.size() && ::strncmp( str_r + str_r.size() - suffix_r.size() , suffix_r, suffix_r.size() ) == 0 ); }
1036 /** \overload Case insensitive */
1037 inline bool hasSuffixCI( const C_Str & str_r, const C_Str & suffix_r )
1038 { return( str_r.size() >= suffix_r.size() && ::strncasecmp( str_r + str_r.size() - suffix_r.size() , suffix_r, suffix_r.size() ) == 0 ); }
1040 /** Strip a \a suffix_r from \a str_r and return the resulting string. */
1041 inline std::string stripSuffix( const C_Str & str_r, const C_Str & suffix_r )
1043 if ( hasSuffix( str_r, suffix_r ) )
1044 return std::string( str_r, str_r.size() - suffix_r.size() );
1045 return str_r.c_str();
1047 /** \overload Case insensitive */
1048 inline std::string stripSuffixCI( const C_Str & str_r, const C_Str & suffix_r )
1050 if ( hasSuffixCI( str_r, suffix_r ) )
1051 return std::string( str_r, str_r.size() - suffix_r.size() );
1052 return str_r.c_str();
1055 /** Return size of the common prefix of \a lhs and \a rhs. */
1056 inline std::string::size_type commonPrefix( const C_Str & lhs, const C_Str & rhs )
1058 const char * lp = lhs.c_str();
1059 const char * rp = rhs.c_str();
1060 std::string::size_type ret = 0;
1061 while ( *lp == *rp && *lp != '\0' )
1062 { ++lp, ++rp, ++ret; }
1065 /** \overload Case insensitive */
1066 inline std::string::size_type commonPrefixCI( const C_Str & lhs, const C_Str & rhs )
1068 const char * lp = lhs.c_str();
1069 const char * rp = rhs.c_str();
1070 std::string::size_type ret = 0;
1071 while ( tolower(*lp) == tolower(*rp) && *lp != '\0' )
1072 { ++lp, ++rp, ++ret; }
1077 /** alias for \ref hasPrefix */
1078 inline bool startsWith( const C_Str & str_r, const C_Str & prefix_r )
1079 { return hasPrefix( str_r, prefix_r ); }
1080 /** \overload Case insensitive */
1081 inline bool startsWithCI( const C_Str & str_r, const C_Str & prefix_r )
1082 { return hasPrefixCI( str_r, prefix_r ); }
1084 /** alias for \ref hasSuffix */
1085 inline bool endsWith( const C_Str & str_r, const C_Str & prefix_r )
1086 { return hasSuffix( str_r, prefix_r ); }
1087 /** \overload Case insensitive */
1088 inline bool endsWithCI( const C_Str & str_r, const C_Str & prefix_r )
1089 { return hasSuffixCI( str_r, prefix_r ); }
1092 ///////////////////////////////////////////////////////////////////
1094 // drag into zypp:: namespace
1095 using str::asString;
1098 ///////////////////////////////////////////////////////////////////
1099 #endif // ZYPP_BASE_STRING_H