Imported Upstream version 14.45.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 #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     {
177       if ( s.empty() )
178         return s;
179
180       std::string ret( s );
181       for ( std::string::size_type i = 0; i < ret.length(); ++i )
182         {
183           if ( isupper( ret[i] ) )
184             ret[i] = static_cast<char>(tolower( ret[i] ));
185         }
186       return ret;
187     }
188
189     /******************************************************************
190      **
191      **      FUNCTION NAME : toUpper
192      **      FUNCTION TYPE : std::string
193     */
194     std::string toUpper( const std::string & s )
195     {
196       if ( s.empty() )
197         return s;
198
199       std::string ret( s );
200       for ( std::string::size_type i = 0; i < ret.length(); ++i )
201         {
202           if ( islower( ret[i] ) )
203             ret[i] = static_cast<char>(toupper( ret[i] ));
204         }
205       return ret;
206     }
207
208     /******************************************************************
209      **
210      **      FUNCTION NAME : trim
211      **      FUNCTION TYPE : std::string
212     */
213     std::string trim( const std::string & s, const Trim trim_r )
214     {
215       if ( s.empty() || trim_r == NO_TRIM )
216         return s;
217
218       std::string ret( s );
219
220       if ( trim_r & L_TRIM )
221         {
222           std::string::size_type p = ret.find_first_not_of( " \t\n" );
223           if ( p == std::string::npos )
224             return std::string();
225
226           ret = ret.substr( p );
227         }
228
229       if ( trim_r & R_TRIM )
230         {
231           std::string::size_type p = ret.find_last_not_of( " \t\n" );
232           if ( p == std::string::npos )
233             return std::string();
234
235           ret = ret.substr( 0, p+1 );
236         }
237
238       return ret;
239     }
240
241     /******************************************************************
242     **
243     **  FUNCTION NAME : stripFirstWord
244     **  FUNCTION TYPE : std::string
245     */
246     std::string stripFirstWord( std::string & line, const bool ltrim_first )
247     {
248       if ( ltrim_first )
249         line = ltrim( line );
250
251       if ( line.empty() )
252         return line;
253
254       std::string ret;
255       std::string::size_type p = line.find_first_of( " \t" );
256
257       if ( p == std::string::npos ) {
258         // no ws on line
259         ret = line;
260         line.erase();
261       } else if ( p == 0 ) {
262         // starts with ws
263         // ret remains empty
264         line = ltrim( line );
265       }
266       else {
267         // strip word and ltim line
268         ret = line.substr( 0, p );
269         line = ltrim( line.erase( 0, p ) );
270       }
271       return ret;
272     }
273
274     /******************************************************************
275     **
276     **  FUNCTION NAME : stripLastWord
277     **  FUNCTION TYPE : std::string
278     */
279     std::string stripLastWord( std::string & line, const bool rtrim_first )
280     {
281       if ( rtrim_first )
282         line = rtrim( line );
283
284       if ( line.empty() )
285         return line;
286
287       std::string ret;
288       std::string::size_type p = line.find_last_of( " \t" );
289
290       if ( p == std::string::npos ) {
291         // no ws on line
292         ret = line;
293         line.erase();
294       } else if ( p == line.size()-1 ) {
295         // ends with ws
296         // ret remains empty
297         line = rtrim( line );
298       }
299       else {
300         // strip word and rtim line
301         ret = line.substr( p+1 );
302         line = rtrim( line.erase( p ) );
303       }
304       return ret;
305     }
306
307     std::string gsub( const std::string & str_r, const std::string & from_r, const std::string & to_r )
308     {
309       std::string ret( str_r );
310       return replaceAll( ret, from_r, to_r );
311     }
312
313     std::string & replaceAll( std::string & str_r, const std::string & from_r, const std::string & to_r )
314     {
315       if ( ! from_r.empty() )
316       {
317         std::string::size_type pos = 0;
318         while ( (pos = str_r.find( from_r, pos )) != std::string::npos )
319         {
320           str_r.replace( pos, from_r.size(), to_r );
321           pos += to_r.size();
322
323           if ( pos >= str_r.length() )
324             break;
325         }
326       }
327       return str_r;
328     }
329
330     std::string gsubFun( const std::string & str_r, const std::string & from_r, function<std::string()> to_r )
331     {
332       std::string ret( str_r );
333       return replaceAllFun( ret, from_r, to_r );
334     }
335
336     std::string & replaceAllFun( std::string & str_r, const std::string & from_r, function<std::string()> to_r )
337     {
338       if ( ! from_r.empty() )
339       {
340         std::string::size_type pos = 0;
341         while ( (pos = str_r.find( from_r, pos )) != std::string::npos )
342         {
343           std::string to( to_r() );
344           str_r.replace( pos, from_r.size(), to );
345           pos += to.size();
346
347           if ( pos >= str_r.length() )
348             break;
349         }
350       }
351       return str_r;
352     }
353
354     std::string escape( const C_Str & str_r, const char sep_r )
355     {
356       std::vector<char> buf;
357       for_( s, str_r.c_str(), s+str_r.size() )
358       {
359         switch ( *s )
360         {
361         case '"':
362         case '\'':
363         case '\\':
364           buf.push_back( '\\' );
365           buf.push_back( *s );
366           break;
367         default:
368           if ( *s == sep_r )
369             buf.push_back( '\\' );
370           buf.push_back( *s );
371         }
372       }
373       return std::string( buf.begin(), buf.end() );
374     }
375
376     std::string getline( std::istream & str, const Trim trim_r )
377     {
378       return trim( receiveUpTo( str, '\n' ), trim_r );
379     }
380
381     std::string getline( std::istream & str, bool trim_r )
382     {
383       return trim( receiveUpTo( str, '\n' ), trim_r?TRIM:NO_TRIM );
384     }
385
386     std::string receiveUpTo( std::istream & str, const char delim_r, bool returnDelim_r )
387     {
388       std::ostringstream datas;
389       do {
390         char ch;
391         if ( str.get( ch ) )
392         {
393           if ( ch != delim_r )
394           {
395             datas.put( ch );
396           }
397           else
398           {
399             if ( returnDelim_r )
400               datas.put( ch );
401             break;      // --> delimiter found
402           }
403         }
404         else
405         {
406           // clear fail bit if we read data before reaching EOF
407           if ( str.eof() && datas.tellp() )
408             str.clear( std::ios::eofbit );
409           break;        // --> no consumable data.
410         }
411       } while ( true );
412       return datas.str();
413     }
414
415     /////////////////////////////////////////////////////////////////
416   } // namespace str
417   ///////////////////////////////////////////////////////////////////
418   ////////////////////////////////////////////////////////////////
419 } // namespace zypp
420 //////////////////////////////////////////////////////////////////