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