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