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