Fix Werrors with GCC-14.1.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 == "always"
70               || t == "on"
71               || t == "+"
72               || strtonum<long long>( str )
73             );
74     }
75
76     /******************************************************************
77      **
78      **      FUNCTION NAME : strToFalse
79      **      FUNCTION TYPE : bool
80     */
81     bool strToFalse( const C_Str & str )
82     {
83       std::string t( toLower( str ) );
84       return ! (    t == "0"
85                  || t == "no"
86                  || t == "false"
87                  || t == "never"
88                  || t == "off"
89                  || t == "-"
90                );
91     }
92
93     TriBool strToTriBool( const C_Str & str )   // from TriBool.h
94     {
95       if ( strToTrue( str ) )   return true;
96       if ( !strToFalse( str ) ) return false;
97       return indeterminate;
98     }
99
100     ///////////////////////////////////////////////////////////////////
101     // Hexencode
102     ///////////////////////////////////////////////////////////////////
103     namespace {
104       /** What's not decoded. */
105       inline bool heIsAlNum( char ch )
106       {
107         return ( ( 'a' <= ch && ch <= 'z' )
108                ||( 'A' <= ch && ch <= 'Z' )
109                ||( '0' <= ch && ch <= '9' ) );
110       }
111       /** Hex-digit to number or -1. */
112       inline int heDecodeCh( char ch )
113       {
114         if ( '0' <= ch && ch <= '9' )
115           return( ch - '0' );
116         if ( 'A' <= ch && ch <= 'F' )
117           return( ch - 'A' + 10 );
118         if ( 'a' <= ch && ch <= 'f' )
119           return( ch - 'a' + 10 );
120         return -1;
121       }
122     }
123
124     std::string hexencode( const C_Str & str_r )
125     {
126       static const char *const hdig = "0123456789ABCDEF";
127       std::string res;
128       res.reserve( str_r.size() );
129       for ( const char * it = str_r.c_str(); *it; ++it )
130       {
131         if ( heIsAlNum( *it ) )
132         {
133           res += *it;
134         }
135         else
136         {
137           res += '%';
138           res += hdig[(unsigned char)(*it)/16];
139           res += hdig[(unsigned char)(*it)%16];
140         }
141       }
142       return res;
143     }
144
145     std::string hexdecode( const C_Str & str_r )
146     {
147       std::string res;
148       res.reserve( str_r.size() );
149       for_( it, str_r.c_str(), str_r.c_str()+str_r.size() )
150       {
151         if ( *it == '%' )
152         {
153           int d1 = heDecodeCh( *(it+1) );
154           if ( d1 != -1 )
155           {
156             int d2 = heDecodeCh( *(it+2) );
157             if ( d2 != -1 )
158             {
159               res += (d1<<4)|d2;
160               it += 2;
161               continue;
162             }
163           }
164         }
165         // verbatim if no %XX:
166         res += *it;
167       }
168       return res;
169     }
170     ///////////////////////////////////////////////////////////////////
171
172     /******************************************************************
173      **
174      **      FUNCTION NAME : toLower
175      **      FUNCTION TYPE : std::string
176     */
177     std::string toLower( const std::string & s )
178     { return toLower( std::string(s) ); }
179
180     std::string toLower( std::string && s )
181     {
182       std::string ret( std::move(s) );
183
184       if ( ret.empty() )
185         return ret;
186
187       for ( std::string::size_type i = 0; i < ret.length(); ++i )
188         {
189           if ( isupper( ret[i] ) )
190             ret[i] = static_cast<char>(tolower( ret[i] ));
191         }
192       return ret;
193     }
194
195     /******************************************************************
196      **
197      **      FUNCTION NAME : toUpper
198      **      FUNCTION TYPE : std::string
199     */
200     std::string toUpper( const std::string & s )
201     { return toUpper( std::string(s) ); }
202
203     std::string toUpper( std::string && s )
204     {
205       std::string ret( std::move(s) );
206
207       if ( ret.empty() )
208         return ret;
209
210       for ( std::string::size_type i = 0; i < ret.length(); ++i )
211         {
212           if ( islower( ret[i] ) )
213             ret[i] = static_cast<char>(toupper( ret[i] ));
214         }
215       return ret;
216     }
217
218     /******************************************************************
219      **
220      **      FUNCTION NAME : trim
221      **      FUNCTION TYPE : std::string
222     */
223     std::string trim( const std::string & s, const Trim trim_r )
224     { return trim( std::string(s), trim_r ); }
225
226     std::string trim( std::string && s, const Trim trim_r )
227     {
228       std::string ret( std::move(s) );
229
230       if ( ret.empty() || trim_r == NO_TRIM )
231         return ret;
232
233       if ( trim_r & L_TRIM )
234       {
235         std::string::size_type p = ret.find_first_not_of( " \t\n" );
236         if ( p == std::string::npos )
237         {
238           ret.clear();
239           return ret;
240         }
241         ret.erase( 0, p );
242       }
243
244       if ( trim_r & R_TRIM )
245       {
246         std::string::size_type p = ret.find_last_not_of( " \t\n" );
247         if ( p == std::string::npos )
248         {
249           ret.clear();
250           return ret;
251         }
252         ret = ret.erase( p+1 );
253       }
254
255       return ret;
256     }
257
258     /******************************************************************
259     **
260     **  FUNCTION NAME : stripFirstWord
261     **  FUNCTION TYPE : std::string
262     */
263     std::string stripFirstWord( std::string & line, const bool ltrim_first )
264     {
265       if ( ltrim_first )
266         line = ltrim( line );
267
268       if ( line.empty() )
269         return line;
270
271       std::string ret;
272       std::string::size_type p = line.find_first_of( " \t" );
273
274       if ( p == std::string::npos ) {
275         // no ws on line
276         ret = line;
277         line.erase();
278       } else if ( p == 0 ) {
279         // starts with ws
280         // ret remains empty
281         line = ltrim( line );
282       }
283       else {
284         // strip word and ltim line
285         ret = line.substr( 0, p );
286         line = ltrim( line.erase( 0, p ) );
287       }
288       return ret;
289     }
290
291     /******************************************************************
292     **
293     **  FUNCTION NAME : stripLastWord
294     **  FUNCTION TYPE : std::string
295     */
296     std::string stripLastWord( std::string & line, const bool rtrim_first )
297     {
298       if ( rtrim_first )
299         line = rtrim( line );
300
301       if ( line.empty() )
302         return line;
303
304       std::string ret;
305       std::string::size_type p = line.find_last_of( " \t" );
306
307       if ( p == std::string::npos ) {
308         // no ws on line
309         ret = line;
310         line.erase();
311       } else if ( p == line.size()-1 ) {
312         // ends with ws
313         // ret remains empty
314         line = rtrim( line );
315       }
316       else {
317         // strip word and rtim line
318         ret = line.substr( p+1 );
319         line = rtrim( line.erase( p ) );
320       }
321       return ret;
322     }
323
324     std::string gsub( const std::string & str_r, const std::string & from_r, const std::string & to_r )
325     {
326       std::string ret( str_r );
327       return replaceAll( ret, from_r, to_r );
328     }
329
330     std::string & replaceAll( std::string & str_r, const std::string & from_r, const std::string & to_r )
331     {
332       if ( ! from_r.empty() )
333       {
334         std::string::size_type pos = 0;
335         while ( (pos = str_r.find( from_r, pos )) != std::string::npos )
336         {
337           str_r.replace( pos, from_r.size(), to_r );
338           pos += to_r.size();
339
340           if ( pos >= str_r.length() )
341             break;
342         }
343       }
344       return str_r;
345     }
346
347     std::string gsubFun( const std::string & str_r, const std::string & from_r, function<std::string()> to_r )
348     {
349       std::string ret( str_r );
350       return replaceAllFun( ret, from_r, to_r );
351     }
352
353     std::string & replaceAllFun( std::string & str_r, const std::string & from_r, function<std::string()> to_r )
354     {
355       if ( ! from_r.empty() )
356       {
357         std::string::size_type pos = 0;
358         while ( (pos = str_r.find( from_r, pos )) != std::string::npos )
359         {
360           std::string to( to_r() );
361           str_r.replace( pos, from_r.size(), to );
362           pos += to.size();
363
364           if ( pos >= str_r.length() )
365             break;
366         }
367       }
368       return str_r;
369     }
370
371     std::string escape( const C_Str & str_r, const char sep_r )
372     {
373       std::vector<char> buf;
374       for_( s, str_r.c_str(), s+str_r.size() )
375       {
376         switch ( *s )
377         {
378         case '"':
379         case '\'':
380         case '\\':
381           buf.push_back( '\\' );
382           buf.push_back( *s );
383           break;
384         default:
385           if ( *s == sep_r )
386             buf.push_back( '\\' );
387           buf.push_back( *s );
388         }
389       }
390       return std::string( buf.begin(), buf.end() );
391     }
392
393
394     std::string bEscape( std::string str_r, const C_Str & special_r )
395     {
396       if ( str_r.empty() )
397         return str_r;
398
399       if ( str_r.find_first_of( special_r ) == std::string::npos
400         && ( ::strchr( special_r.c_str(), '\\' ) ||  !::strchr( str_r.c_str(), '\\' ) ) )
401         return str_r;
402
403       Str buf;
404       for_( s, str_r.c_str(), s+str_r.size() )
405       {
406         if ( *s == '\\' || ::strchr( special_r.c_str(), *s ) )
407           buf << '\\';
408         buf << *s;
409       }
410       return buf;
411     }
412
413     #define RXSPECIALCHARS "\\.*+?^$[()|{"
414
415     std::string rxEscapeStr( std::string str_r )
416     {
417       return bEscape( std::move(str_r), RXSPECIALCHARS );
418     }
419
420     std::string rxEscapeGlob( std::string str_r )
421     {
422       if ( str_r.empty() )
423         return str_r;
424
425       if ( str_r.find_first_of( RXSPECIALCHARS ) == std::string::npos )
426         return str_r;
427
428       Str buf;
429       for_( s, str_r.c_str(), s+str_r.size() )
430       {
431         if ( *s == '\\' )       // + next char literally
432         {
433           buf << '\\';
434           if ( *(s+1) ) { ++s; buf << *s; }
435         }
436         else if ( *s == '?' )   // translate
437         {
438           buf << '.';
439         }
440         else if ( *s == '*' )   // translate
441         {
442           buf << ".*";
443         }
444         else if ( *s == '[' )   // character class if closing ] is found, else literally
445         {
446           const char * e = s+1;
447           if ( *e == '^' || *e == '!' ) // negated cclass
448             ++e;
449           if ( *e == ']' )              // ] in cclass
450             ++e;
451           while ( *e && *e != ']' )     // ...to ] or \0
452             ++e;
453           if ( *e ) // on closing ']'
454           {
455             ++s;  buf << '[' << (*s == '!' ? '^' : *s );
456             while ( ++s != e )
457               buf << *s;
458             buf << ']';
459           }
460           else
461           {
462             buf << "\\[";
463           }
464         }
465         else if ( ::strchr( RXSPECIALCHARS, *s ) )      // escape
466         {
467           buf << '\\' << *s;
468         }
469         else
470         {
471           buf << *s;
472         }
473       }
474       return buf;
475     }
476
477
478     std::string getline( std::istream & str, const Trim trim_r )
479     {
480       return trim( receiveUpTo( str, '\n' ), trim_r );
481     }
482
483     std::string getline( std::istream & str, bool trim_r )
484     {
485       return trim( receiveUpTo( str, '\n' ), trim_r?TRIM:NO_TRIM );
486     }
487
488     std::string receiveUpTo( std::istream & str, const char delim_r, bool returnDelim_r )
489     {
490       std::ostringstream datas;
491       do {
492         char ch;
493         if ( str.get( ch ) )
494         {
495           if ( ch != delim_r )
496           {
497             datas.put( ch );
498           }
499           else
500           {
501             if ( returnDelim_r )
502               datas.put( ch );
503             break;      // --> delimiter found
504           }
505         }
506         else
507         {
508           // clear fail bit if we read data before reaching EOF
509           if ( str.eof() && datas.tellp() )
510             str.clear( std::ios::eofbit );
511           break;        // --> no consumable data.
512         }
513       } while ( true );
514       return datas.str();
515     }
516
517     /////////////////////////////////////////////////////////////////
518   } // namespace str
519   ///////////////////////////////////////////////////////////////////
520   ////////////////////////////////////////////////////////////////
521 } // namespace zypp
522 //////////////////////////////////////////////////////////////////