wibble 0.1.28
|
00001 // -*- C++ -*- 00002 #ifndef WIBBLE_STRING_H 00003 #define WIBBLE_STRING_H 00004 00005 /* 00006 * Various string functions 00007 * 00008 * Copyright (C) 2007,2008 Enrico Zini <enrico@debian.org> 00009 * 00010 * This library is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public 00012 * License as published by the Free Software Foundation; either 00013 * version 2.1 of the License, or (at your option) any later version. 00014 * 00015 * This library is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 * Lesser General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU Lesser General Public 00021 * License along with this library; if not, write to the Free Software 00022 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00023 */ 00024 00025 #include <wibble/operators.h> 00026 #include <wibble/sfinae.h> 00027 00028 #include <cstdarg> 00029 #include <cstdio> 00030 #include <string> 00031 #include <set> 00032 #include <vector> 00033 #include <sstream> 00034 #include <cctype> 00035 #ifdef _WIN32 00036 #include <cstring> 00037 #include <cstdlib> 00038 #endif 00039 00040 namespace wibble { 00041 namespace str { 00042 00043 using namespace wibble::operators; 00044 00045 #ifdef _WIN32 00046 static int vasprintf (char **, const char *, va_list); 00047 #endif 00048 00049 std::string fmt( const char* f, ... ) __attribute__ ((deprecated)); 00050 std::string fmtf( const char* f, ... ); 00051 template< typename T > inline std::string fmt(const T& val); 00052 00053 // Formatting lists -- actually, we need to move list handling into wibble, 00054 // really. 00055 template< typename X > 00056 inline typename TPair< std::ostream, typename X::Type >::First &operator<<( 00057 std::ostream &o, X list ) 00058 { 00059 if ( list.empty() ) 00060 return o << "[]"; 00061 00062 o << "[ "; 00063 while( !list.empty() ) { 00064 o << fmt( list.head() ); 00065 if ( !list.tail().empty() ) 00066 o << ", "; 00067 list = list.tail(); 00068 } 00069 return o << " ]"; 00070 } 00071 00073 template< typename T > 00074 inline std::string fmt(const T& val) 00075 { 00076 std::stringstream str; 00077 str << val; 00078 return str.str(); 00079 } 00080 00081 template<> inline std::string fmt<std::string>(const std::string& val) { 00082 return val; 00083 } 00084 template<> inline std::string fmt<char*>(char * const & val) { return val; } 00085 00086 template< typename C > 00087 inline std::string fmt_container( const C &c, char f, char l ) 00088 { 00089 std::string s; 00090 s += f; 00091 if ( c.empty() ) 00092 return s + l; 00093 00094 s += ' '; 00095 for ( typename C::const_iterator i = c.begin(); i != c.end(); ++i ) { 00096 s += fmt( *i ); 00097 if ( i != c.end() && i + 1 != c.end() ) 00098 s += ", "; 00099 } 00100 s += ' '; 00101 s += l; 00102 return s; 00103 } 00104 00105 // formatting sets using { ... } notation 00106 template< typename X > 00107 inline std::string fmt(const std::set< X >& val) { 00108 return fmt_container( val, '{', '}' ); 00109 } 00110 00111 // formatting vectors using [ ... ] notation 00112 template< typename X > 00113 inline std::string fmt(const std::vector< X > &val) { 00114 return fmt_container( val, '[', ']' ); 00115 } 00116 00118 inline std::string basename(const std::string& pathname) 00119 { 00120 size_t pos = pathname.rfind("/"); 00121 if (pos == std::string::npos) 00122 return pathname; 00123 else 00124 return pathname.substr(pos+1); 00125 } 00126 00128 inline std::string dirname(const std::string& pathname) 00129 { 00130 size_t pos = pathname.rfind("/"); 00131 if (pos == std::string::npos) 00132 return std::string(); 00133 else if (pos == 0) 00134 // Handle the case of '/foo' 00135 return std::string("/"); 00136 else 00137 return pathname.substr(0, pos); 00138 } 00139 00145 std::string normpath(const std::string& pathname); 00146 00148 inline bool startsWith(const std::string& str, const std::string& part) 00149 { 00150 if (str.size() < part.size()) 00151 return false; 00152 return str.substr(0, part.size()) == part; 00153 } 00154 00156 inline bool endsWith(const std::string& str, const std::string& part) 00157 { 00158 if (str.size() < part.size()) 00159 return false; 00160 return str.substr(str.size() - part.size()) == part; 00161 } 00162 00163 inline std::string replace(const std::string& str, char from, char to) 00164 { 00165 std::string res; 00166 res.reserve(str.size()); 00167 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) 00168 if (*i == from) 00169 res.append(1, to); 00170 else 00171 res.append(1, *i); 00172 return res; 00173 } 00174 00175 #if !__xlC__ && (! __GNUC__ || __GNUC__ >= 4) 00176 00180 template<typename FUN> 00181 inline std::string trim(const std::string& str, const FUN& classifier) 00182 { 00183 if (str.empty()) 00184 return str; 00185 00186 size_t beg = 0; 00187 size_t end = str.size() - 1; 00188 while (beg < end && classifier(str[beg])) 00189 ++beg; 00190 while (end >= beg && classifier(str[end])) 00191 --end; 00192 00193 return str.substr(beg, end-beg+1); 00194 } 00195 00199 inline std::string trim(const std::string& str) 00200 { 00201 return trim(str, ::isspace); 00202 } 00203 #else 00204 00205 inline std::string trim(const std::string& str) 00206 { 00207 if (str.empty()) 00208 return str; 00209 00210 size_t beg = 0; 00211 size_t end = str.size() - 1; 00212 while (beg < end && ::isspace(str[beg])) 00213 ++beg; 00214 while (end >= beg && ::isspace(str[end])) 00215 --end; 00216 00217 return str.substr(beg, end-beg+1); 00218 } 00219 #endif 00220 00222 inline std::string toupper(const std::string& str) 00223 { 00224 std::string res; 00225 res.reserve(str.size()); 00226 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) 00227 res += ::toupper(*i); 00228 return res; 00229 } 00230 00232 inline std::string tolower(const std::string& str) 00233 { 00234 std::string res; 00235 res.reserve(str.size()); 00236 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) 00237 res += ::tolower(*i); 00238 return res; 00239 } 00240 00242 inline std::string ucfirst(const std::string& str) 00243 { 00244 if (str.empty()) return str; 00245 std::string res; 00246 res += ::toupper(str[0]); 00247 return res + tolower(str.substr(1)); 00248 } 00249 00251 inline std::string joinpath(const std::string& path1, const std::string& path2) 00252 { 00253 if (path1.empty()) 00254 return path2; 00255 if (path2.empty()) 00256 return path1; 00257 00258 if (path1[path1.size() - 1] == '/') 00259 if (path2[0] == '/') 00260 return path1 + path2.substr(1); 00261 else 00262 return path1 + path2; 00263 else 00264 if (path2[0] == '/') 00265 return path1 + path2; 00266 else 00267 return path1 + '/' + path2; 00268 } 00269 00271 std::string urlencode(const std::string& str); 00272 00274 std::string urldecode(const std::string& str); 00275 00277 std::string encodeBase64(const std::string& str); 00278 00280 std::string decodeBase64(const std::string& str); 00281 00294 class Split 00295 { 00296 std::string sep; 00297 std::string str; 00298 00299 public: 00300 // TODO: add iterator_traits 00301 class const_iterator 00302 { 00303 const std::string& sep; 00304 const std::string& str; 00305 std::string cur; 00306 size_t pos; 00307 00308 public: 00309 const_iterator(const std::string& sep, const std::string& str) : sep(sep), str(str), pos(0) 00310 { 00311 ++*this; 00312 } 00313 const_iterator(const std::string& sep, const std::string& str, bool) : sep(sep), str(str), pos(std::string::npos) {} 00314 00315 const_iterator& operator++() 00316 { 00317 if (pos == str.size()) 00318 pos = std::string::npos; 00319 else 00320 { 00321 size_t end; 00322 if (sep.empty()) 00323 if (pos + 1 == str.size()) 00324 end = std::string::npos; 00325 else 00326 end = pos + 1; 00327 else 00328 end = str.find(sep, pos); 00329 if (end == std::string::npos) 00330 { 00331 cur = str.substr(pos); 00332 pos = str.size(); 00333 } 00334 else 00335 { 00336 cur = str.substr(pos, end-pos); 00337 pos = end + sep.size(); 00338 } 00339 } 00340 return *this; 00341 } 00342 00343 std::string remainder() const 00344 { 00345 if (pos == std::string::npos) 00346 return std::string(); 00347 else 00348 return str.substr(pos); 00349 } 00350 00351 const std::string& operator*() const 00352 { 00353 return cur; 00354 } 00355 const std::string* operator->() const 00356 { 00357 return &cur; 00358 } 00359 bool operator==(const const_iterator& ti) const 00360 { 00361 // Comparing iterators on different strings is not supported for 00362 // performance reasons 00363 return pos == ti.pos; 00364 } 00365 bool operator!=(const const_iterator& ti) const 00366 { 00367 // Comparing iterators on different strings is not supported for 00368 // performance reasons 00369 return pos != ti.pos; 00370 } 00371 }; 00372 00376 Split(const std::string& sep, const std::string& str) : sep(sep), str(str) {} 00377 00381 const_iterator begin() const { return const_iterator(sep, str); } 00382 const_iterator end() const { return const_iterator(sep, str, false); } 00383 }; 00384 00385 template<typename ITER> 00386 std::string join(const ITER& begin, const ITER& end, const std::string& sep = ", ") 00387 { 00388 std::stringstream res; 00389 bool first = true; 00390 for (ITER i = begin; i != end; ++i) 00391 { 00392 if (first) 00393 first = false; 00394 else 00395 res << sep; 00396 res << *i; 00397 } 00398 return res.str(); 00399 } 00400 00415 class YamlStream 00416 { 00417 public: 00418 // TODO: add iterator_traits 00419 class const_iterator 00420 { 00421 std::istream* in; 00422 std::pair<std::string, std::string> value; 00423 std::string line; 00424 00425 public: 00426 const_iterator(std::istream& in); 00427 const_iterator() : in(0) {} 00428 00429 const_iterator& operator++(); 00430 00431 const std::pair<std::string, std::string>& operator*() const 00432 { 00433 return value; 00434 } 00435 const std::pair<std::string, std::string>* operator->() const 00436 { 00437 return &value; 00438 } 00439 bool operator==(const const_iterator& ti) const 00440 { 00441 return in == ti.in; 00442 } 00443 bool operator!=(const const_iterator& ti) const 00444 { 00445 return in != ti.in; 00446 } 00447 }; 00448 00449 const_iterator begin(std::istream& in) { return const_iterator(in); } 00450 const_iterator end() { return const_iterator(); } 00451 }; 00452 00453 } 00454 } 00455 00456 // vim:set ts=4 sw=4: 00457 #endif