// vi:set ft=cpp: -*- Mode: C++ -*- /* * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de> * economic rights: Technische Universität Dresden (Germany) * * This file is part of TUD:OS and distributed under the terms of the * GNU General Public License 2. * Please see the COPYING-GPL-2 file for details. * * As a special exception, you may use this file as part of a free software * library without restriction. Specifically, if other files instantiate * templates or use macros or inline functions from this file, or you compile * this file and link it with other files to produce an executable, this * file does not by itself cause the resulting executable to be covered by * the GNU General Public License. This exception does not however * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. */ /** * Strings. */ #pragma once #include <l4/cxx/minmax> #include <l4/cxx/basic_ostream> namespace cxx { /** * Allocation free string class with explicit length field. * * This class is used to group characters of a string which belong * to one syntactical token types number, identifier, string, * whitespace or another single character. * * Stings in this class can contain null bytes and may denote parts of * other strings. */ class String { public: /// Character index type. typedef char const *Index; /// Initialize from a zero-terminated string. String(char const *s) throw() : _start(s), _len(__builtin_strlen(s)) {} /// Initialize from a pointer to first character and a length. String(char const *s, unsigned long len) throw() : _start(s), _len(len) {} /** * Initialize with start and end pointer. * * \param s first character of the string * \param e pointer to first byte behind the string */ String(char const *s, char const *e) throw() : _start(s), _len(e - s) {} /// Zero-initialize. Create an invalid string. String() : _start(0), _len(0) {} /// Pointer to first character. Index start() const { return _start; } /// Pointer to first byte behind the string. Index end() const { return _start + _len; } /// Length. int len() const { return _len; } /// Set start. void start(char const *s) { _start = s; } /// Set length. void len(unsigned long len) { _len = len; } /// Check if the string has length zero. bool empty() const { return !_len; } /// Return prefix up to index. String head(Index end) const { if (end < _start) return String(); if (eof(end)) return *this; return String(_start, end - _start); } /// Prefix of length `end`. String head(unsigned long end) const { return head(start() + end); } /// Substring of length `len` starting at `idx`. String substr(unsigned long idx, unsigned long len = ~0UL) const { if (idx >= _len) return String(end(), 0UL); return String(_start + idx, cxx::min(len, _len - idx)); } /// Substring of length `len` starting at `start`. String substr(char const *start, unsigned long len = 0) const { if (start >= _start && !eof(start)) { unsigned long nlen = _start + _len - start; if (len != 0) nlen = cxx::min(nlen, len); return String(start, nlen); } return String(end(), 0UL); } /// Find matching character. `match` should be a function such as `isspace`. template< typename F > char const *find_match(F &&match) const { String::Index s = _start; while (1) { if (eof(s)) return s; if (match(*s)) return s; ++s; } } /// Find character. Return end() if not found. char const *find(char const *c) const { return find(c, start()); } /// Find character. Return end() if not found. char const *find(int c) const { return find(c, start()); } /// Find right-most character. Return end() if not found. char const *rfind(char const *c) const { if (!_len) return end(); char const *p = end(); --p; while (p >= _start) { if (*p == *c) return p; --p; } return end(); } /** * Check if `c` is a prefix of string. * * \return 0 if `c` is not a prefix, if it is a prefix, return * first position not in `c` (which might be end()). */ Index starts_with(cxx::String const &c) const { unsigned long i; for (i = 0; i < c._len && i < _len; ++i) if (_start[i] != c[i]) return 0; return i == c._len ? start() + i : 0; } /// Find character `c` starting at position `s`. Return end() if not found. char const *find(int c, char const *s) const { if (s < _start) return end(); while (1) { if (eof(s)) return s; if (*s == c) return s; ++s; } } /** * Find character set at position. * * \param c zero-terminated string of characters to search for * \param s start position of search in string * * \retval end() if no char in `c` is contained in string at or behind `s`. * \retval position in string of some character in `c`. */ char const *find(char const *c, char const *s) const { if (s < _start) return end(); while (1) { if (eof(s)) return s; for (char const *x = c; *x; ++x) if (*s == *x) return s; ++s; } } /// Get character at `idx`. char const &operator [] (unsigned long idx) const { return _start[idx]; } /// Get character at `idx`. char const &operator [] (int idx) const { return _start[idx]; } /// Get character at `idx`. char const &operator [] (Index idx) const { return *idx; } /// Check if pointer `s` points behind string. bool eof(char const *s) const { return s >= _start + _len || !*s; } /** * Convert decimal string to integer. * * \tparam INT result integer type * \param[out] v conversion result * * \return position of first character not converted. */ template<typename INT> int from_dec(INT *v) const { *v = 0; Index c; for (c = start(); !eof(c); ++c) { unsigned char n; if (*c >= '0' && *c <= '9') n = *c - '0'; else return c - start(); *v *= 10; *v += n; } return c - start(); } /** * Convert hex string to integer. * * \tparam INT result integer type * \param[out] v conversion result * * \retval -1 if the maximal amount of digits fitting into `INT` have * been read, * \retval position of first character not converted otherwise. */ template<typename INT> int from_hex(INT *v) const { *v = 0; unsigned shift = 0; Index c; for (c = start(); !eof(c); ++c) { shift += 4; if (shift > sizeof(INT) * 8) return -1; unsigned char n; if (*c >= '0' && *c <= '9') n = *c - '0'; else if (*c >= 'A' && *c <= 'F') n = *c - 'A' + 10; else if (*c >= 'a' && *c <= 'f') n = *c - 'a' + 10; else return c - start(); *v <<= 4; *v |= n; } return c - start(); } /// Equality. bool operator == (String const &o) const { if (len() != o.len()) return false; for (unsigned long i = 0; i < _len; ++i) if (_start[i] != o._start[i]) return false; return true; } /// Inequality. bool operator != (String const &o) const { return ! (operator == (o)); } private: char const *_start; unsigned long _len; }; } /// Write `str` on `s`. inline L4::BasicOStream &operator << (L4::BasicOStream &s, cxx::String const &str) { s.write(str.start(), str.len()); return s; }