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