# HG changeset patch # User Teemu Piippo # Date 1611749093 -7200 # Node ID 20ca0a6be1759ccfa1497ac5450007fd020db494 # Parent e254398fcc7cafc20962ed2b7257986fb826cb5b removed the String class in favor of std::string diff -r e254398fcc7c -r 20ca0a6be175 sources/coloredline.cpp --- a/sources/coloredline.cpp Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/coloredline.cpp Wed Jan 27 14:04:53 2021 +0200 @@ -127,11 +127,11 @@ { if (ch == ']') { - String color = m_incomingColorName.toLowerCase(); + String color = to_lowercase(m_incomingColorName); for (const ColorCodeInfo &colorInfo : colorCodes) { - if (String(colorInfo.name).toLowerCase() == color) + if (to_lowercase(colorInfo.name) == color) { activateColor(colorInfo.color, colorInfo.bold); m_colorCodeStage = 0; diff -r e254398fcc7c -r 20ca0a6be175 sources/interface.cpp --- a/sources/interface.cpp Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/interface.cpp Wed Jan 27 14:04:53 2021 +0200 @@ -203,13 +203,13 @@ // void Interface::renderTitlebar() { - if (m_title.length() <= COLS) + if (static_cast(m_title.length()) <= COLS) { chtype pair = getColorPair(WHITE, BLUE); int startx =(COLS - m_title.length()) / 2; int endx = startx + m_title.length(); attron(pair); - mvprintw(0, startx, "%s", m_title.chars()); + mvprintw(0, startx, "%s", m_title.data()); mvhline(0, 0, ' ', startx); mvhline(0, endx, ' ', COLS - endx); attroff(pair); @@ -430,7 +430,7 @@ } // Ensure the cursor is within bounds - m_cursorPosition = clamp(m_cursorPosition, 0, displayString.length()); + m_cursorPosition = clamp(m_cursorPosition, 0, static_cast(displayString.length())); // Ensure that the cursor is always in view, adjust panning if this is not the case if (m_cursorPosition > m_inputPanning + displayLength) @@ -445,11 +445,11 @@ // Render the input string mvhline(LINES - 2, 0, ' ', COLS); - mvprintw(y, prompt.length() + 1, "%s", displayString.mid(start, end).chars()); + mvprintw(y, prompt.length() + 1, "%s", mid(displayString, start, end).data()); // Render the prompt attron(promptColor); - mvprintw(y, 0, "%s", prompt.chars()); + mvprintw(y, 0, "%s", prompt.data()); attroff(promptColor); // Store in memory where the cursor is now(so that we can re-draw it to position the terminal @@ -468,7 +468,7 @@ int y = LINES - 1; attron(color); mvhline(y, 0, ' ', COLS); - mvprintw(y, 0, "%s", m_statusBarText.chars()); + mvprintw(y, 0, "%s", m_statusBarText.data()); attroff(color); m_needRefresh = true; m_needStatusBarRender = false; @@ -501,19 +501,19 @@ } else { - adminText.sprintf("%d other admin%s", m_session.getAdminCount(), + adminText = zfc::sprintf("%d other admin%s", m_session.getAdminCount(), m_session.getAdminCount() != 1 ? "s" : ""); } - text.sprintf("%s | %s | %s", - m_session.address().to_string(IPAddress::WITH_PORT).chars(), - m_session.getLevel().chars(), - adminText.chars()); + text = zfc::sprintf("%s | %s | %s", + m_session.address().to_string(IPAddress::WITH_PORT).data(), + m_session.getLevel().data(), + adminText.data()); } break; } - if (not text.isEmpty()) + if (not text.empty()) text += " | "; text += "Ctrl+N to connect, Ctrl+Q to "; @@ -580,7 +580,7 @@ int pos = m_cursorPosition; // Move past current whitespace - while (pos < input.length() and isspace(input[pos])) + while (pos < static_cast(input.length()) and isspace(input[pos])) pos++; // Move past the word @@ -601,8 +601,8 @@ m_cursorPosition = a; String& input = getEditableInput(); - m_pasteBuffer = input.mid(a, b); - input.remove(a, b - a); + m_pasteBuffer = mid(input, a, b); + input = remove_range(input, a, b - a); m_needInputRender = true; } @@ -637,7 +637,9 @@ if (ch >= 0x20 and ch <= 0x7E) { - getEditableInput().insert(m_cursorPosition++, char(ch)); + std::string& input = getEditableInput(); + input.insert(input.begin() + m_cursorPosition, char(ch)); + m_cursorPosition += 1; m_needInputRender = true; } else switch (ch) @@ -683,7 +685,7 @@ case KEY_RIGHT: case 'F' - 'A' + 1: // readline ^F - if (m_cursorPosition < getCurrentInput().length()) + if (m_cursorPosition < static_cast(getCurrentInput().length())) { m_cursorPosition++; m_needInputRender = true; @@ -706,7 +708,7 @@ case KEY_END: case 'E' - 'A' + 1: // readline ^E - if (m_cursorPosition != getCurrentInput().length()) + if (m_cursorPosition != static_cast(getCurrentInput().length())) { m_cursorPosition = getCurrentInput().length(); m_needInputRender = true; @@ -717,16 +719,19 @@ case '\b': if (m_cursorPosition > 0) { - getEditableInput().removeAt(--m_cursorPosition); + String& input = getEditableInput(); + input.erase(input.begin() + m_cursorPosition); + m_cursorPosition -= 1; m_needInputRender = true; } break; case KEY_DC: case 'D' - 'A' + 1: // readline ^D - if (m_cursorPosition < getCurrentInput().length()) + if (m_cursorPosition < static_cast(getCurrentInput().length())) { - getEditableInput().removeAt(m_cursorPosition); + String& input = getEditableInput(); + input.erase(input.begin() + m_cursorPosition); m_needInputRender = true; } break; @@ -758,7 +763,7 @@ break; case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text - if (not m_pasteBuffer.isEmpty()) + if (not m_pasteBuffer.empty()) { getEditableInput().insert(m_cursorPosition, m_pasteBuffer); m_cursorPosition += m_pasteBuffer.length(); @@ -774,7 +779,7 @@ and m_cursorPosition > 0 and(space == -1 or space >= m_cursorPosition)) { - String start = getCurrentInput().mid(0, m_cursorPosition); + String start = mid(getCurrentInput(), 0, m_cursorPosition); m_session.requestTabCompletion(start); } } @@ -806,7 +811,7 @@ break; case INPUTSTATE_PASSWORD: - if (m_inputState == INPUTSTATE_PASSWORD and not getCurrentInput().isEmpty()) + if (m_inputState == INPUTSTATE_PASSWORD and not getCurrentInput().empty()) { m_session.disconnect(); m_session.setPassword(getCurrentInput()); @@ -904,7 +909,7 @@ void Interface::vprint(const char* fmtstr, va_list args) { String message; - message.vsprintf(fmtstr, args); + message = vsprintf(fmtstr, args); printToConsole(message); } @@ -957,7 +962,7 @@ { // Zandronum sometimes sends color codes as "\\c" and sometimes as "\x1C". // Let's correct that on our end and hope this won't cause conflicts. - message.replace("\\c", "\x1C"); + replace_all(message, "\\c", "\x1C"); for (char ch : message) { @@ -1034,7 +1039,7 @@ { String& input = getEditableInput(); - if (input.startsWith(part)) + if (starts_with(input, part)) { if (input[part.length()] != ' ') complete += ' '; @@ -1052,8 +1057,8 @@ if (input[0] != '/') return; - StringList args = input.right(input.length() - 1).split(" "); - String command = args[0].toLowerCase(); + StringList args = split(right(input, input.length() - 1), " "); + String command = to_lowercase(args[0]); args.erase(args.begin()); if (command == "connect") @@ -1095,14 +1100,14 @@ throw Exitception(); } else - printError("Unknown command: %s\n", command.chars()); + printError("Unknown command: %s\n", command.data()); } // ------------------------------------------------------------------------------------------------- // void Interface::disconnected() { - print("Disconnected from %s\n", m_session.address().to_string(IPAddress::WITH_PORT).chars()); + print("Disconnected from %s\n", m_session.address().to_string(IPAddress::WITH_PORT).data()); resetTitle(); renderFull(); } @@ -1111,7 +1116,7 @@ // void Interface::resetTitle() { - m_title.sprintf("%s %s (%s)", application_name(), full_version_string(), changeset_date_string()); + m_title = sprintf("%s %s (%s)", application_name(), full_version_string(), changeset_date_string()); } // ------------------------------------------------------------------------------------------------- diff -r e254398fcc7c -r 20ca0a6be175 sources/list.cpp --- a/sources/list.cpp Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/list.cpp Wed Jan 27 14:04:53 2021 +0200 @@ -29,7 +29,6 @@ */ #include "list.h" -#include "mystring.h" BEGIN_ZFC_NAMESPACE @@ -76,9 +75,9 @@ } } -String quote(const ByteArray &bytes) +std::string quote(const ByteArray &bytes) { - String result; + std::string result; for (unsigned char byte : bytes) result += representByte(byte); diff -r e254398fcc7c -r 20ca0a6be175 sources/list.h --- a/sources/list.h Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/list.h Wed Jan 27 14:04:53 2021 +0200 @@ -30,6 +30,7 @@ #pragma once #include +#include #include "basics.h" #include "range.h" BEGIN_ZFC_NAMESPACE @@ -44,7 +45,7 @@ } using ByteArray = std::vector; -class String quote(const ByteArray& bytes); +std::string quote(const ByteArray& bytes); template T splice(const T& container, int start, int end, int step = 1) diff -r e254398fcc7c -r 20ca0a6be175 sources/md5.cpp --- a/sources/md5.cpp Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/md5.cpp Wed Jan 27 14:04:53 2021 +0200 @@ -306,4 +306,12 @@ } } +std::string md5(const char *buffer) +{ + char checksum[33]; + CalculateMD5(reinterpret_cast(buffer), strlen(buffer), checksum); + checksum[sizeof checksum - 1] = '\0'; + return {checksum}; +} + END_ZFC_NAMESPACE \ No newline at end of file diff -r e254398fcc7c -r 20ca0a6be175 sources/md5.h --- a/sources/md5.h Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/md5.h Wed Jan 27 14:04:53 2021 +0200 @@ -1,7 +1,9 @@ #pragma once +#include #include "basics.h" BEGIN_ZFC_NAMESPACE void CalculateMD5 (unsigned char const *buffer, int length, char *checksum); +std::string md5(const char* buffer); END_ZFC_NAMESPACE diff -r e254398fcc7c -r 20ca0a6be175 sources/mystring.cpp --- a/sources/mystring.cpp Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/mystring.cpp Wed Jan 27 14:04:53 2021 +0200 @@ -31,46 +31,17 @@ #include #include "main.h" #include "mystring.h" -#include "md5.h" BEGIN_ZFC_NAMESPACE /*! - * \brief Compares this string with another. - * \param other The string to compare with. - * \returns -1 if this string is lexicographically less than \c other, - * 0 if they are equal, or - * 1 if this string is lexicographically greater than \c other. - */ -int String::compare (const String& other) const -{ - return m_string.compare (other.stdString()); -} - -/*! - * \returns an upper-case version of this string. - */ -String String::toUpperCase() const -{ - String result (m_string); - - for (char &ch : result) - { - if (islower(ch)) - ch -= 'a' - 'A'; - } - - return result; -} - -/*! * \returns a lower-case version of this string. */ -String String::toLowerCase() const +std::string to_lowercase(const std::string& string) { - String result (m_string); + String result = string; - for (char &ch : result) + for (char& ch : result) { if (isupper(ch)) ch += 'a' - 'A'; @@ -80,74 +51,35 @@ } /*! - * \brief Splits this string using the provided delimeter. - * \param delimeter Delimeter to use for splitting. - * \returns a string list containing the split strings. + * \brief Joins the elements of this string list into one longer string. + * \param delimeter The delimeter to place between the element strings. + * \returns the catenated string. */ -StringList String::split (char delimeter) const -{ - String delimeterString; - delimeterString += delimeter; - return split (delimeterString); -} - -/*! - * \brief Splits this string using the provided delimeter. - * \param delimeter Delimeter to use for splitting. - * \returns a string list containing the split strings. - */ -StringList String::split (const String& delimeter) const +std::string join_string_list(const StringList& strings, const std::string& delimeter) { - StringList result; - int a = 0; - int b; - - // Find all separators and store the text left to them. - while ((b = find (delimeter, a)) != -1) - { - String sub = mid (a, b); + std::string result; - if (sub.length() > 0) - result.push_back(sub); + for (const std::string &item : strings) + { + if (not result.empty()) + result += delimeter; - a = b + delimeter.length(); + result += item; } - // Add the string at the right of the last separator - if (a < (int) length()) - result.push_back(mid(a, length())); - return result; } /*! - * \brief Replaces all instances of \c text with \c replacement. - * \param text Text to replace away. - * \param replacement Text to replace \c text with. + * \brief Modifies the given index so that if it is negative, it is translated into a positive index starting from the + * end of the string. For example, an index of -1 will be modified to point to the last character in the string, + * -2 to the second last, etc. + * \param index Index to translate. */ -void String::replace (const char* text, const char* replacement) +inline void modifyIndex(const std::string& str, int& index) { - int position; - - while ((position = find (text)) != -1) - m_string = m_string.replace (position, strlen (text), replacement); -} - -/*! - * \param character Character to count. - * \returns the amount of \c character found in the string. - */ -int String::count (char character) const -{ - int result = 0; - - for (char ch : *this) - { - if (ch == character) - result++; - } - - return result; + if (index < 0) + index = str.length() - index; } /*! @@ -155,204 +87,29 @@ * \param b Ending index of the range. * \returns a sub-string containing all characters from \c a to \c b, not including the character at \c b. */ -String String::mid (int rangeBegin, int rangeEnd) const +std::string mid(const std::string& str, int rangeBegin, int rangeEnd) { - modifyIndex(rangeBegin); - modifyIndex(rangeEnd); + modifyIndex(str, rangeBegin); + modifyIndex(str, rangeEnd); rangeBegin = max(rangeBegin, 0); - rangeEnd = min(rangeEnd, length()); + rangeEnd = min(rangeEnd, static_cast(str.length())); if (rangeEnd <= rangeBegin) return ""; else - return m_string.substr(rangeBegin, rangeEnd - rangeBegin); + return str.substr(rangeBegin, rangeEnd - rangeBegin); } /*! * \param length Amount of characters to return. * \returns the \c length right-most characters of the string. */ -String String::right(int length) const -{ - if (length >= this->length()) - return *this; - else - return String(chars() + this->length() - length); -} - -/*! - * \brief Finds the first instance of a sub-string. - * \param subString Sub-string to search within this string. - * \param startingPosition Position to start looking for the sub-string from. - * \returns the position the first instance of sub-string found, or -1 if not found. - */ -int String::find (const char* subString, int startingPosition) const -{ - int position = m_string.find (subString, startingPosition); - - if (position == int (std::string::npos)) - return -1; - else - return position; -} - -/*! - * \brief Finds the first instance of a character. - * \param character Character to search within this string. - * \param startingPosition Position to start looking for the character from. - * \returns the position of the first instance of the provided character found, or -1 if not found. - */ -int String::find (char character, int startingPosition) const -{ - int position = m_string.find (character, startingPosition); - - if (position == int (std::string::npos)) - return -1; - else - return position; -} - -/*! - * \brief Finds the last instance of a sub-string. - * \param subString Sub-string to search within this string. - * \param startingPosition Position to start looking for the sub-string from. - * \returns the position the last instance of sub-string found, or -1 if not found. - */ -int String::findLast (const char* subString, int startingPosition) const -{ - modifyIndex(startingPosition); - - for (; startingPosition > 0; startingPosition--) - { - if (strncmp (chars() + startingPosition, subString, strlen (subString)) == 0) - return startingPosition; - } - - return -1; -} - -/*! - * \brief Converts this string to an integer. - * \param ok An pointer to a boolean to store whether or not the conversion was successful. - * If \c ok is \c NULL, the success state is not stored. - * \param base The base to interpret this string with. - * \returns the resulting integer. - */ -long String::toInt (bool* ok, int base) const -{ - errno = 0; - char* endPointer; - long result = strtol (chars(), &endPointer, base); - - if (ok != nullptr) - *ok = (errno == 0 and *endPointer == '\0'); - - return result; -} - -/*! - * \brief Converts this string to a floating-point number. - * \param ok An pointer to a boolean to store whether or not the conversion was successful. - * If \c ok is \c NULL, the success state is not stored. - * \returns the resulting floating-point number. - */ -float String::toFloat (bool* ok) const +std::string right(const std::string& str, int length) { - return static_cast(toDouble(ok)); -} - -/*! - * \brief Converts this string to a double-precision floating-point number. - * \param ok An pointer to a boolean to store whether or not the conversion was successful. - * If \c ok is \c NULL, the success state is not stored. - * \returns the resulting floating-point number. - */ -double String::toDouble (bool* ok) const -{ - errno = 0; - char* endptr; - double i = strtod (chars(), &endptr); - - if (ok != nullptr) - *ok = (errno == 0 and *endptr == '\0'); - - return i; -} - -/*! - * \brief Catenates this string with another string. - * \param text String to catenate to the end of this string. - * \returns the resulting string. - */ -String String::operator+ (const String& text) const -{ - String newString = *this; - newString.append (text); - return newString; -} - -/*! - * \brief Catenates this string with another string. - * \param text String to catenate to the end of this string. - * \returns the resulting string. - */ -String String::operator+ (const char* text) const -{ - String newString = *this; - newString.append (text); - return newString; -} - -/*! - * \returns whether or not this string represents a number. - */ -bool String::isNumeric() const -{ - char* endPointer; - strtol (chars(), &endPointer, 10); - return (endPointer != nullptr) and (*endPointer != '\0'); -} - -/*! - * \param other Sub-string to find from the end of this string. - * \return whether or not this string ends with the provided sub-string. - */ -bool String::endsWith (const String& other) const -{ - if (length() < other.length()) - { - return false; - } + if (length >= static_cast(str.length())) + return str; else - { - const int offset = length() - other.length(); - return strncmp (chars() + offset, other.chars(), other.length()) == 0; - } -} - -/*! - * \param other Sub-string to find from the beginning of this string. - * \returns whether or not this string begins with the provided sub-string. - */ -bool String::startsWith (const String& other) const -{ - if (length() < other.length()) - return false; - else - return strncmp (chars(), other.chars(), other.length()) == 0; -} - -/*! - * \brief Formats this string using \c printf -like syntax. - * \param formatString Template string to use with formatting. - * \param ... Variadic arguments to use with formatting. - */ -void __cdecl String::sprintf (const char* formatString, ...) -{ - va_list args; - va_start (args, formatString); - this->vsprintf (formatString, args); - va_end (args); + return std::string{str.data() + str.length() - length}; } /*! @@ -360,8 +117,10 @@ * \param formatString Template string to use with formatting. * \param args Variadic arguments to use with formatting. */ -void String::vsprintf (const char* formatString, va_list args) +std::string vsprintf(const char* formatString, va_list args) { + std::string result; + // Copy the argument list so that we have something to provide to vsnprintf in case we have to call it again. va_list argsCopy; va_copy(argsCopy, args); @@ -373,192 +132,118 @@ if (length < sizeof buffer) { // vsnprintf succeeded in fitting the formatted string into the buffer, so we're done. - m_string = buffer; + result = buffer; } else { // vsnprintf needs more space, so we have to allocate a new buffer and try again. Vector newBuffer(length + 1); vsnprintf(newBuffer.data(), length + 1, formatString, argsCopy); - m_string = newBuffer.data(); + result = newBuffer.data(); + } + + return result; +} + +/*! + * \brief Formats this string using \c printf -like syntax. + * \param formatString Template string to use with formatting. + * \param ... Variadic arguments to use with formatting. + */ +std::string __cdecl sprintf(const char* formatString, ...) +{ + va_list args; + va_start (args, formatString); + std::string result = vsprintf(formatString, args); + va_end (args); + return result; +} + +std::string remove_range(const std::string &string, int start, int end) +{ + std::string result; + result.reserve(string.length() - (end - start)); + std::copy(string.begin(), string.begin() + start, std::back_inserter(result)); + std::copy(string.begin() + end, string.end(), std::back_inserter(result)); + return result; +} + + +/*! + * \param other Sub-string to find from the beginning of this string. + * \returns whether or not this string begins with the provided sub-string. + */ +bool starts_with(const std::string& str, const String& other) +{ + if (str.length() < other.length()) + return false; + else + return std::strncmp(str.data(), other.data(), other.length()) == 0; +} + +/*! + * \brief Replaces all instances of \c text with \c replacement. + * \param text Text to replace away. + * \param replacement Text to replace \c text with. + */ +void replace_all(std::string& str, const char* text, const char* replacement) +{ + int position; + while ((position = str.find(text)) != -1) + { + str.replace(position, std::strlen(text), replacement); } } /*! - * \brief Joins the elements of this string list into one longer string. - * \param delimeter The delimeter to place between the element strings. - * \returns the catenated string. + * \brief Splits this string using the provided delimeter. + * \param delimeter Delimeter to use for splitting. + * \returns a string list containing the split strings. */ -String join_string_list(const StringList& strings, const String& delimeter) +StringList split(const std::string& string, const String& delimeter) { - String result; + StringList result; + int a = 0; + int b; - for (const String &item : strings) + // Find all separators and store the text left to them. + while ((b = string.find(delimeter, a)) != -1) { - if (result.isEmpty() == false) - result += delimeter; + String sub = mid(string, a, b); + + if (sub.length() > 0) + result.push_back(sub); - result += item; + a = b + delimeter.length(); } + // Add the string at the right of the last separator + if (a < static_cast(string.length())) + result.push_back(mid(string, a, string.length())); + return result; } /*! - * \brief Tries to match this string against a mask pattern. In the pattern, '?' refers to one character, and '*' to - * any number of characters. - * \param pattern The masking pattern to use for matching. - * \returns whether or not this string matches the provided pattern. + * \brief Converts this string to an integer. + * \param ok An pointer to a boolean to store whether or not the conversion was successful. + * If \c ok is \c NULL, the success state is not stored. + * \param base The base to interpret this string with. + * \returns the resulting integer. */ -bool String::maskAgainst (const String& pattern) const -{ - // Elevate to uppercase for case-insensitive matching - String pattern_upper = pattern.toUpperCase(); - String this_upper = toUpperCase(); - 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; -} - -/*! - * \brief Converts a short integer into a string. - * \param value The value to convert. - * \returns the resulting string. - */ -String String::fromNumber (short int value) -{ - char buffer[32]; - ::sprintf (buffer, "%d", value); - return String (buffer); -} - -/*! - * \brief Converts an integer into a string. - * \param value The value to convert. - * \returns the resulting string. - */ -String String::fromNumber (int value) +std::optional to_int(const char* str, int base) { - char buffer[32]; - ::sprintf (buffer, "%d", value); - return String (buffer); -} - -/*! - * \brief Converts a long integer into a string. - * \param value The value to convert. - * \returns the resulting string. - */ -String String::fromNumber (long int value) -{ - char buffer[32]; - ::sprintf (buffer, "%ld", value); - return String (buffer); -} - -/*! - * \brief Converts an unsigned short integer into a string. - * \param value The value to convert. - * \returns the resulting string. - */ -String String::fromNumber (unsigned short int value) -{ - char buffer[32]; - ::sprintf (buffer, "%u", value); - return String (buffer); -} - -/*! - * \brief Converts an unsigned integer into a string. - * \param value The value to convert. - * \returns the resulting string. - */ -String String::fromNumber (unsigned int value) -{ - char buffer[32]; - ::sprintf (buffer, "%u", value); - return String (buffer); -} - -/*! - * \brief Converts an unsigned long integer into a string. - * \param value The value to convert. - * \returns the resulting string. - */ -String String::fromNumber (unsigned long int value) -{ - char buffer[32]; - ::sprintf (buffer, "%lu", value); - return String (buffer); -} - -/*! - * \brief Converts a double-precision floating point number into a string, using the "%f" format specifier. - * \param value The value to convert. - * \returns the resulting string. - */ -String String::fromNumber (double value) -{ - char buffer[64]; - ::sprintf (buffer, "%f", value); - return String (buffer); -} - -/*! - * \brief Constructs a string from a vector of bytes. The bytes do not have to be null-terminated. - * \param bytes Bytes to use for construction - * \returns the resulting string. - */ -String String::fromBytes(const ByteArray& bytes) -{ - return String(reinterpret_cast&>(bytes)); -} - -/*! - * \returns the MD5-checksum of this string. - */ -String String::md5() const -{ - char checksum[33]; - CalculateMD5 (reinterpret_cast (chars()), length(), checksum); - checksum[sizeof checksum - 1] = '\0'; - return String (checksum); + errno = 0; + char* endPointer; + long result = strtol(str, &endPointer, base); + if (errno == 0 and *endPointer == '\0') + { + return result; + } + else + { + return {}; + } } /*! @@ -566,32 +251,26 @@ * something else than whitespace. * \param filter The filtering function to use. */ -void String::normalize (int (*filter)(int)) +void normalize(std::string& string, int (*filter)(int)) { int a = 0; - int b = length() - 1; - - while ((*filter) (m_string[a]) and a != b) + int b = string.length() - 1; + while ((*filter)(string[a]) and a != b) + { ++a; - - while ((*filter) (m_string[b]) and a != b) + } + while ((*filter)(string[b]) and a != b) + { --b; - + } if (a == b) - m_string = ""; - else if (a != 0 or b != length() - 1) - m_string = m_string.substr (a, b - a + 1); -} - -/*! - * \returns a version of this string without leading or trailing whitespace. Alternatively a custom filter can be used - * to strip something else than whitespace. - */ -String String::normalized (int (*filter)(int)) const -{ - String result = *this; - result.normalize(filter); - return result; + { + string = ""; + } + else if (a != 0 or b != static_cast(string.length() - 1)) + { + string = string.substr (a, b - a + 1); + } } END_ZFC_NAMESPACE diff -r e254398fcc7c -r 20ca0a6be175 sources/mystring.h --- a/sources/mystring.h Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/mystring.h Wed Jan 27 14:04:53 2021 +0200 @@ -37,544 +37,21 @@ BEGIN_ZFC_NAMESPACE -using StringList = std::vector; - -class String -{ -public: - typedef std::string::iterator Iterator; - typedef std::string::const_iterator ConstIterator; - - String(); - String(char a); - String(const char* data); - String(const std::string& data); - String(const Vector& data); - - void append(const char* text); - void append(char character); - void append(const String& text); - ConstIterator begin() const; - Iterator begin(); - int compare(const String &other) const; - int count(char character) const; - const char* chars() const; - void clear(); - ConstIterator end() const; - Iterator end(); - bool endsWith(const String &other) const; - int find(const char* subString, int startingPosition = 0) const; - int find(char character, int startingPosition = 0) const; - int indexDifference(int a, int b); - void insert(int position, char character); - void insert(int position, const char* string); - bool isEmpty() const; - bool isNumeric() const; - void modifyIndex(int &a) const; - int findLast(const char* subString, int startingPosition = -1) const; - int length() const; - bool maskAgainst(const String &pattern) const; - String md5() const; - String mid(int rangeBegin, int rangeEnd) const; - void normalize(int(*filter)(int) = &isspace); - String normalized(int(*filter)(int) = &isspace) const; - void prepend(String text); - void remove(int position, int length); - void removeAt(int position); - void removeFromEnd(int length); - void removeFromStart(int length); - void replace(const char* text, const char* replacement); - void replace(int position, int amount, const String &text); - String right(int length) const; - void shrinkToFit(); - StringList split(const String &delimeter) const; - StringList split(char delimeter) const; - void __cdecl sprintf(const char* fmtstr, ...); - bool startsWith(const String &other) const; - const std::string& stdString() const; - const unsigned char* toBytes() const; - double toDouble(bool* ok = nullptr) const; - float toFloat(bool* ok = nullptr) const; - long toInt(bool* ok = nullptr, int base = 10) const; - String toLowerCase() const; - String toUpperCase() const; - void vsprintf(const char* fmtstr, va_list args); - - static String fromNumber(short int a); - static String fromNumber(int a); - static String fromNumber(long int a); - static String fromNumber(unsigned short int a); - static String fromNumber(unsigned int a); - static String fromNumber(unsigned long int a); - static String fromNumber(double a); - static String fromBytes(const ByteArray& bytes); - - String operator+(const String& data) const; - String operator+(const char* data) const; - String operator+(int num) const; - String& operator+=(const String& data); - String& operator+=(const char* data); - String& operator+=(int num); - String& operator+=(char data); - char& operator[](int i); - char operator[](int i) const; - bool operator==(const String& other) const; - bool operator==(const char* other) const; - bool operator!=(const String& other) const; - bool operator!=(const char* other) const; - bool operator>(const String& other) const; - bool operator<(const String& other) const; - bool operator>=(const String& other) const; - bool operator<=(const String& other) const; - operator const char*() const; - operator const std::string&() const; - -private: - std::string m_string; -}; - -String join_string_list(const StringList& strings, const String& delim); - -inline bool operator==(const char* a, const String& b); -inline String operator+(const char* a, const String& b); - -// -------------------------------------------------------------------------------------------------------------------- - -/*! - * \brief Constructs an empty string. - */ -inline String::String() {} - -/*! - * \brief Constructs a string from a single character. - * \param character Character to create a string out of. - */ -inline String::String(char character) -{ - char buffer[2] = { character, '\0' }; - m_string = buffer; -} - -/*! - * \brief Constructs a string from a char-array. - * \param string char-array to convert. - */ -inline String::String(const char* string) : - m_string(string) {} - -/*! - * \brief Constructs a string out of a \c std::string . - * \param string \c std::string to base the construction on. - */ -inline String::String(const std::string& string) : - m_string(string) {} - -/*! - * \brief Constructs a string out of a vector of characters. The vector does not have to be null-terminated. - * \param charVector Vector of characters to construct the string out of. - */ -inline String::String(const Vector& charVector) : - m_string(charVector.data(), charVector.size()) {} - -/*! - * \returns a constant iterator to the beginning of the string. - */ -inline String::ConstIterator String::begin() const -{ - return m_string.cbegin(); -} - -/*! - * \returns the string's contents as a char-array. - */ -inline const char* String::chars() const -{ - return m_string.c_str(); -} - -/*! - * \returns the string's constant end-iterator. - */ -inline String::ConstIterator String::end() const -{ - return m_string.end(); -} - -/*! - * \returns whether or not the string is empty. - */ -inline bool String::isEmpty() const -{ - return m_string[0] == '\0'; -} - -/*! - * \returns the length of the string. - */ -inline int String::length() const -{ - return m_string.length(); -} - -/*! - * \returns the underlying \c std::string . - */ -inline const std::string& String::stdString() const -{ - return m_string; -} - -/*! - * \brief Adds text from a char-array to the end of the string. - * \param text Text to append. - */ -inline void String::append(const char* text) -{ - m_string.append(text); -} - -/*! - * \brief Adds text to the end of the string. - * \param text Text to append. - */ -inline void String::append(char character) -{ - m_string.push_back(character); -} - -/*! - * \brief Adds text from another string to the end of this string. - * \param text Text to append. - */ -inline void String::append(const String& text) -{ - m_string.append(text.chars()); -} - -/*! - * \returns a mutable iterator to the beginning of the string. - */ -inline String::Iterator String::begin() -{ - return m_string.begin(); -} - -/*! - * \brief Clears the string. - */ -inline void String::clear() -{ - m_string.clear(); -} - -/*! - * \returns the string's mutable end-iterator. - */ -inline String::Iterator String::end() -{ - return m_string.end(); -} - -/*! - * \brief Compares two string indices, supporting negatives as offsets from the end of string. - * \param a First index to compare - * \param b Second index to compare - * \returns the difference of two indices. - */ -inline int String::indexDifference(int a, int b) -{ - modifyIndex(a); - modifyIndex(b); - return b - a; -} - -/*! - * \brief Inserts a character into the string. - * \param position Position in the string where to insert the character into. - * \param character Character to insert into the string. - */ -inline void String::insert(int position, char character) -{ - m_string.insert(m_string.begin() + position, character); -} +using String = std::string; +using StringList = std::vector; +using namespace std::string_literals; -/*! - * \brief Inserts a substring into the string. - * \param position Position in the string where to insert the substring. - * \param string Substring to insert. - */ -inline void String::insert(int position, const char* string) -{ - m_string.insert(position, string); -} - -/*! - * \brief Modifies the given index so that if it is negative, it is translated into a positive index starting from the - * end of the string. For example, an index of -1 will be modified to point to the last character in the string, - * -2 to the second last, etc. - * \param index Index to translate. - */ -inline void String::modifyIndex(int& index) const -{ - if (index < 0) - index = length() - index; -} - -/*! - * \brief Prepends the given text to the beginning of the string. - * \param text Text to prepend. - */ -inline void String::prepend(String text) -{ - m_string = (text + m_string).stdString(); -} - -/*! - * \brief Removes a range of text from the string. - * \param position Position where to start removing text. - * \param length Amount of characters to remove. - */ -inline void String::remove(int position, int length) -{ - m_string.replace(position, length, ""); -} - -/*! - * \brief Removes a single character from the string. - * \param position Position of the character to remove string from. - */ -inline void String::removeAt(int position) -{ - m_string.erase(m_string.begin() + position); -} - -/*! - * \brief Removes a number of characters from the end of the string. - * \param length Amount of characters to remove. - */ -inline void String::removeFromEnd(int length) -{ - remove(this->length() - length, length); -} - -/*! - * \brief Removes a number of characters from the beginning of the string. - * \param length Amount of characters to remove. - */ -inline void String::removeFromStart(int length) -{ - remove(0, length); -} - -/*! - * \brief Replaces a range of text in the string with another. - * \param position Position where to start replacing text. - * \param amount Amount of characters to replace. - * \param text Replacement string. - */ -inline void String::replace(int position, int amount, const String& text) -{ - m_string.replace(position, amount, text.chars()); -} - -/*! - * \brief Shrinks the string so that it does not allocate more characters than necessary. - */ -inline void String::shrinkToFit() -{ - m_string.shrink_to_fit(); -} - -/*! - * \brief Converts a number into a string, and returns a new string with the number appended to the end of the string. - * \param number Number to convert and append. - * \returns the resulting string. - */ -inline String String::operator+(int number) const -{ - return *this + String::fromNumber(number); -} - -/*! - * \brief Appends text into the string. - * \param text Text to append. - * \returns a reference to this string. - */ -inline String& String::operator+=(const String& text) -{ - append(text); - return *this; -} - -/*! - * \brief Appends text into the string. - * \param text Text to append. - * \returns a reference to this string. - */ -inline String& String::operator+=(const char* text) -{ - append(text); - return *this; -} - -/*! - * \brief Converts a number into a string, and appends it into this string. - * \param number The number to append. - * \returns a refence to this string. - */ -inline String& String::operator+=(int number) -{ - return operator+=(String::fromNumber(number)); -} - -/*! - * \brief Appends a character into this string. - * \param character The character to append. - * \return a reference to this string. - */ -inline String& String::operator+=(char character) -{ - append(character); - return *this; -} - -/*! - * \param index Index referring to a character of this string. - * \returns an editable reference to the character pointed by the given index. - */ -inline char& String::operator[](int index) -{ - return m_string[index]; -} - -/*! - * \param index Index referring to a character of this string. - * \returns an const reference to the character pointed by the given index. - */ -inline char String::operator[](int index) const -{ - return m_string[index]; -} - -/*! - * \param other String to compare with. - * \returns whether or not this string is the same as the other string. - */ -inline bool String::operator==(const String& other) const -{ - return stdString() == other.stdString(); -} - -/*! - * \param other String to compare with. - * \returns whether or not this string is the same as the other string. - */ -inline bool String::operator==(const char* other) const -{ - return m_string == other; -} - -/*! - * \param other String to compare with. - * \returns whether or not this string is different than the other string. - */ -inline bool String::operator!=(const String& other) const -{ - return stdString() != other.stdString(); -} - -/*! - * \param other String to compare with. - * \returns whether or not this string is different than the other string. - */ -inline bool String::operator!=(const char* other) const -{ - return m_string != other; -} - -/*! - * \param other String to compare with. - * \return whether or not this string is lexicographically greater than the other string. - */ -inline bool String::operator>(const String& other) const -{ - return stdString() > other.stdString(); -} - -/*! - * \param other String to compare with. - * \return whether or not this string is lexicographically lesser than the other string. - */ -inline bool String::operator<(const String& other) const -{ - return stdString() < other.stdString(); -} - -/*! - * \param other String to compare with. - * \return whether or not this string is lexicographically at least as great as the other string. - */ -inline bool String::operator>=(const String& other) const -{ - return stdString() >= other.stdString(); -} - -/*! - * \param other String to compare with. - * \return whether or not this string is lexicographically at most as great as the other string. - */ -inline bool String::operator<=(const String& other) const -{ - return stdString() <= other.stdString(); -} - -/*! - * \returns a char-array representation of this string. - */ -inline String::operator const char*() const -{ - return chars(); -} - -/*! - * \returns the underlying \c std::string of this string. - */ -inline String::operator const std::string&() const -{ - return stdString(); -} - -/*! - * \returns the underlying char-array representation of this string, casted to unsigned chars. - */ -inline const unsigned char* String::toBytes() const -{ - return reinterpret_cast(chars()); -} - -/*! - * \brief An \c operator== implementation that allows a char-array to be at the left side of a string comparison - * with a \c String. - * \param one A char-array representation of a string to compare. - * \param other A string to compare. - * \returns whether or not the two parameters are equal. - */ -inline bool operator==(const char* one, const String& other) -{ - return other == one; -} - -/*! - * \brief An \c operator+ implementation that allows a char-array to be at the left side of a string catenation - * with a \c String. - * \param one A char-array representation of a string to catenate. - * \param other A string to catenate. - * \returns the catenated string. - */ -inline String operator+(const char* one, const String& other) -{ - return String(one) + other; -} - +std::string to_lowercase(const std::string& string); +std::string join_string_list(const StringList& strings, const String& delim); +std::string mid(const std::string& str, int rangeBegin, int rangeEnd); +std::string right(const std::string& str, int length); +std::string vsprintf(const char* formatString, va_list args); +std::string __cdecl sprintf(const char* formatString, ...); +std::string remove_range(const std::string& string, int start, int end); +void replace_all(std::string& str, const char* text, const char* replacement); +bool starts_with(const std::string& str, const String& other); +StringList split(const std::string& string, const String& delimeter); +std::optional to_int(const char* str, int base = 10); +void normalize(std::string& string, int (*filter)(int) = std::isspace); END_ZFC_NAMESPACE diff -r e254398fcc7c -r 20ca0a6be175 sources/network/bytestream.cpp --- a/sources/network/bytestream.cpp Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/network/bytestream.cpp Wed Jan 27 14:04:53 2021 +0200 @@ -50,7 +50,7 @@ { int bytesPast = bytes - bytesLeft(); String message; - message.sprintf("attempted to read %d byte%s past the end of bytestream", bytesPast, plural(bytesPast)); + message = sprintf("attempted to read %d byte%s past the end of bytestream", bytesPast, plural(bytesPast)); throw IOError (message); } } diff -r e254398fcc7c -r 20ca0a6be175 sources/network/bytestream.h --- a/sources/network/bytestream.h Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/network/bytestream.h Wed Jan 27 14:04:53 2021 +0200 @@ -30,11 +30,10 @@ #pragma once #include +#include #include "../main.h" BEGIN_ZFC_NAMESPACE -class String; - enum { MAX_NETWORK_STRING = 0x800 @@ -42,15 +41,15 @@ class IOError : public std::exception { - String m_message; + std::string m_message; public: - IOError(String message) : + IOError(std::string message) : m_message(message) {} const char* what() const throw() { - return m_message; + return m_message.data(); } }; diff -r e254398fcc7c -r 20ca0a6be175 sources/network/ipaddress.cpp --- a/sources/network/ipaddress.cpp Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/network/ipaddress.cpp Wed Jan 27 14:04:53 2021 +0200 @@ -71,9 +71,9 @@ String val; if (withport == WITH_PORT) - val.sprintf ("%u.%u.%u.%u:%u", octet (0), octet (1), octet (2), octet (3), port); + val = sprintf ("%u.%u.%u.%u:%u", octet (0), octet (1), octet (2), octet (3), port); else - val.sprintf ("%u.%u.%u.%u", octet (0), octet (1), octet (2), octet (3)); + val = sprintf ("%u.%u.%u.%u", octet (0), octet (1), octet (2), octet (3)); return val; } @@ -145,11 +145,11 @@ { unsigned int parts[4]; int colonpos = input.find (":"); - String addressString = colonpos == -1 ? input : input.mid (0, colonpos); + String addressString = colonpos == -1 ? input : mid(input, 0, colonpos); IPAddress value; // Try scanf the IPv4 host first - if (sscanf (addressString, "%u.%u.%u.%u", &parts[0], &parts[1], &parts[2], &parts[3])) + if (sscanf(addressString.data(), "%u.%u.%u.%u", &parts[0], &parts[1], &parts[2], &parts[3])) { for (int i : range(4)) value.set_octet (i, parts[i]); @@ -161,7 +161,13 @@ } if (colonpos != -1) - value.port = (unsigned short) input.mid (colonpos + 1, -1).toInt(); + { + std::optional opt = to_int(mid(input, colonpos + 1, -1).data()); + if (opt.has_value()) + { + value.port = opt.value(); + } + } return value; } @@ -175,7 +181,7 @@ memset (&hints, 0, sizeof hints); hints.ai_family = AF_INET; - if (getaddrinfo (node, nullptr, &hints, &lookup) != 0) + if (getaddrinfo(node.data(), nullptr, &hints, &lookup) != 0) throw StringParseError ("unknown host " + node); IPAddress result; diff -r e254398fcc7c -r 20ca0a6be175 sources/network/ipaddress.h --- a/sources/network/ipaddress.h Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/network/ipaddress.h Wed Jan 27 14:04:53 2021 +0200 @@ -59,7 +59,7 @@ const char* what() const throw() { - return m_message.chars(); + return m_message.data(); } }; diff -r e254398fcc7c -r 20ca0a6be175 sources/network/rconsession.cpp --- a/sources/network/rconsession.cpp Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/network/rconsession.cpp Wed Jan 27 14:04:53 2021 +0200 @@ -31,6 +31,7 @@ #include #include "rconsession.h" #include "../interface.h" +#include "../md5.h" BEGIN_ZFC_NAMESPACE // ------------------------------------------------------------------------------------------------- @@ -44,7 +45,7 @@ if (not m_socket.set_blocking(false)) { fprintf(stderr, "unable to set socket as non-blocking: %s\n", - m_socket.error_string().chars()); + m_socket.error_string().data()); exit(EXIT_FAILURE); } } @@ -157,8 +158,8 @@ case SVRC_MESSAGE: { String message = stream.readString(); - message.normalize(); - m_interface->printText("%s\n", message.chars()); + normalize(message); + m_interface->printText("%s\n", message.data()); } break; @@ -177,8 +178,8 @@ for (int i = stream.readByte(); i > 0; --i) { String message = stream.readString(); - message.normalize(); - m_interface->printText("--- %s\n", message.chars()); + normalize(message); + m_interface->printText("--- %s\n", message.data()); } m_interface->print("End of previous messages.\n"); @@ -192,7 +193,7 @@ { unsigned int numCompletions = stream.readShort(); m_interface->print("%d completions for '%s'.\n", - int(numCompletions), m_lastTabComplete.chars()); + int(numCompletions), m_lastTabComplete.data()); } break; @@ -210,13 +211,13 @@ } else if (completes.size() > 0) { - m_interface->print("Completions for '%s':\n", m_lastTabComplete.chars()); + m_interface->print("Completions for '%s':\n", m_lastTabComplete.data()); for (int i : range(0, static_cast(completes.size()), 8)) { const int end = min(i + 8, static_cast(completes.size())); StringList splices = splice(completes, i, end); - m_interface->print("- %s\n", join_string_list(splices, ", ").chars()); + m_interface->print("- %s\n", join_string_list(splices, ", ").data()); } } } @@ -227,7 +228,7 @@ catch (std::exception& e) { m_interface->printWarning("Couldn't process packet: %s\n", e.what()); - m_interface->printWarning("Packet contents was: %s\n", quote(message).chars()); + m_interface->printWarning("Packet contents was: %s\n", quote(message).data()); m_interface->printWarning("Stream position in payload was: %d\n", stream.position()); } } @@ -276,7 +277,7 @@ // void RCONSession::sendHello() { - m_interface->print("Connecting to %s...\n", m_address.to_string(IPAddress::WITH_PORT).chars()); + m_interface->print("Connecting to %s...\n", m_address.to_string(IPAddress::WITH_PORT).data()); send({CLRC_BEGINCONNECTION, RCON_PROTOCOL_VERSION}); bumpLastPing(); } @@ -289,7 +290,7 @@ ByteArray message; Bytestream stream(message); stream.writeByte(CLRC_PASSWORD); - stream.writeString((m_salt + m_password).md5()); + stream.writeString(md5((m_salt + m_password).data())); send(message); bumpLastPing(); } @@ -322,7 +323,7 @@ // bool RCONSession::sendCommand(const String& commandString) { - if (m_state != RCON_CONNECTED or commandString.isEmpty()) + if (m_state != RCON_CONNECTED or commandString.empty()) return false; ByteArray message; diff -r e254398fcc7c -r 20ca0a6be175 sources/network/udpsocket.cpp --- a/sources/network/udpsocket.cpp Wed Jan 27 13:17:11 2021 +0200 +++ b/sources/network/udpsocket.cpp Wed Jan 27 14:04:53 2021 +0200 @@ -105,7 +105,7 @@ if (::bind (m_socket, reinterpret_cast (&svaddr), sizeof svaddr) == -1) { - m_error = String ("Couldn't bind to port ") + String::fromNumber (port); + m_error = "Couldn't bind to port "s + std::to_string(port); return false; }