wibble  0.1.28
string.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 #ifndef WIBBLE_STRING_H
3 #define WIBBLE_STRING_H
4 
5 /*
6  * Various string functions
7  *
8  * Copyright (C) 2007,2008 Enrico Zini <enrico@debian.org>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  */
24 
25 #include <wibble/operators.h>
26 #include <wibble/sfinae.h>
27 
28 #include <cstdarg>
29 #include <cstdio>
30 #include <string>
31 #include <set>
32 #include <vector>
33 #include <sstream>
34 #include <cctype>
35 #ifdef _WIN32
36 #include <cstring>
37 #include <cstdlib>
38 #endif
39 
40 namespace wibble {
41 namespace str {
42 
43 using namespace wibble::operators;
44 
45 #ifdef _WIN32
46 static int vasprintf (char **, const char *, va_list);
47 #endif
48 
49 std::string fmt( const char* f, ... ) __attribute__ ((deprecated));
50 std::string fmtf( const char* f, ... );
51 template< typename T > inline std::string fmt(const T& val);
52 
53 // Formatting lists -- actually, we need to move list handling into wibble,
54 // really.
55 template< typename X >
56 inline typename TPair< std::ostream, typename X::Type >::First &operator<<(
57  std::ostream &o, X list )
58 {
59  if ( list.empty() )
60  return o << "[]";
61 
62  o << "[ ";
63  while( !list.empty() ) {
64  o << fmt( list.head() );
65  if ( !list.tail().empty() )
66  o << ", ";
67  list = list.tail();
68  }
69  return o << " ]";
70 }
71 
73 template< typename T >
74 inline std::string fmt(const T& val)
75 {
76  std::stringstream str;
77  str << val;
78  return str.str();
79 }
80 
81 template<> inline std::string fmt<std::string>(const std::string& val) {
82  return val;
83 }
84 template<> inline std::string fmt<char*>(char * const & val) { return val; }
85 
86 template< typename C >
87 inline std::string fmt_container( const C &c, char f, char l )
88 {
89  std::string s;
90  s += f;
91  if ( c.empty() )
92  return s + l;
93 
94  s += ' ';
95  for ( typename C::const_iterator i = c.begin(); i != c.end(); ++i ) {
96  s += fmt( *i );
97  if ( i != c.end() && i + 1 != c.end() )
98  s += ", ";
99  }
100  s += ' ';
101  s += l;
102  return s;
103 }
104 
105 // formatting sets using { ... } notation
106 template< typename X >
107 inline std::string fmt(const std::set< X >& val) {
108  return fmt_container( val, '{', '}' );
109 }
110 
111 // formatting vectors using [ ... ] notation
112 template< typename X >
113 inline std::string fmt(const std::vector< X > &val) {
114  return fmt_container( val, '[', ']' );
115 }
116 
118 inline std::string basename(const std::string& pathname)
119 {
120  size_t pos = pathname.rfind("/");
121  if (pos == std::string::npos)
122  return pathname;
123  else
124  return pathname.substr(pos+1);
125 }
126 
128 inline std::string dirname(const std::string& pathname)
129 {
130  size_t pos = pathname.rfind("/");
131  if (pos == std::string::npos)
132  return std::string();
133  else if (pos == 0)
134  // Handle the case of '/foo'
135  return std::string("/");
136  else
137  return pathname.substr(0, pos);
138 }
139 
145 std::string normpath(const std::string& pathname);
146 
148 inline bool startsWith(const std::string& str, const std::string& part)
149 {
150  if (str.size() < part.size())
151  return false;
152  return str.substr(0, part.size()) == part;
153 }
154 
156 inline bool endsWith(const std::string& str, const std::string& part)
157 {
158  if (str.size() < part.size())
159  return false;
160  return str.substr(str.size() - part.size()) == part;
161 }
162 
163 inline std::string replace(const std::string& str, char from, char to)
164 {
165  std::string res;
166  res.reserve(str.size());
167  for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
168  if (*i == from)
169  res.append(1, to);
170  else
171  res.append(1, *i);
172  return res;
173 }
174 
175 #if !__xlC__ && (! __GNUC__ || __GNUC__ >= 4)
176 
180 template<typename FUN>
181 inline std::string trim(const std::string& str, const FUN& classifier)
182 {
183  if (str.empty())
184  return str;
185 
186  size_t beg = 0;
187  size_t end = str.size() - 1;
188  while (beg < end && classifier(str[beg]))
189  ++beg;
190  while (end >= beg && classifier(str[end]))
191  --end;
192 
193  return str.substr(beg, end-beg+1);
194 }
195 
199 inline std::string trim(const std::string& str)
200 {
201  return trim(str, ::isspace);
202 }
203 #else
204 
205 inline std::string trim(const std::string& str)
206 {
207  if (str.empty())
208  return str;
209 
210  size_t beg = 0;
211  size_t end = str.size() - 1;
212  while (beg < end && ::isspace(str[beg]))
213  ++beg;
214  while (end >= beg && ::isspace(str[end]))
215  --end;
216 
217  return str.substr(beg, end-beg+1);
218 }
219 #endif
220 
222 inline std::string toupper(const std::string& str)
223 {
224  std::string res;
225  res.reserve(str.size());
226  for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
227  res += ::toupper(*i);
228  return res;
229 }
230 
232 inline std::string tolower(const std::string& str)
233 {
234  std::string res;
235  res.reserve(str.size());
236  for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
237  res += ::tolower(*i);
238  return res;
239 }
240 
242 inline std::string ucfirst(const std::string& str)
243 {
244  if (str.empty()) return str;
245  std::string res;
246  res += ::toupper(str[0]);
247  return res + tolower(str.substr(1));
248 }
249 
251 inline std::string joinpath(const std::string& path1, const std::string& path2)
252 {
253  if (path1.empty())
254  return path2;
255  if (path2.empty())
256  return path1;
257 
258  if (path1[path1.size() - 1] == '/')
259  if (path2[0] == '/')
260  return path1 + path2.substr(1);
261  else
262  return path1 + path2;
263  else
264  if (path2[0] == '/')
265  return path1 + path2;
266  else
267  return path1 + '/' + path2;
268 }
269 
271 std::string urlencode(const std::string& str);
272 
274 std::string urldecode(const std::string& str);
275 
277 std::string encodeBase64(const std::string& str);
278 
280 std::string decodeBase64(const std::string& str);
281 
294 class Split
295 {
296  std::string sep;
297  std::string str;
298 
299 public:
300  // TODO: add iterator_traits
302  {
303  const std::string& sep;
304  const std::string& str;
305  std::string cur;
306  size_t pos;
307 
308  public:
309  const_iterator(const std::string& sep, const std::string& str) : sep(sep), str(str), pos(0)
310  {
311  ++*this;
312  }
313  const_iterator(const std::string& sep, const std::string& str, bool) : sep(sep), str(str), pos(std::string::npos) {}
314 
315  const_iterator& operator++()
316  {
317  if (pos == str.size())
318  pos = std::string::npos;
319  else
320  {
321  size_t end;
322  if (sep.empty())
323  if (pos + 1 == str.size())
324  end = std::string::npos;
325  else
326  end = pos + 1;
327  else
328  end = str.find(sep, pos);
329  if (end == std::string::npos)
330  {
331  cur = str.substr(pos);
332  pos = str.size();
333  }
334  else
335  {
336  cur = str.substr(pos, end-pos);
337  pos = end + sep.size();
338  }
339  }
340  return *this;
341  }
342 
343  std::string remainder() const
344  {
345  if (pos == std::string::npos)
346  return std::string();
347  else
348  return str.substr(pos);
349  }
350 
351  const std::string& operator*() const
352  {
353  return cur;
354  }
355  const std::string* operator->() const
356  {
357  return &cur;
358  }
359  bool operator==(const const_iterator& ti) const
360  {
361  // Comparing iterators on different strings is not supported for
362  // performance reasons
363  return pos == ti.pos;
364  }
365  bool operator!=(const const_iterator& ti) const
366  {
367  // Comparing iterators on different strings is not supported for
368  // performance reasons
369  return pos != ti.pos;
370  }
371  };
372 
376  Split(const std::string& sep, const std::string& str) : sep(sep), str(str) {}
377 
381  const_iterator begin() const { return const_iterator(sep, str); }
382  const_iterator end() const { return const_iterator(sep, str, false); }
383 };
384 
385 template<typename ITER>
386 std::string join(const ITER& begin, const ITER& end, const std::string& sep = ", ")
387 {
388  std::stringstream res;
389  bool first = true;
390  for (ITER i = begin; i != end; ++i)
391  {
392  if (first)
393  first = false;
394  else
395  res << sep;
396  res << *i;
397  }
398  return res.str();
399 }
400 
416 {
417 public:
418  // TODO: add iterator_traits
420  {
421  std::istream* in;
422  std::pair<std::string, std::string> value;
423  std::string line;
424 
425  public:
426  const_iterator(std::istream& in);
427  const_iterator() : in(0) {}
428 
429  const_iterator& operator++();
430 
431  const std::pair<std::string, std::string>& operator*() const
432  {
433  return value;
434  }
435  const std::pair<std::string, std::string>* operator->() const
436  {
437  return &value;
438  }
439  bool operator==(const const_iterator& ti) const
440  {
441  return in == ti.in;
442  }
443  bool operator!=(const const_iterator& ti) const
444  {
445  return in != ti.in;
446  }
447  };
448 
449  const_iterator begin(std::istream& in) { return const_iterator(in); }
451 };
452 
453 }
454 }
455 
456 // vim:set ts=4 sw=4:
457 #endif