~thopiekar/zypper/libzypp-manual-import

« back to all changes in this revision

Viewing changes to zypp/base/String.h

  • Committer: Thomas-Karl Pietrowski
  • Date: 2014-01-29 22:44:28 UTC
  • Revision ID: thopiekar@googlemail.com-20140129224428-gpcqnsdakby362n8
firstĀ import

Show diffs side-by-side

added added

removed removed

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