Add str::receiveUpTo to read stream content up to the next ocurrence of a delimiter.
[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 <= 'Z' )
106           return( ch - 'A' + 10 );
107         if ( 'a' <= ch && ch <= 'z' )
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     string gsub(const string& sData, const string& sFrom, const string& sTo)
299     {
300       string sNew;
301       sNew.reserve(sData.size());
302
303       if (! sData.empty())
304       {
305         string::size_type frLen = sFrom.length();
306         string::size_type loc = 0;
307         string::size_type oldLoc = 0;
308
309         while (string::npos != (loc = sData.find(sFrom, loc)))
310         {
311           sNew.append(sData,oldLoc,loc-oldLoc);
312           sNew.append(sTo);
313           loc += frLen;
314           oldLoc = loc;
315           if (loc >= sData.length())
316             break;
317         }
318         if (oldLoc!=sData.size())
319             sNew.append(sData,oldLoc,sData.size()-oldLoc);
320       }
321
322       return sNew;
323     }
324
325     string & replaceAll(string & str, const string & from, const string & to)
326     {
327       string::size_type pos = 0;
328       while((pos = str.find(from, pos)) != string::npos)
329       {
330         str.replace(pos, from.size(), to);
331         pos += to.size();
332
333         if (pos >= str.length())
334           break;
335       }
336       return str;
337     }
338
339
340     std::string escape( const C_Str & str_r, const char sep_r )
341     {
342       std::vector<char> buf;
343       for_( s, str_r.c_str(), s+str_r.size() )
344       {
345         switch ( *s )
346         {
347         case '"':
348         case '\'':
349         case '\\':
350           buf.push_back( '\\' );
351           buf.push_back( *s );
352           break;
353         default:
354           if ( *s == sep_r )
355             buf.push_back( '\\' );
356           buf.push_back( *s );
357         }
358       }
359       return std::string( buf.begin(), buf.end() );
360     }
361
362     std::string getline( std::istream & str, const Trim trim_r )
363     {
364       return trim( receiveUpTo( str, '\n' ), trim_r );
365     }
366
367     std::string getline( std::istream & str, bool trim_r )
368     {
369       return trim( receiveUpTo( str, '\n' ), trim_r?TRIM:NO_TRIM );
370     }
371
372     std::string receiveUpTo( std::istream & str, const char delim_r, bool returnDelim_r )
373     {
374       std::ostringstream datas;
375       do {
376         char ch;
377         if ( str.get( ch ) )
378         {
379           if ( ch != delim_r )
380           {
381             datas.put( ch );
382           }
383           else
384           {
385             if ( returnDelim_r )
386               datas.put( ch );
387             break;      // --> delimiter found
388           }
389         }
390         else
391         {
392           // clear fail bit if we read data before reaching EOF
393           if ( str.eof() && datas.tellp() )
394             str.clear( std::ios::eofbit );
395           break;        // --> no consumable data.
396         }
397       } while ( true );
398       return datas.str();
399     }
400
401     /////////////////////////////////////////////////////////////////
402   } // namespace str
403   ///////////////////////////////////////////////////////////////////
404   ////////////////////////////////////////////////////////////////
405 } // namespace zypp
406 //////////////////////////////////////////////////////////////////