L4Re - L4 Runtime Environment
string
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /*
3  * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
4  * economic rights: Technische Universit├Ąt Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  *
10  * As a special exception, you may use this file as part of a free software
11  * library without restriction. Specifically, if other files instantiate
12  * templates or use macros or inline functions from this file, or you compile
13  * this file and link it with other files to produce an executable, this
14  * file does not by itself cause the resulting executable to be covered by
15  * the GNU General Public License. This exception does not however
16  * invalidate any other reasons why the executable file might be covered by
17  * the GNU General Public License.
18  */
19 
20 /**
21  * Strings.
22  */
23 
24 #pragma once
25 
26 #include <l4/cxx/minmax>
27 #include <l4/cxx/basic_ostream>
28 
29 
30 namespace cxx {
31 
32 /**
33  * Allocation free string class with explicit length field.
34  *
35  * This class is used to group characters of a string which belong
36  * to one syntactical token types number, identifier, string,
37  * whitespace or another single character.
38  *
39  * Stings in this class can contain null bytes and may denote parts of
40  * other strings.
41  */
42 class String
43 {
44 public:
45 
46  /// Character index type.
47  typedef char const *Index;
48 
49  /// Initialize from a zero-terminated string.
50  String(char const *s) throw() : _start(s), _len(__builtin_strlen(s)) {}
51  /// Initialize from a pointer to first character and a length.
52  String(char const *s, unsigned long len) throw() : _start(s), _len(len) {}
53 
54  /**
55  * Initialize with start and end pointer.
56  *
57  * \param s first character of the string
58  * \param e pointer to first byte behind the string
59  */
60  String(char const *s, char const *e) throw() : _start(s), _len(e-s) {}
61 
62  /// Zero-initialize. Create an invalid string.
63  String() : _start(0), _len(0) {}
64 
65  /// Pointer to first character.
66  Index start() const { return _start; }
67  /// Pointer to first byte behind the string.
68  Index end() const { return _start + _len; }
69  /// Length.
70  int len() const { return _len; }
71 
72  /// Set start.
73  void start(char const *s) { _start = s; }
74  /// Set length.
75  void len(unsigned long len) { _len = len; }
76  /// Check if the string has length zero.
77  bool empty() const { return !_len; }
78 
79  /// Return prefix up to index.
80  String head(Index end) const
81  {
82  if (end < _start)
83  return String();
84 
85  if (eof(end))
86  return *this;
87 
88  return String(_start, end - _start);
89  }
90 
91  /// Prefix of length `end`.
92  String head(unsigned long end) const
93  { return head(start() + end); }
94 
95  /// Substring of length `len` starting at `idx`.
96  String substr(unsigned long idx, unsigned long len = ~0UL) const
97  {
98  if (idx >= _len)
99  return String(end(), 0UL);
100 
101  return String(_start + idx, cxx::min(len, _len - idx));
102  }
103 
104  /// Substring of length `len` starting at `start`.
105  String substr(char const *start, unsigned long len = 0) const
106  {
107  if (start >= _start && !eof(start))
108  {
109  unsigned long nlen = _start + _len - start;
110  if (len != 0)
111  nlen = cxx::min(nlen, len);
112  return String(start, nlen);
113  }
114 
115  return String(end(), 0UL);
116  }
117 
118  /// Find matching character. `match` should be a function such as `isspace`.
119  template< typename F >
120  char const *find_match(F &&match) const
121  {
122  String::Index s = _start;
123  while (1)
124  {
125  if (eof(s))
126  return s;
127 
128  if (match(*s))
129  return s;
130 
131  ++s;
132  }
133  }
134 
135  /// Find character. Return end() if not found.
136  char const *find(char const *c) const
137  { return find(c, start()); }
138 
139  /// Find character. Return end() if not found.
140  char const *find(int c) const
141  { return find(c, start()); }
142 
143  /// Find right-most character. Return end() if not found.
144  char const *rfind(char const *c) const
145  {
146  if (!_len)
147  return end();
148 
149  char const *p = end();
150  --p;
151  while (p >= _start)
152  {
153  if (*p == *c)
154  return p;
155  --p;
156  }
157  return end();
158 
159  }
160 
161  /**
162  * Check if `c` is a prefix of string.
163  *
164  * \return 0 if `c` is not a prefix, if it is a prefix, return
165  * first position not in `c` (which might be end()).
166  */
167  Index starts_with(cxx::String const &c) const
168  {
169  unsigned long i;
170  for (i = 0; i < c._len && i < _len; ++i)
171  if (_start[i] != c[i])
172  return 0;
173  return i == c._len ? start() + i : 0;
174  }
175 
176  /// Find character `c` starting at position `s`. Return end() if not found.
177  char const *find(int c, char const *s) const
178  {
179  if (s<_start)
180  return end();
181 
182  while (1)
183  {
184  if (eof(s))
185  return s;
186 
187  if (*s == c)
188  return s;
189 
190  ++s;
191  }
192  }
193 
194  /**
195  * Find character set at position.
196  *
197  * \param c zero-terminated string of characters to search for
198  * \param s start position of search in string
199  *
200  * \retval end() if no char in `c` is contained in string at or behind `s`.
201  * \retval position in string of some character in `c`.
202  */
203  char const *find(char const *c, char const *s) const
204  {
205  if (s<_start)
206  return end();
207 
208  while (1)
209  {
210  if (eof(s))
211  return s;
212 
213  for (char const *x = c; *x; ++x)
214  if (*s == *x)
215  return s;
216 
217  ++s;
218  }
219  }
220 
221  /// Get character at `idx`.
222  char const &operator [] (unsigned long idx) const { return _start[idx]; }
223  /// Get character at `idx`.
224  char const &operator [] (int idx) const { return _start[idx]; }
225  /// Get character at `idx`.
226  char const &operator [] (Index idx) const { return *idx; }
227 
228  /// Check if pointer `s` points behind string.
229  bool eof(char const *s) const { return s >= _start + _len || !*s; }
230 
231  /**
232  * Convert decimal string to integer.
233  *
234  * \tparam INT result integer type
235  * \param[out] v conversion result
236  *
237  * \return position of first character not converted.
238  */
239  template<typename INT>
240  int from_dec(INT *v) const
241  {
242  *v = 0;
243  Index c;
244  for (c = start(); !eof(c); ++c)
245  {
246  unsigned char n;
247  if (*c >= '0' && *c <= '9')
248  n = *c - '0';
249  else
250  return c - start();
251 
252  *v *= 10;
253  *v += n;
254  }
255  return c - start();
256  }
257 
258  /**
259  * Convert hex string to integer.
260  *
261  * \tparam INT result integer type
262  * \param[out] v conversion result
263  *
264  * \retval -1 if the maximal amount of digits fitting into `INT` have
265  * been read,
266  * \retval position of first character not converted otherwise.
267  */
268  template<typename INT>
269  int from_hex(INT *v) const
270  {
271  *v = 0;
272  unsigned shift = 0;
273  Index c;
274  for (c = start(); !eof(c); ++c)
275  {
276  shift += 4;
277  if (shift > sizeof(INT) * 8)
278  return -1;
279  unsigned char n;
280  if (*c >= '0' && *c <= '9')
281  n = *c - '0';
282  else if (*c >= 'A' && *c <= 'F')
283  n = *c - 'A' + 10;
284  else if (*c >= 'a' && *c <= 'f')
285  n = *c - 'a' + 10;
286  else
287  return c - start();
288 
289  *v <<= 4;
290  *v |= n;
291  }
292  return c - start();
293  }
294 
295  /// Equality.
296  bool operator == (String const &o) const
297  {
298  if (len() != o.len())
299  return false;
300 
301  for (unsigned long i = 0; i < _len; ++i)
302  if (_start[i] != o._start[i])
303  return false;
304 
305  return true;
306  }
307 
308  /// Inequality.
309  bool operator != (String const &o) const
310  { return ! (operator == (o)); }
311 
312 private:
313 
314  char const *_start;
315  unsigned long _len;
316 
317 };
318 
319 }
320 
321 /// Write `str` on `s`.
322 inline
323 L4::BasicOStream &operator << (L4::BasicOStream &s, cxx::String const &str)
324 {
325  s.write(str.start(), str.len());
326  return s;
327 }