wibble  0.1.28
string.h
Go to the documentation of this file.
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