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