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