00001
00002 #ifndef WIBBLE_STRING_H
00003 #define WIBBLE_STRING_H
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00046
00047 template< typename X >
00048 inline typename TPair< std::ostream, typename X::Type >::First &operator<<(
00049 std::ostream &o, X list )
00050 {
00051 if ( list.empty() )
00052 return o << "[]";
00053
00054 o << "[ ";
00055 while( !list.empty() ) {
00056 o << fmt( list.head() );
00057 if ( !list.tail().empty() )
00058 o << ", ";
00059 list = list.tail();
00060 }
00061 return o << " ]";
00062 }
00063
00064 #ifdef _WIN32
00065 static int vasprintf (char **, const char *, va_list);
00066 #endif
00067
00068 std::string fmt( const char* f, ... ) __attribute__ ((deprecated));
00069 std::string fmtf( const char* f, ... );
00070
00072 template< typename T >
00073 inline std::string fmt(const T& val)
00074 {
00075 std::stringstream str;
00076 str << val;
00077 return str.str();
00078 }
00079
00080 template<> inline std::string fmt<std::string>(const std::string& val) {
00081 return val;
00082 }
00083 template<> inline std::string fmt<char*>(char * const & val) { return val; }
00084
00085 template< typename C >
00086 inline std::string fmt_container( const C &c, char f, char l )
00087 {
00088 std::string s;
00089 s += f;
00090 if ( c.empty() )
00091 return s + l;
00092
00093 s += ' ';
00094 for ( typename C::const_iterator i = c.begin(); i != c.end(); ++i ) {
00095 s += fmt( *i );
00096 if ( i != c.end() && i + 1 != c.end() )
00097 s += ", ";
00098 }
00099 s += ' ';
00100 s += l;
00101 return s;
00102 }
00103
00104
00105 template< typename X >
00106 inline std::string fmt(const std::set< X >& val) {
00107 return fmt_container( val, '{', '}' );
00108 }
00109
00110
00111 template< typename X >
00112 inline std::string fmt(const std::vector< X > &val) {
00113 return fmt_container( val, '[', ']' );
00114 }
00115
00117 inline std::string basename(const std::string& pathname)
00118 {
00119 size_t pos = pathname.rfind("/");
00120 if (pos == std::string::npos)
00121 return pathname;
00122 else
00123 return pathname.substr(pos+1);
00124 }
00125
00127 inline std::string dirname(const std::string& pathname)
00128 {
00129 size_t pos = pathname.rfind("/");
00130 if (pos == std::string::npos)
00131 return std::string();
00132 else if (pos == 0)
00133
00134 return std::string("/");
00135 else
00136 return pathname.substr(0, pos);
00137 }
00138
00144 std::string normpath(const std::string& pathname);
00145
00147 inline bool startsWith(const std::string& str, const std::string& part)
00148 {
00149 if (str.size() < part.size())
00150 return false;
00151 return str.substr(0, part.size()) == part;
00152 }
00153
00155 inline bool endsWith(const std::string& str, const std::string& part)
00156 {
00157 if (str.size() < part.size())
00158 return false;
00159 return str.substr(str.size() - part.size()) == part;
00160 }
00161
00162 #if ! __GNUC__ || __GNUC__ >= 4
00163
00167 template<typename FUN>
00168 inline std::string trim(const std::string& str, const FUN& classifier)
00169 {
00170 if (str.empty())
00171 return str;
00172
00173 size_t beg = 0;
00174 size_t end = str.size() - 1;
00175 while (beg < end && classifier(str[beg]))
00176 ++beg;
00177 while (end >= beg && classifier(str[end]))
00178 --end;
00179
00180 return str.substr(beg, end-beg+1);
00181 }
00182
00186 inline std::string trim(const std::string& str)
00187 {
00188 return trim(str, ::isspace);
00189 }
00190 #else
00191
00192 inline std::string trim(const std::string& str)
00193 {
00194 if (str.empty())
00195 return str;
00196
00197 size_t beg = 0;
00198 size_t end = str.size() - 1;
00199 while (beg < end && ::isspace(str[beg]))
00200 ++beg;
00201 while (end >= beg && ::isspace(str[end]))
00202 --end;
00203
00204 return str.substr(beg, end-beg+1);
00205 }
00206 #endif
00207
00209 inline std::string toupper(const std::string& str)
00210 {
00211 std::string res;
00212 res.reserve(str.size());
00213 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
00214 res += ::toupper(*i);
00215 return res;
00216 }
00217
00219 inline std::string tolower(const std::string& str)
00220 {
00221 std::string res;
00222 res.reserve(str.size());
00223 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
00224 res += ::tolower(*i);
00225 return res;
00226 }
00227
00229 inline std::string ucfirst(const std::string& str)
00230 {
00231 if (str.empty()) return str;
00232 std::string res;
00233 res += ::toupper(str[0]);
00234 return res + tolower(str.substr(1));
00235 }
00236
00238 inline std::string joinpath(const std::string& path1, const std::string& path2)
00239 {
00240 if (path1.empty())
00241 return path2;
00242 if (path2.empty())
00243 return path1;
00244
00245 if (path1[path1.size() - 1] == '/')
00246 if (path2[0] == '/')
00247 return path1 + path2.substr(1);
00248 else
00249 return path1 + path2;
00250 else
00251 if (path2[0] == '/')
00252 return path1 + path2;
00253 else
00254 return path1 + '/' + path2;
00255 }
00256
00258 std::string urlencode(const std::string& str);
00259
00261 std::string urldecode(const std::string& str);
00262
00264 std::string encodeBase64(const std::string& str);
00265
00267 std::string decodeBase64(const std::string& str);
00268
00281 class Split
00282 {
00283 std::string sep;
00284 std::string str;
00285
00286 public:
00287
00288 class const_iterator
00289 {
00290 const std::string& sep;
00291 const std::string& str;
00292 std::string cur;
00293 size_t pos;
00294
00295 public:
00296 const_iterator(const std::string& sep, const std::string& str) : sep(sep), str(str), pos(0)
00297 {
00298 ++*this;
00299 }
00300 const_iterator(const std::string& sep, const std::string& str, bool) : sep(sep), str(str), pos(std::string::npos) {}
00301
00302 const_iterator& operator++()
00303 {
00304 if (pos == str.size())
00305 pos = std::string::npos;
00306 else
00307 {
00308 size_t end;
00309 if (sep.empty())
00310 if (pos + 1 == str.size())
00311 end = std::string::npos;
00312 else
00313 end = pos + 1;
00314 else
00315 end = str.find(sep, pos);
00316 if (end == std::string::npos)
00317 {
00318 cur = str.substr(pos);
00319 pos = str.size();
00320 }
00321 else
00322 {
00323 cur = str.substr(pos, end-pos);
00324 pos = end + sep.size();
00325 }
00326 }
00327 return *this;
00328 }
00329
00330 std::string remainder() const
00331 {
00332 if (pos == std::string::npos)
00333 return std::string();
00334 else
00335 return str.substr(pos);
00336 }
00337
00338 const std::string& operator*() const
00339 {
00340 return cur;
00341 }
00342 const std::string* operator->() const
00343 {
00344 return &cur;
00345 }
00346 bool operator==(const const_iterator& ti) const
00347 {
00348
00349
00350 return pos == ti.pos;
00351 }
00352 bool operator!=(const const_iterator& ti) const
00353 {
00354
00355
00356 return pos != ti.pos;
00357 }
00358 };
00359
00363 Split(const std::string& sep, const std::string& str) : sep(sep), str(str) {}
00364
00368 const_iterator begin() const { return const_iterator(sep, str); }
00369 const_iterator end() const { return const_iterator(sep, str, false); }
00370 };
00371
00372 template<typename ITER>
00373 std::string join(const ITER& begin, const ITER& end, const std::string& sep = ", ")
00374 {
00375 std::stringstream res;
00376 bool first = true;
00377 for (ITER i = begin; i != end; ++i)
00378 {
00379 if (first)
00380 first = false;
00381 else
00382 res << sep;
00383 res << *i;
00384 }
00385 return res.str();
00386 }
00387
00402 class YamlStream
00403 {
00404 public:
00405
00406 class const_iterator
00407 {
00408 std::istream* in;
00409 std::pair<std::string, std::string> value;
00410 std::string line;
00411
00412 public:
00413 const_iterator(std::istream& in);
00414 const_iterator() : in(0) {}
00415
00416 const_iterator& operator++();
00417
00418 const std::pair<std::string, std::string>& operator*() const
00419 {
00420 return value;
00421 }
00422 const std::pair<std::string, std::string>* operator->() const
00423 {
00424 return &value;
00425 }
00426 bool operator==(const const_iterator& ti) const
00427 {
00428 return in == ti.in;
00429 }
00430 bool operator!=(const const_iterator& ti) const
00431 {
00432 return in != ti.in;
00433 }
00434 };
00435
00436 const_iterator begin(std::istream& in) { return const_iterator(in); }
00437 const_iterator end() { return const_iterator(); }
00438 };
00439
00440 }
00441 }
00442
00443
00444 #endif