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