Imported Upstream version 15.0.0
[platform/upstream/libzypp.git] / zypp / base / String.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/String.h
10  *
11 */
12 #ifndef ZYPP_BASE_STRING_H
13 #define ZYPP_BASE_STRING_H
14
15 #include <cstring>
16
17 #include <iosfwd>
18 #include <vector>
19 #include <string>
20 #include <sstream>
21 #include <boost/format.hpp>
22
23 #include "zypp/base/Easy.h"
24 #include "zypp/base/PtrTypes.h"
25 #include "zypp/base/Function.h"
26
27
28 ///////////////////////////////////////////////////////////////////
29 namespace boost
30 {
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
34    * default formater.
35    */
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 ) );
40     return fmter;
41   }
42 } // namespace boost
43 namespace zypp { using boost::formatNAC; }
44 ///////////////////////////////////////////////////////////////////
45
46 ///////////////////////////////////////////////////////////////////
47 namespace zypp
48 {
49   /** Request a human readable (translated) string representation of _Tp [_Tp.asUserString()]
50    * Classes may implement a default as member function.
51    */
52   template <class _Tp>
53   std::string asUserString( const _Tp & val_r )
54   { return val_r.asUserString(); }
55
56 }// namespace zypp
57 ///////////////////////////////////////////////////////////////////
58
59 ///////////////////////////////////////////////////////////////////
60 namespace zypp
61 { /////////////////////////////////////////////////////////////////
62
63   struct MessageString : public std::string
64   {
65     MessageString() {}
66     MessageString( const char * str_r )                 : std::string( str_r ? str_r : "" ) {}
67     MessageString( const std::string & str_r )          : std::string( str_r ) {}
68     // boost::format, std::ostringstream, str::Str ...
69     template<class _Str>
70     MessageString( const _Str & str_r ) : std::string( str_r.str() ) {}
71   };
72
73   /** Convenience \c char* constructible from \c std::string and \c char*,
74    *  it maps \c (char*)0 to an empty string.
75    *
76    * \code
77    * bool hasPrefix( const std::string & str_r, const std::string & prefix_r )
78    * { return( ::strncmp( str_r.c_str(), prefix_r.c_str(), prefix_r.size() ) == 0 ); }
79    * \endcode
80    *
81    * Called with a plain \c char* as argument, the \c std::string is created form
82    * for nothing. The implementation actually does not use the \c std::string.
83    *
84    * Best would be to implement \c hasPrefix for each combination of \c char*
85    * and \c std::string arguments:
86    *
87    * \code
88    * bool hasPrefix( const std::string & str_r, const std::string & prefix_r )
89    * { return( ::strncmp( str_r.c_str(), prefix_r.c_str(), prefix_r.size() ) == 0 ); }
90    *
91    * bool hasPrefix( const std::string & str_r, const char * prefix_r )
92    * { return( !prefix_r || ::strncmp( str_r.c_str(), prefix_r, ::strlen(prefix_r) ) == 0 ); }
93    *
94    * bool hasPrefix( const char * str_r, const std::string & prefix_r )
95    * { return( str_r ? ::strncmp( str_r, prefix_r.c_str(), prefix_r.size() ) == 0 : prefix_r.empty() ); }
96    *
97    * bool hasPrefix( const char * str_r, const char * prefix_r )
98    * { return( str && prefix_r ? ::strncmp( str_r, prefix_r, ::strlen(prefix_r) ) == 0
99    *                           : !((str_r && *str_r) || (prefix_r && *prefix_r)); }
100    * \endcode
101    *
102    * This is where \ref C_Str can help. Constructible from \c std::string and \c char*,
103    * it \e reduces the \c std::string to it's \c char*. At the same time it converts
104    * \c (char*)0 into an \c "" string.
105    *
106    * \code
107    * bool hasPrefix( const C_Str & str_r, const C_Str & prefix_r )
108    * { return( ::strncmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
109    * \endcode
110    */
111   class C_Str
112   {
113     public:
114       typedef std::string::size_type size_type;
115
116     public:
117       C_Str()                            : _val( 0 ),             _sze( 0 ) {}
118       C_Str( char * c_str_r )            : _val( c_str_r ),       _sze( std::string::npos ) {}
119       C_Str( const char * c_str_r )      : _val( c_str_r ),       _sze( std::string::npos ) {}
120       C_Str( const std::string & str_r ) : _val( str_r.c_str() ), _sze( str_r.size() ) {}
121
122     public:
123       bool      isNull()       const { return !_val; }
124       bool      empty()        const { return !(_val && *_val); }
125       size_type size()         const
126       {
127         if ( _sze == std::string::npos )
128         { _sze = _val ? ::strlen( _val ) : 0; }
129         return _sze;
130       };
131
132       operator const char *() const { return c_str(); }
133       const char * c_str()    const { return _val ? _val : ""; }
134
135     private:
136       const char *const _val;
137       mutable size_type _sze;
138   };
139
140   /** \relates C_Str Stream output */
141   inline std::ostream & operator<<( std::ostream & str, const C_Str & obj )
142   { return str << obj.c_str(); }
143
144   ///////////////////////////////////////////////////////////////////
145   /** String related utilities and \ref ZYPP_STR_REGEX.
146    \see \ref ZYPP_STR_REGEX
147   */
148
149   namespace str
150   { /////////////////////////////////////////////////////////////////
151
152     ///////////////////////////////////////////////////////////////////
153     /**
154      * Global asString() that works with std::string too
155      */
156     inline std::string asString( const std::string &t )
157     { return t; }
158
159 #ifndef SWIG // Swig treats it as syntax error
160     inline std::string asString( std::string && t )
161     { return std::move(t); }
162 #endif
163
164     inline std::string asString( const char * t )
165     { return t; }
166
167     inline std::string asString( char * t )
168     { return t; }
169
170     template<class _T>
171         inline std::string asString( const _T &t )
172         { return t.asString(); }
173
174     template<class _T>
175         inline std::string asString( const intrusive_ptr<_T> &p )
176         { return p->asString(); }
177
178     template<class _T>
179         inline std::string asString( const weak_ptr<_T> &p )
180         { return p->asString(); }
181
182     template<>
183         inline std::string asString( const bool &t )
184         { return t ? "true" : "false"; }
185
186     ///////////////////////////////////////////////////////////////////
187     /** Printf style construction of std::string. */
188     std::string form( const char * format, ... )
189     __attribute__ ((format (printf, 1, 2)));
190
191     ///////////////////////////////////////////////////////////////////
192     /** Return string describing the \a error_r code.
193      * Like ::strerror, but the numerical value is included in
194      * the string as well.
195     */
196     std::string strerror( int errno_r );
197
198     ///////////////////////////////////////////////////////////////////
199     /** Assert \c free called for allocated <tt>char *</tt>.
200      * \code
201      * ...
202      * SafeBuf safe;
203      * vasprintf( &safe._buf, format, ap );
204      * return safe.asString();
205      * \endcode
206      *
207      * \ingroup g_RAII
208     */
209     struct SafeBuf
210     {
211       char * _buf;
212       SafeBuf() : _buf( 0 ) {}
213       ~SafeBuf() { if ( _buf ) free( _buf ); }
214       std::string asString() const
215       { return _buf ? std::string(_buf) : std::string(); }
216     };
217
218     ///////////////////////////////////////////////////////////////////
219     /** Convenient building of std::string via std::ostream::operator<<.
220      * Basically this is an \ref ostringstream which is autocenvertible
221      * into a \ref string.
222      * \code
223      *  void fnc( const std::string & txt_r );
224      *  fnc( str::Str() << "Hello " << 13 );
225      *
226      *  std::string txt( str::Str() << 45 );
227      * \endcode
228     */
229     struct Str
230     {
231       template<class _Tp>
232       Str & operator<<( const _Tp & val )
233       { _str << val; return *this; }
234
235       operator std::string() const
236       { return _str.str(); }
237
238       std::string str() const
239       { return _str.str(); }
240
241       std::ostream & stream()
242       { return _str; }
243
244       void clear()
245       { _str.str( std::string() ); }
246
247       std::ostringstream _str;
248     };
249
250     inline std::ostream & operator<<( std::ostream & str, const Str & obj )
251     { return str << (std::string)obj; }
252
253     ///////////////////////////////////////////////////////////////////
254     /** \name String representation of number.
255      *
256      * Optional second argument sets the minimal string width (' ' padded).
257      * Negative values will cause the number to be left adjusted within the string.
258      *
259      * Default width is 0.
260      * \code
261      * numstring(42)           -> "42"
262      * numstring(42, 4)        -> "  42"
263      * numstring(42,-4)        -> "42  "
264      * \endcode
265      **/
266     //@{
267     inline std::string numstring( char n,               int w = 0 ) { return form( "%*hhd",  w, n ); }
268     inline std::string numstring( unsigned char n,      int w = 0 ) { return form( "%*hhu",  w, n ); }
269     inline std::string numstring( short n,              int w = 0 ) { return form( "%*hd",   w, n ); }
270     inline std::string numstring( unsigned short n,     int w = 0 ) { return form( "%*hu",   w, n ); }
271     inline std::string numstring( int n,                int w = 0 ) { return form( "%*d",    w, n ); }
272     inline std::string numstring( unsigned n,           int w = 0 ) { return form( "%*u",    w, n ); }
273     inline std::string numstring( long n,               int w = 0 ) { return form( "%*ld",   w, n ); }
274     inline std::string numstring( unsigned long n,      int w = 0 ) { return form( "%*lu",   w, n ); }
275     inline std::string numstring( long long n,          int w = 0 ) { return form( "%*lld",  w, n ); }
276     inline std::string numstring( unsigned long long n, int w = 0 ) { return form( "%*llu",  w, n ); }
277
278     template<> inline std::string asString( const char & t )                    { return numstring( t ); }
279     template<> inline std::string asString( const unsigned char & t )           { return numstring( t ); }
280     template<> inline std::string asString( const short & t )                   { return numstring( t ); }
281     template<> inline std::string asString( const unsigned short & t )          { return numstring( t ); }
282     template<> inline std::string asString( const int & t )                     { return numstring( t ); }
283     template<> inline std::string asString( const unsigned & t )                { return numstring( t ); }
284     template<> inline std::string asString( const long & t )                    { return numstring( t ); }
285     template<> inline std::string asString( const unsigned long & t )           { return numstring( t ); }
286     template<> inline std::string asString( const long long & t )               { return numstring( t ); }
287     template<> inline std::string asString( const unsigned long long & t )      { return numstring( t ); }
288     //@}
289
290     ///////////////////////////////////////////////////////////////////
291     /** \name String representation of number as hex value with leading '0x'.
292      * Optional second argument sets the minimal
293      * string width (0 padded). Negative values will cause the number to be left adjusted
294      * within the string. Default width is 10 (4 for char).
295      * <PRE>
296      * hexstring(42)           -> "0x0000002a"
297      * hexstring(42, 4)        -> "0x2a"
298      * hexstring(42,-4)        -> "0x2a"
299      * </PRE>
300      **/
301     //@{
302     inline std::string hexstring( char n,               int w = 4 ) { return form( "%#0*hhx", w, n ); }
303     inline std::string hexstring( unsigned char n,      int w = 4 ) { return form( "%#0*hhx", w, n ); }
304     inline std::string hexstring( short n,              int w = 10 ){ return form( "%#0*hx",  w, n ); }
305     inline std::string hexstring( unsigned short n,     int w = 10 ){ return form( "%#0*hx",  w, n ); }
306     inline std::string hexstring( int n,                int w = 10 ){ return form( "%#0*x",   w, n ); }
307     inline std::string hexstring( unsigned n,           int w = 10 ){ return form( "%#0*x",   w, n ); }
308     inline std::string hexstring( long n,               int w = 10 ){ return form( "%#0*lx",  w, n ); }
309     inline std::string hexstring( unsigned long n,      int w = 10 ){ return form( "%#0*lx",  w, n ); }
310     inline std::string hexstring( long long n,          int w = 0 ) { return form( "%#0*llx", w, n ); }
311     inline std::string hexstring( unsigned long long n, int w = 0 ) { return form( "%#0*llx", w, n ); }
312     //@}
313
314     ///////////////////////////////////////////////////////////////////
315     /** \name String representation of number as octal value with leading '0'.
316      * Optional second argument sets the minimal
317      * string width (0 padded). Negative values will cause the number to be left adjusted
318      * within the string. Default width is 5 (4 for char).
319      * <PRE>
320      * octstring(42)           -> "00052"
321      * octstring(42, 4)        -> "0052"
322      * octstring(42,-4)        -> "052 "
323      * </PRE>
324      **/
325     //@{
326     inline std::string octstring( char n,               int w = 4 ) { return form( "%#0*hho",  w, n ); }
327     inline std::string octstring( unsigned char n,      int w = 4 ) { return form( "%#0*hho",  w, n ); }
328     inline std::string octstring( short n,              int w = 5 ) { return form( "%#0*ho",   w, n ); }
329     inline std::string octstring( unsigned short n,     int w = 5 ) { return form( "%#0*ho",   w, n ); }
330     inline std::string octstring( int n,                int w = 5 ) { return form( "%#0*o",    w, n ); }
331     inline std::string octstring( unsigned n,           int w = 5 ) { return form( "%#0*o",    w, n ); }
332     inline std::string octstring( long n,               int w = 5 ) { return form( "%#0*lo",   w, n ); }
333     inline std::string octstring( unsigned long n,      int w = 5 ) { return form( "%#0*lo",   w, n ); }
334     inline std::string octstring( long long n,          int w = 0 ) { return form( "%#0*llo",  w, n ); }
335     inline std::string octstring( unsigned long long n, int w = 0 ) { return form( "%#0*llo",  w, n ); }
336     //@}
337
338     ///////////////////////////////////////////////////////////////////
339     /** Parsing numbers from string.
340     */
341     //@{
342     /** String to integer type determined by template arg.
343      * \note Only specializations are defined.
344      * \code
345      * time_t t = strtonum<time_t>( "42" );
346      * \endcode
347     */
348     template<typename _It>
349       _It strtonum( const C_Str & str );
350
351     template<>
352       inline short              strtonum( const C_Str & str ) { return ::strtol  ( str, NULL, 0 ); }
353     template<>
354       inline int                strtonum( const C_Str & str ) { return ::strtol  ( str, NULL, 0 ); }
355     template<>
356       inline long               strtonum( const C_Str & str ) { return ::strtol  ( str, NULL, 0 ); }
357     template<>
358       inline long long          strtonum( const C_Str & str ) { return ::strtoll ( str, NULL, 0 ); }
359
360     template<>
361       inline unsigned short     strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
362     template<>
363       inline unsigned           strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
364     template<>
365       inline unsigned long      strtonum( const C_Str & str ) { return ::strtoul ( str, NULL, 0 ); }
366     template<>
367       inline unsigned long long strtonum( const C_Str & str ) { return ::strtoull( str, NULL, 0 ); }
368
369     /** String to integer type detemined 2nd function arg \a i.
370      * \code
371      * time_t t; strtonum( "42", t );
372      * \endcode
373     */
374     template<typename _It>
375       inline _It strtonum( const C_Str & str, _It & i )
376       { return i = strtonum<_It>( str ); }
377     //@}
378
379     ///////////////////////////////////////////////////////////////////
380     /** Parsing boolean from string.
381     */
382     //@{
383     /** Return \c true if str is <tt>1, true, yes, on</tt> (or a nonzero number). */
384     bool strToTrue( const C_Str & str );
385
386     /** Return \c false if str is <tt>0, false, no, off</tt>. */
387     bool strToFalse( const C_Str & str );
388
389     /** Parse \c str into a bool depending on the default value.
390      * If the \c default is true, look for a legal \c false string.
391      * If the \c default is false, look for a legal \c true string.
392      */
393     inline bool strToBool( const C_Str & str, bool default_r )
394     { return( default_r ? strToFalse( str ) : strToTrue( str ) ); }
395
396     /** Parse \c str into a bool if it's a legal \c true or \c false string.
397      * If \c str is not a recognized \c true or \c false string, \a return_r
398      * is left unchanged.
399      */
400     inline bool strToBoolNodefault( const C_Str & str, bool & return_r )
401     {
402       if ( strToTrue( str ) ) return (return_r = true);
403       if ( !strToFalse( str ) ) return (return_r = false);
404       return return_r;
405     }
406
407     //@}
408
409     /**
410      * \short Return a string with all occurrences of \c from_r replaced with \c to_r.
411      */
412     std::string gsub( const std::string & str_r, const std::string & from_r, const std::string & to_r );
413
414     /** \overload A function is called on demand to compute each replacement value.
415      */
416     std::string gsubFun( const std::string & str_r, const std::string & from_r, function<std::string()> to_r );
417
418     /**
419      * \short Replace all occurrences of \c from_r with \c to_r in \c str_r (inplace).
420      * A reference to \c str_r is also returned for convenience.
421      */
422     std::string & replaceAll( std::string & str_r, const std::string & from_r, const std::string & to_r );
423
424     /** \overload A function is called on demand to compute each replacement value.
425      */
426     std::string & replaceAllFun( std::string & str_r, const std::string & from_r, function<std::string()> to_r );
427
428     /** Enhance readability: insert gaps at regular distance
429      * \code
430      *   // no gaps
431      *   Key Fingerprint:  22C07BA534178CD02EFE22AAB88B2FD43DBDC284
432      *   // gapify 8
433      *   Key Fingerprint:  22C07BA5 34178CD0 2EFE22AA B88B2FD4 3DBDC284
434      *   // gapify 4
435      *   Key Fingerprint:  22C0 7BA5 3417 8CD0 2EFE 22AA B88B 2FD4 3DBD C284
436      *   // gapify 4, '-'
437      *   Key Fingerprint:  22C0-7BA5-3417-8CD0-2EFE-22AA-B88B-2FD4-3DBD-C284
438      * \endcode
439      */
440     inline std::string gapify( std::string inp_r, std::string::size_type gap_r = 1, char gapchar = ' ' )
441     {
442       if ( gap_r &&  inp_r.size() > gap_r )
443       {
444         inp_r.reserve( inp_r.size() + (inp_r.size()-1)/gap_r );
445         for ( std::string::size_type pos = gap_r; pos < inp_r.size(); pos += gap_r+1 )
446           inp_r.insert( pos, 1, gapchar );
447       }
448       return inp_r;
449     }
450
451     ///////////////////////////////////////////////////////////////////
452     /** \name Split. */
453     //@{
454     /** Split \a line_r into words.
455      * Any sequence of characters in \a sepchars_r is treated as
456      * delimiter. The words are passed to OutputIterator \a result_r.
457      * \code
458      * std::vector<std::string> words;
459      * str::split( "some line", std::back_inserter(words) )
460      * \endcode
461      *
462     */
463     template<class _OutputIterator>
464       unsigned split( const C_Str &   line_r,
465                       _OutputIterator result_r,
466                       const C_Str &   sepchars_r = " \t" )
467       {
468         const char * beg = line_r;
469         const char * cur = beg;
470         // skip leading sepchars
471         while ( *cur && ::strchr( sepchars_r, *cur ) )
472           ++cur;
473         unsigned ret = 0;
474         for ( beg = cur; *beg; beg = cur, ++result_r, ++ret )
475           {
476             // skip non sepchars
477             while( *cur && !::strchr( sepchars_r, *cur ) )
478               ++cur;
479             // build string
480             *result_r = std::string( beg, cur-beg );
481             // skip sepchars
482             while ( *cur && ::strchr( sepchars_r, *cur ) )
483               ++cur;
484           }
485         return ret;
486       }
487
488     /** Split \a line_r into words with respect to escape delimeters.
489      * Any sequence of characters in \a sepchars_r is treated as
490      * delimiter if not inside \c "" or \c '' or escaped by \c \.
491      *
492      * \li A non-quoted backslash (\) preserves the literal value of the next character.
493      * \li Enclosing characters in single quotes preserves the literal value of each
494      *     character within the quotes.  A single quote may not occur between single
495      *     quotes, even when preceded by a backslash.
496      * \li Enclosing characters in double quotes preserves the literal value of all
497      *     characters within the quotes, with the exception of \c \. The backslash
498      *     retains its special meaning only when followed by \c " or \c \.
499      *
500      * The words are passed to OutputIterator \a result_r.
501      *
502      * \see \ref splitEscaped
503      *
504      * \code
505      * std::vector<std::string> words;
506      * str::splitEscaped( "some line", std::back_inserter(words) )
507      * \endcode
508      *
509      * \code
510      * example splitted strings
511      * normal line -> 2 elements ( "normal", "line" )
512      * escaped\ line -> 1 element(escaped line)
513      * "quoted line" -> 1 element same as above
514      * 'quoted line' -> 1 element same as above
515      * "escaped quote\"" -> 1 element (escaped quote")
516      *
517      * \param line_r   The string to parse.
518      * \param result_r
519      * \param sepchars_r  String of separator characters.
520      * \param withEmpty   Whether to include empty fields between separators in the result.
521      *
522      * \endcode
523      */
524     template<class _OutputIterator>
525       unsigned splitEscaped( const C_Str &   line_r,
526                       _OutputIterator result_r,
527                       const C_Str &   sepchars_r = " \t",
528                       bool withEmpty = false)
529       {
530         const char * beg = line_r;
531         const char * cur = beg;
532         unsigned ret = 0;
533
534         // skip leading sepchars
535         while ( *cur && ::strchr( sepchars_r, *cur ) )
536         {
537           ++cur;
538           if (withEmpty)
539           {
540             *result_r = "";
541             ++ret;
542           }
543         }
544
545         // there were only sepchars in the string
546         if (!*cur && withEmpty)
547         {
548           *result_r = "";
549           return ++ret;
550         }
551
552         // after the leading sepchars
553         enum class Quote { None, Slash, Single, Double, DoubleSlash };
554         std::vector<char> buf;
555         Quote quoting = Quote::None;
556         for ( beg = cur; *beg; beg = cur, ++result_r, ++ret )
557         {
558           // read next value until unquoted sepchar
559           buf.clear();
560           quoting = Quote::None;
561           do {
562             switch ( quoting )
563             {
564               case Quote::None:
565                 switch ( *cur )
566                 {
567                   case '\\':    quoting = Quote::Slash;         break;
568                   case '\'':    quoting = Quote::Single;        break;
569                   case '"':     quoting = Quote::Double;        break;
570                   default:      buf.push_back( *cur );          break;
571                 }
572                 break;
573
574               case Quote::Slash:
575                 buf.push_back( *cur );
576                 quoting = Quote::None;
577                 break;
578
579               case Quote::Single:
580                 switch ( *cur )
581                 {
582                   case '\'':    quoting = Quote::None;          break;
583                   default:      buf.push_back( *cur );          break;
584                 }
585                 break;
586
587               case Quote::Double:
588                 switch ( *cur )
589                 {
590                   case '\"':    quoting = Quote::None;          break;
591                   case '\\':    quoting = Quote::DoubleSlash;   break;
592                   default:      buf.push_back( *cur );          break;
593                 }
594                 break;
595
596               case Quote::DoubleSlash:
597                 switch ( *cur )
598                 {
599                   case '\"':    /*fallthrough*/
600                   case '\\':    buf.push_back( *cur );          break;
601                   default:
602                     buf.push_back( '\\' );
603                     buf.push_back( *cur );
604                     break;
605                 }
606                 quoting = Quote::Double;
607                 break;
608             }
609             ++cur;
610           } while ( *cur && ( quoting != Quote::None || !::strchr( sepchars_r, *cur ) ) );
611           *result_r = std::string( buf.begin(), buf.end() );
612
613
614           // skip sepchars
615           if ( *cur && ::strchr( sepchars_r, *cur ) )
616             ++cur;
617           while ( *cur && ::strchr( sepchars_r, *cur ) )
618           {
619             ++cur;
620             if (withEmpty)
621             {
622               *result_r = "";
623               ++ret;
624             }
625           }
626           // the last was a separator => one more field
627           if ( !*cur && withEmpty && ::strchr( sepchars_r, *(cur-1) ) )
628           {
629             *result_r = "";
630             ++ret;
631           }
632         }
633         return ret;
634       }
635
636     /** Split \a line_r into fields.
637      * Any single character in \a sepchars_r is treated as a
638      * field separator unless \-escaped. The words are passed
639      * to OutputIterator.
640      * \a result_r.
641      * \code
642      * ""        -> words 0
643      * ":"       -> words 2  |||
644      * "a"       -> words 1  |a|
645      * ":a"      -> words 2  ||a|
646      * "a:"      -> words 2  |a||
647      * ":a:"     -> words 3  ||a||
648      *
649      * \endcode
650      *
651      * \code
652      * std::vector<std::string> words;
653      * str::split( "some line", std::back_inserter(words) )
654      * \endcode
655      *
656     */
657     template<class _OutputIterator>
658       unsigned splitFields( const C_Str &   line_r,
659                             _OutputIterator result_r,
660                             const C_Str &   sepchars_r = ":" )
661       {
662         const char * beg = line_r;
663         const char * cur = beg;
664         unsigned ret = 0;
665         for ( beg = cur; *beg; beg = cur, ++result_r )
666           {
667             // skip non sepchars
668             while( *cur && !::strchr( sepchars_r, *cur ) )
669             {
670               if ( *cur == '\\' && *(cur+1) )
671                 ++cur;
672               ++cur;
673             }
674             // build string
675             *result_r = std::string( beg, cur-beg );
676             ++ret;
677             // skip sepchar
678             if ( *cur )
679             {
680               ++cur;
681               if ( ! *cur )                // ending with sepchar
682               {
683                 *result_r = std::string(); // add final empty field
684                 ++ret;
685                 break;
686               }
687             }
688           }
689         return ret;
690       }
691
692     /**
693      * Split \a line_r into fields handling also escaped separators.
694      *
695      * \see splitFields()
696      * \see splitEscaped()
697      */
698     template<class _OutputIterator>
699       unsigned splitFieldsEscaped( const C_Str &   line_r,
700                             _OutputIterator result_r,
701                             const C_Str &   sepchars_r = ":" )
702       {
703         return
704           splitEscaped( line_r, result_r, sepchars_r, true /* withEmpty */ );
705       }
706
707     //@}
708
709     ///////////////////////////////////////////////////////////////////
710     /** \name Join. */
711     //@{
712     /** Join strings using separator \a sep_r (defaults to BLANK). */
713     template <class _Iterator>
714       std::string join( _Iterator begin, _Iterator end,
715                         const C_Str & sep_r = " " )
716       {
717         std::string res;
718         for ( _Iterator iter = begin; iter != end; ++ iter )
719           {
720             if ( iter != begin )
721               res += sep_r;
722             res += asString(*iter);
723           }
724         return res;
725       }
726
727     /** Join strings using separator \a sep_r (defaults to BLANK). */
728     template <class _Container>
729       std::string join( const _Container & cont_r,
730                         const C_Str & sep_r = " " )
731       { return join( cont_r.begin(), cont_r.end(), sep_r ); }
732
733     /** Join strings using separator \a sep_r, quoting or escaping the values.
734      * Separator defaults to BLANK. Use \ref splitEscaped to restore the
735      * values.
736      */
737     template <class _Iterator>
738       std::string joinEscaped( _Iterator begin, _Iterator end,
739                                const char sep_r = ' ' )
740       {
741         std::vector<char> buf;
742         for ( _Iterator iter = begin; iter != end; ++ iter )
743         {
744           if ( iter != begin )
745             buf.push_back( sep_r );
746
747           if ( iter->empty() )
748           {
749             // empty string goes ""
750             buf.push_back( '"' );
751             buf.push_back( '"' );
752           }
753           else
754           {
755             std::string toadd( asString(*iter) );
756             for_( ch, toadd.begin(), toadd.end() )
757             {
758               switch ( *ch )
759               {
760                 case '"':
761                 case '\'':
762                 case '\\':
763                   buf.push_back( '\\' );
764                   buf.push_back( *ch );
765                   break;
766                 default:
767                   if ( *ch == sep_r )
768                     buf.push_back( '\\' );
769                   buf.push_back( *ch );
770               }
771             }
772           }
773         }
774         return std::string( buf.begin(), buf.end() );
775       }
776     //@}
777
778
779     ///////////////////////////////////////////////////////////////////
780     /** \name Indent. */
781     //@{
782       /** Indent by string ["  "] optionally wrap.
783        * Prints nothing for an empty string. Asserts a trainling '\n' on
784        * the last line. Optionally wrap lines at ' ' at a given length.
785        */
786       inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, const std::string & indent_r = "  ", unsigned maxWitdh_r = 0 )
787       {
788         if ( maxWitdh_r )
789         {
790           if ( indent_r.size() >= maxWitdh_r )
791             maxWitdh_r = 0;     // nonsense: indent larger than line witdh
792           else
793             maxWitdh_r -= indent_r.size();
794         }
795         unsigned width = 0;
796         for ( const char * e = text_r.c_str(), * s = e; *e; s = ++e )
797         {
798           for ( ; *e && *e != '\n'; ++e ) ;/*searching*/
799           width = e-s;
800           if ( maxWitdh_r && width > maxWitdh_r )
801           {
802             // must break line
803             width = maxWitdh_r;
804             for ( e = s+width; e > s && *e != ' '; --e ) ;/*searching*/
805             if ( e > s )
806               width = e-s;      // on a ' ', replaced by '\n'
807             else
808               e = s+width-1;    // cut line;
809           }
810           str << indent_r;
811           str.write( s, width );
812           str << "\n";
813           if ( !*e )    // on '\0'
814             break;
815         }
816         return str;
817       }
818       /** \overload Indent by number of chars [' '] optionally wrap. */
819       inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, unsigned indent_r, char indentch_r = ' ', unsigned maxWitdh_r = 0 )
820       { return printIndented( str, text_r, std::string( indent_r, indentch_r ), maxWitdh_r ); }
821       /** \overload Indent by number of chars [' '] wrap. */
822       inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, unsigned indent_r, unsigned maxWitdh_r, char indentch_r = ' ' )
823       { return printIndented( str, text_r, std::string( indent_r, indentch_r ), maxWitdh_r ); }
824
825       /** Prefix lines by string computed by function taking line begin/end [std::string(const char*, const char*)]
826        * Prints nothing for an empty string. Asserts a trainling '\n' on the last line.
827        */
828       inline std::ostream & autoPrefix( std::ostream & str, const std::string & text_r, function<std::string(const char*, const char*)> fnc_r )
829       {
830         for ( const char * e = text_r.c_str(); *e; ++e )
831         {
832           const char * s = e;
833           for ( ; *e && *e != '\n'; ++e ) /*searching*/;
834           str << fnc_r( s, e );
835           str.write( s, e-s );
836           str << "\n";
837           if ( !*e )    // on '\0'
838             break;
839         }
840         return str;
841       }
842       /** \overload Prefix lines by string generated by function [std::string()] */
843       inline std::ostream & autoPrefix0( std::ostream & str, const std::string & text_r, function<std::string()> fnc_r )
844       {
845         auto wrap = [&fnc_r]( const char*, const char* )-> std::string {
846           return fnc_r();
847         };
848         return autoPrefix( str, text_r, wrap );
849       }
850     //@}
851     ///////////////////////////////////////////////////////////////////
852     /** \name Escape. */
853     //@{
854       /**
855        * Escape desired character \a c using a backslash.
856        *
857        * For use when printing \a c separated values, and where
858        * \ref joinEscaped() is too heavy.
859        */
860       std::string escape( const C_Str & str_r, const char c = ' ' );
861
862       /** Escape \a next_r and append it to \a str_r using separator \a sep_r. */
863       inline void appendEscaped( std::string & str_r, const C_Str & next_r, const char sep_r = ' ' )
864       {
865         if ( ! str_r.empty() )
866           str_r += sep_r;
867         if ( next_r.empty() )
868           str_r += "\"\"";
869         else
870           str_r += escape( next_r, sep_r );
871       }
872
873       //! \todo unsecape()
874
875     //@}
876     ///////////////////////////////////////////////////////////////////
877     ///////////////////////////////////////////////////////////////////
878     /** \name Hexencode.
879      * Encode all characters other than [a-zA-Z0-9] as %XX.
880      * This includes the % character itself, which becomes %25.
881      */
882     //@{
883     /** Encode all characters other than [a-zA-Z0-9] as %XX.
884      * This includes the % character itself, which becomes %25.
885      */
886     std::string hexencode( const C_Str & str_r );
887     /** Decode hexencoded %XX sequences. */
888     std::string hexdecode( const C_Str & str_r );
889     //@}
890     ///////////////////////////////////////////////////////////////////
891
892     /** \name Case conversion. */
893     //@{
894     /** Return lowercase version of \a s
895      * \todo improve
896     */
897     std::string toLower( const std::string & s );
898     /** \overload */
899     inline std::string toLower( const char * s )
900     { return( s ? toLower( std::string(s) ) : std::string() ); }
901
902     /** Return uppercase version of \a s
903      * \todo improve
904     */
905     std::string toUpper( const std::string & s );
906     /** \overload */
907     inline std::string toUpper( const char * s )
908     { return( s ? toUpper( std::string(s) ) : std::string() ); }
909     //@}
910
911
912     /** \name Case insensitive comparison. */
913     //@{
914     inline int compareCI( const C_Str & lhs, const C_Str & rhs )
915     { return ::strcasecmp( lhs, rhs ); }
916     //@}
917
918     /** \name Locate substring. */
919     //@{
920     /** Locate substring case sensitive. */
921     inline bool contains( const C_Str & str_r, const C_Str & val_r )
922     { return ::strstr( str_r, val_r ); }
923     /** Locate substring case insensitive. */
924     inline bool containsCI( const C_Str & str_r, const C_Str & val_r )
925     { return ::strcasestr( str_r, val_r ); }
926     //@}
927
928     ///////////////////////////////////////////////////////////////////
929     /** \name Trimming whitepace.
930      * \todo optimize l/r trim.
931     */
932     //@{
933     /** To define how to trim. */
934     enum Trim {
935       NO_TRIM = 0x00,
936       L_TRIM  = 0x01,
937       R_TRIM  = 0x02,
938       TRIM    = (L_TRIM|R_TRIM)
939     };
940
941     std::string trim( const std::string & s, const Trim trim_r = TRIM );
942
943     inline std::string ltrim( const std::string & s )
944     { return trim( s, L_TRIM ); }
945
946     inline std::string rtrim( const std::string & s )
947     { return trim( s, R_TRIM ); }
948     //@}
949
950     std::string stripFirstWord( std::string & line, const bool ltrim_first = true );
951
952     std::string stripLastWord( std::string & line, const bool rtrim_first = true );
953
954     /** Return stream content up to (but not returning) the next newline.
955      * \see \ref receiveUpTo
956      */
957     std::string getline( std::istream & str, bool trim = false );
958
959     /** Return stream content up to (but not returning) the next newline.
960      * \see \ref receiveUpTo
961      */
962     std::string getline( std::istream & str, const Trim trim_r );
963
964     /** Return stream content up to the next ocurrence of \c delim_r or EOF
965      * \c delim_r, if found, is always read from the stream. Whether it is
966      * also returned in the string depends on \c returnDelim_r.
967      * If the stream status is \c good, \c delim_r was found in the stream.
968      * If we reached EOF while looking for \c delim_r, \c eof is set; and
969      * also \c fail, if we did not read any data before.
970      */
971     std::string receiveUpTo( std::istream & str, const char delim_r, bool returnDelim_r = false );
972
973     ///////////////////////////////////////////////////////////////////
974
975     /** \name String prefix/suffix handling.
976      */
977     //@{
978     /** Return whether \a str_r has prefix \a prefix_r. */
979     inline bool hasPrefix( const C_Str & str_r, const C_Str & prefix_r )
980     { return( ::strncmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
981
982     /** Strip a \a prefix_r from \a str_r and return the resulting string. */
983     inline std::string stripPrefix( const C_Str & str_r, const C_Str & prefix_r )
984     { return( hasPrefix( str_r, prefix_r ) ? str_r + prefix_r.size() : str_r.c_str() ); }
985
986     /** Return whether \a str_r has suffix \a suffix_r. */
987     inline bool hasSuffix( const C_Str & str_r, const C_Str & suffix_r )
988     { return( str_r.size() >= suffix_r.size() && ::strncmp( str_r + str_r.size() - suffix_r.size() , suffix_r, suffix_r.size() ) == 0 ); }
989
990     /** Strip a \a suffix_r from \a str_r and return the resulting string. */
991     inline std::string stripSuffix( const C_Str & str_r, const C_Str & suffix_r )
992     {
993       if ( hasSuffix( str_r, suffix_r ) )
994         return std::string( str_r, str_r.size() - suffix_r.size() );
995       return str_r.c_str();
996     }
997     /** Return size of the common prefix of \a lhs and \a rhs. */
998     inline std::string::size_type commonPrefix( const C_Str & lhs, const C_Str & rhs )
999     {
1000       const char * lp = lhs.c_str();
1001       const char * rp = rhs.c_str();
1002       std::string::size_type ret = 0;
1003       while ( *lp == *rp && *lp != '\0' )
1004       { ++lp, ++rp, ++ret; }
1005       return ret;
1006     }
1007
1008     /** alias for \ref hasPrefix */
1009     inline bool startsWith( const C_Str & str_r, const C_Str & prefix_r )
1010     { return hasPrefix( str_r, prefix_r ); }
1011     /** alias for \ref hasSuffix */
1012     inline bool endsWith( const C_Str & str_r, const C_Str & prefix_r )
1013     { return hasSuffix( str_r, prefix_r ); }
1014     //@}
1015   } // namespace str
1016   ///////////////////////////////////////////////////////////////////
1017
1018   // drag into zypp:: namespace
1019   using str::asString;
1020
1021 } // namespace zypp
1022 ///////////////////////////////////////////////////////////////////
1023 #endif // ZYPP_BASE_STRING_H