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