Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / base / String.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/String.cc
10  *
11 */
12 #include <cstdio>
13 #include <cstdarg>
14
15 #include <iostream>
16
17 #include "zypp/base/String.h"
18 #include "zypp/base/LogTools.h"
19
20 #include "zypp/TriBool.h"
21
22 using std::string;
23
24 ///////////////////////////////////////////////////////////////////
25 namespace zypp
26 { /////////////////////////////////////////////////////////////////
27   ///////////////////////////////////////////////////////////////////
28   namespace str
29   { /////////////////////////////////////////////////////////////////
30
31     /******************************************************************
32      **
33      **      FUNCTION NAME : form
34      **      FUNCTION TYPE : std::string
35     */
36     std::string form( const char * format, ... )
37     {
38       SafeBuf safe;
39
40       va_list ap;
41       va_start( ap, format );
42       vasprintf( &safe._buf, format, ap );
43       va_end( ap );
44
45       return safe.asString();
46     }
47
48     /******************************************************************
49      **
50      **      FUNCTION NAME : strerror
51      **      FUNCTION TYPE : std::string
52     */
53     std::string strerror( int errno_r )
54     {
55       return form( "(%d)%s", errno_r, ::strerror( errno_r ) );
56     }
57
58     /******************************************************************
59      **
60      **      FUNCTION NAME : strToTrue
61      **      FUNCTION TYPE : bool
62     */
63     bool strToTrue( const C_Str & str )
64     {
65       std::string t( toLower( str ) );
66       return(    t == "1"
67               || t == "yes"
68               || t == "true"
69               || t == "on"
70               || t == "+"
71               || strtonum<long long>( str )
72             );
73     }
74
75     /******************************************************************
76      **
77      **      FUNCTION NAME : strToFalse
78      **      FUNCTION TYPE : bool
79     */
80     bool strToFalse( const C_Str & str )
81     {
82       std::string t( toLower( str ) );
83       return ! (    t == "0"
84                  || t == "no"
85                  || t == "false"
86                  || t == "off"
87                  || t == "-"
88                );
89     }
90
91     TriBool strToTriBool( const C_Str & str )   // from TriBool.h
92     {
93       if ( strToTrue( str ) )   return true;
94       if ( !strToFalse( str ) ) return false;
95       return indeterminate;
96     }
97
98     ///////////////////////////////////////////////////////////////////
99     // Hexencode
100     ///////////////////////////////////////////////////////////////////
101     namespace {
102       /** What's not decoded. */
103       inline bool heIsAlNum( char ch )
104       {
105         return ( ( 'a' <= ch && ch <= 'z' )
106                ||( 'A' <= ch && ch <= 'Z' )
107                ||( '0' <= ch && ch <= '9' ) );
108       }
109       /** Hex-digit to number or -1. */
110       inline int heDecodeCh( char ch )
111       {
112         if ( '0' <= ch && ch <= '9' )
113           return( ch - '0' );
114         if ( 'A' <= ch && ch <= 'F' )
115           return( ch - 'A' + 10 );
116         if ( 'a' <= ch && ch <= 'f' )
117           return( ch - 'a' + 10 );
118         return -1;
119       }
120     }
121
122     std::string hexencode( const C_Str & str_r )
123     {
124       static const char *const hdig = "0123456789ABCDEF";
125       std::string res;
126       res.reserve( str_r.size() );
127       for ( const char * it = str_r.c_str(); *it; ++it )
128       {
129         if ( heIsAlNum( *it ) )
130         {
131           res += *it;
132         }
133         else
134         {
135           res += '%';
136           res += hdig[(unsigned char)(*it)/16];
137           res += hdig[(unsigned char)(*it)%16];
138         }
139       }
140       return res;
141     }
142
143     std::string hexdecode( const C_Str & str_r )
144     {
145       std::string res;
146       res.reserve( str_r.size() );
147       for_( it, str_r.c_str(), str_r.c_str()+str_r.size() )
148       {
149         if ( *it == '%' )
150         {
151           int d1 = heDecodeCh( *(it+1) );
152           if ( d1 != -1 )
153           {
154             int d2 = heDecodeCh( *(it+2) );
155             if ( d2 != -1 )
156             {
157               res += (d1<<4)|d2;
158               it += 2;
159               continue;
160             }
161           }
162         }
163         // verbatim if no %XX:
164         res += *it;
165       }
166       return res;
167     }
168     ///////////////////////////////////////////////////////////////////
169
170     /******************************************************************
171      **
172      **      FUNCTION NAME : toLower
173      **      FUNCTION TYPE : std::string
174     */
175     std::string toLower( const std::string & s )
176     { return toLower( std::string(s) ); }
177
178     std::string toLower( std::string && s )
179     {
180       std::string ret( std::move(s) );
181
182       if ( ret.empty() )
183         return ret;
184
185       for ( std::string::size_type i = 0; i < ret.length(); ++i )
186         {
187           if ( isupper( ret[i] ) )
188             ret[i] = static_cast<char>(tolower( ret[i] ));
189         }
190       return ret;
191     }
192
193     /******************************************************************
194      **
195      **      FUNCTION NAME : toUpper
196      **      FUNCTION TYPE : std::string
197     */
198     std::string toUpper( const std::string & s )
199     { return toUpper( std::string(s) ); }
200
201     std::string toUpper( std::string && s )
202     {
203       std::string ret( std::move(s) );
204
205       if ( ret.empty() )
206         return ret;
207
208       for ( std::string::size_type i = 0; i < ret.length(); ++i )
209         {
210           if ( islower( ret[i] ) )
211             ret[i] = static_cast<char>(toupper( ret[i] ));
212         }
213       return ret;
214     }
215
216     /******************************************************************
217      **
218      **      FUNCTION NAME : trim
219      **      FUNCTION TYPE : std::string
220     */
221     std::string trim( const std::string & s, const Trim trim_r )
222     { return trim( std::string(s), trim_r ); }
223
224     std::string trim( std::string && s, const Trim trim_r )
225     {
226       std::string ret( std::move(s) );
227
228       if ( ret.empty() || trim_r == NO_TRIM )
229         return ret;
230
231       if ( trim_r & L_TRIM )
232       {
233         std::string::size_type p = ret.find_first_not_of( " \t\n" );
234         if ( p == std::string::npos )
235         {
236           ret.clear();
237           return ret;
238         }
239         ret.erase( 0, p );
240       }
241
242       if ( trim_r & R_TRIM )
243       {
244         std::string::size_type p = ret.find_last_not_of( " \t\n" );
245         if ( p == std::string::npos )
246         {
247           ret.clear();
248           return ret;
249         }
250         ret = ret.erase( p+1 );
251       }
252
253       return ret;
254     }
255
256     /******************************************************************
257     **
258     **  FUNCTION NAME : stripFirstWord
259     **  FUNCTION TYPE : std::string
260     */
261     std::string stripFirstWord( std::string & line, const bool ltrim_first )
262     {
263       if ( ltrim_first )
264         line = ltrim( line );
265
266       if ( line.empty() )
267         return line;
268
269       std::string ret;
270       std::string::size_type p = line.find_first_of( " \t" );
271
272       if ( p == std::string::npos ) {
273         // no ws on line
274         ret = line;
275         line.erase();
276       } else if ( p == 0 ) {
277         // starts with ws
278         // ret remains empty
279         line = ltrim( line );
280       }
281       else {
282         // strip word and ltim line
283         ret = line.substr( 0, p );
284         line = ltrim( line.erase( 0, p ) );
285       }
286       return ret;
287     }
288
289     /******************************************************************
290     **
291     **  FUNCTION NAME : stripLastWord
292     **  FUNCTION TYPE : std::string
293     */
294     std::string stripLastWord( std::string & line, const bool rtrim_first )
295     {
296       if ( rtrim_first )
297         line = rtrim( line );
298
299       if ( line.empty() )
300         return line;
301
302       std::string ret;
303       std::string::size_type p = line.find_last_of( " \t" );
304
305       if ( p == std::string::npos ) {
306         // no ws on line
307         ret = line;
308         line.erase();
309       } else if ( p == line.size()-1 ) {
310         // ends with ws
311         // ret remains empty
312         line = rtrim( line );
313       }
314       else {
315         // strip word and rtim line
316         ret = line.substr( p+1 );
317         line = rtrim( line.erase( p ) );
318       }
319       return ret;
320     }
321
322     std::string gsub( const std::string & str_r, const std::string & from_r, const std::string & to_r )
323     {
324       std::string ret( str_r );
325       return replaceAll( ret, from_r, to_r );
326     }
327
328     std::string & replaceAll( std::string & str_r, const std::string & from_r, const std::string & to_r )
329     {
330       if ( ! from_r.empty() )
331       {
332         std::string::size_type pos = 0;
333         while ( (pos = str_r.find( from_r, pos )) != std::string::npos )
334         {
335           str_r.replace( pos, from_r.size(), to_r );
336           pos += to_r.size();
337
338           if ( pos >= str_r.length() )
339             break;
340         }
341       }
342       return str_r;
343     }
344
345     std::string gsubFun( const std::string & str_r, const std::string & from_r, function<std::string()> to_r )
346     {
347       std::string ret( str_r );
348       return replaceAllFun( ret, from_r, to_r );
349     }
350
351     std::string & replaceAllFun( std::string & str_r, const std::string & from_r, function<std::string()> to_r )
352     {
353       if ( ! from_r.empty() )
354       {
355         std::string::size_type pos = 0;
356         while ( (pos = str_r.find( from_r, pos )) != std::string::npos )
357         {
358           std::string to( to_r() );
359           str_r.replace( pos, from_r.size(), to );
360           pos += to.size();
361
362           if ( pos >= str_r.length() )
363             break;
364         }
365       }
366       return str_r;
367     }
368
369     std::string escape( const C_Str & str_r, const char sep_r )
370     {
371       std::vector<char> buf;
372       for_( s, str_r.c_str(), s+str_r.size() )
373       {
374         switch ( *s )
375         {
376         case '"':
377         case '\'':
378         case '\\':
379           buf.push_back( '\\' );
380           buf.push_back( *s );
381           break;
382         default:
383           if ( *s == sep_r )
384             buf.push_back( '\\' );
385           buf.push_back( *s );
386         }
387       }
388       return std::string( buf.begin(), buf.end() );
389     }
390
391     std::string getline( std::istream & str, const Trim trim_r )
392     {
393       return trim( receiveUpTo( str, '\n' ), trim_r );
394     }
395
396     std::string getline( std::istream & str, bool trim_r )
397     {
398       return trim( receiveUpTo( str, '\n' ), trim_r?TRIM:NO_TRIM );
399     }
400
401     std::string receiveUpTo( std::istream & str, const char delim_r, bool returnDelim_r )
402     {
403       std::ostringstream datas;
404       do {
405         char ch;
406         if ( str.get( ch ) )
407         {
408           if ( ch != delim_r )
409           {
410             datas.put( ch );
411           }
412           else
413           {
414             if ( returnDelim_r )
415               datas.put( ch );
416             break;      // --> delimiter found
417           }
418         }
419         else
420         {
421           // clear fail bit if we read data before reaching EOF
422           if ( str.eof() && datas.tellp() )
423             str.clear( std::ios::eofbit );
424           break;        // --> no consumable data.
425         }
426       } while ( true );
427       return datas.str();
428     }
429
430     /////////////////////////////////////////////////////////////////
431   } // namespace str
432   ///////////////////////////////////////////////////////////////////
433   ////////////////////////////////////////////////////////////////
434 } // namespace zypp
435 //////////////////////////////////////////////////////////////////