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