diff -r 792876306489 -r 4dd5bde4e777 sources/mystring.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sources/mystring.cpp Wed Dec 10 19:17:00 2014 +0200 @@ -0,0 +1,482 @@ +/* + Copyright 2014 Teemu Piippo + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "main.h" +#include "mystring.h" +#include "format.h" + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::compare (const String& other) const -> int +{ + return m_string.compare (other.std_string()); +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::trim (int n) -> void +{ + if (n > 0) + m_string = mid (0, length() - n).std_string(); + else + m_string = mid (n, -1).std_string(); +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::strip (const List& unwanted) -> String +{ + String copy (m_string); + + for (char c : unwanted) + { + for (int pos = 0; (pos = copy.find (String (c))) != -1;) + copy.remove (pos--); + } + + return copy; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::to_uppercase() const -> String +{ + String newstr (m_string); + + for (char& c : newstr) + { + if (c >= 'a' and c <= 'z') + c -= 'a' - 'A'; + } + + return newstr; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::to_lowercase() const -> String +{ + String newstr (m_string); + + for (char& c : newstr) + { + if (c >= 'A' and c <= 'Z') + c += 'a' - 'A'; + } + + return newstr; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::split (char del) const -> StringList +{ + String delimstr; + delimstr += del; + return split (delimstr); +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::split (const String& del) const -> StringList +{ + StringList res; + int a = 0; + int b; + + // Find all separators and store the text left to them. + while ((b = find (del, a)) != -1) + { + String sub = mid (a, b); + + if (sub.length() > 0) + res << sub; + + a = b + del.length(); + } + + // Add the string at the right of the last separator + if (a < (int) length()) + res.append (mid (a, length())); + + return res; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::replace (const char* a, const char* b) -> void +{ + long pos; + + while ((pos = find (a)) != -1) + m_string = m_string.replace (pos, strlen (a), b); +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::count (char needle) const -> int +{ + int needles = 0; + + for (const char & c : m_string) + if (c == needle) + needles++; + + return needles; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::mid (long a, long b) const -> String +{ + if (b == -1 or b > length()) + b = length(); + + if (b == a) + return ""; + + if (b < a) + swap (a, b); + + if (a == 0 and b == length()) + return *this; + + char* newstr = new char[b - a + 1]; + strncpy (newstr, chars() + a, b - a); + newstr[b - a] = '\0'; + String other (newstr); + delete[] newstr; + return other; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::word_position (int n) const -> int +{ + int count = 0; + + for (int i = 0; i < length(); ++i) + { + if (m_string[i] != ' ') + continue; + + if (++count < n) + continue; + + return i; + } + + return -1; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::find (const char* c, int a) const -> int +{ + int pos = m_string.find (c, a); + + if (pos == int (std::string::npos)) + return -1; + + return pos; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::find_last (const char* c, int a) const -> int +{ + if (a == -1 or a >= length()) + a = length() - 1; + + for (; a > 0; a--) + if (m_string[a] == c[0] and strncmp (chars() + a, c, strlen (c)) == 0) + return a; + + return -1; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::to_int (bool* ok, int base) const -> long +{ + errno = 0; + char* endptr; + long i = strtol (chars(), &endptr, base); + + if (ok) + *ok = (errno == 0 and *endptr == '\0'); + + return i; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::to_float (bool* ok) const -> float +{ + errno = 0; + char* endptr; + float i = strtof (chars(), &endptr); + + if (ok != nullptr) + *ok = (errno == 0 and *endptr == '\0'); + + return i; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::to_double (bool* ok) const -> double +{ + errno = 0; + char* endptr; + double i = strtod (chars(), &endptr); + + if (ok != nullptr) + *ok = (errno == 0 and *endptr == '\0'); + + return i; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::operator+ (const String& data) const -> String +{ + String newString = *this; + newString.append (data); + return newString; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::operator+ (const char* data) const -> String +{ + String newstr = *this; + newstr.append (data); + return newstr; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::is_numeric() const -> bool +{ + bool gotDot = false; + + for (const char & c : m_string) + { + // Allow leading hyphen for negatives + if (&c == &m_string[0] and c == '-') + continue; + + // Check for decimal point + if (!gotDot and c == '.') + { + gotDot = true; + continue; + } + + if (c >= '0' and c <= '9') + continue; // Digit + + // If the above cases didn't catch this character, it was + // illegal and this is therefore not a number. + return false; + } + + return true; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::ends_with (const String& other) -> bool +{ + if (length() < other.length()) + return false; + + const int ofs = length() - other.length(); + return strncmp (chars() + ofs, other.chars(), other.length()) == 0; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::starts_with (const String& other) -> bool +{ + if (length() < other.length()) + return false; + + return strncmp (chars(), other.chars(), other.length()) == 0; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::sprintf (const char* fmtstr, ...) -> void +{ + char* buf; + int bufsize = 256; + va_list va; + va_start (va, fmtstr); + + do + buf = new char[bufsize]; + while (vsnprintf (buf, bufsize, fmtstr, va) >= bufsize); + + va_end (va); + m_string = buf; + delete[] buf; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +StringList::join (const String& delim) -> String +{ + String result; + + for (const String& it : container()) + { + if (result.is_empty() == false) + result += delim; + + result += it; + } + + return result; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::mask_against (const String& pattern) const -> bool +{ + // Elevate to uppercase for case-insensitive matching + String pattern_upper = pattern.to_uppercase(); + String this_upper = to_uppercase(); + const char* maskstring = pattern_upper.chars(); + const char* mptr = &maskstring[0]; + + for (const char* sptr = this_upper.chars(); *sptr != '\0'; sptr++) + { + if (*mptr == '?') + { + if (*(sptr + 1) == '\0') + { + // ? demands that there's a character here and there wasn't. + // Therefore, mask matching fails + return false; + } + } + else if (*mptr == '*') + { + char end = *(++mptr); + + // If '*' is the final character of the message, all of the remaining + // string matches against the '*'. We don't need to bother checking + // the string any further. + if (end == '\0') + return true; + + // Skip to the end character + while (*sptr != end and *sptr != '\0') + sptr++; + + // String ended while the mask still had stuff + if (*sptr == '\0') + return false; + } + else if (*sptr != *mptr) + return false; + + mptr++; + } + + return true; +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::from_number (int a) -> String +{ + char buf[32]; + ::sprintf (buf, "%d", a); + return String (buf); +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::from_number (long a) -> String +{ + char buf[32]; + ::sprintf (buf, "%ld", a); + return String (buf); +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::from_number (unsigned long a) -> String +{ + char buf[32]; + ::sprintf (buf, "%lu", a); + return String (buf); +} + +// ------------------------------------------------------------------------------------------------- + +METHOD +String::from_number (double a) -> String +{ + char buf[64]; + ::sprintf (buf, "%f", a); + return String (buf); +}