removed the String class in favor of std::string

Wed, 27 Jan 2021 14:04:53 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 27 Jan 2021 14:04:53 +0200
changeset 182
20ca0a6be175
parent 181
e254398fcc7c
child 183
9b6a0daedfc0

removed the String class in favor of std::string

sources/coloredline.cpp file | annotate | diff | comparison | revisions
sources/interface.cpp file | annotate | diff | comparison | revisions
sources/list.cpp file | annotate | diff | comparison | revisions
sources/list.h file | annotate | diff | comparison | revisions
sources/md5.cpp file | annotate | diff | comparison | revisions
sources/md5.h file | annotate | diff | comparison | revisions
sources/mystring.cpp file | annotate | diff | comparison | revisions
sources/mystring.h file | annotate | diff | comparison | revisions
sources/network/bytestream.cpp file | annotate | diff | comparison | revisions
sources/network/bytestream.h file | annotate | diff | comparison | revisions
sources/network/ipaddress.cpp file | annotate | diff | comparison | revisions
sources/network/ipaddress.h file | annotate | diff | comparison | revisions
sources/network/rconsession.cpp file | annotate | diff | comparison | revisions
sources/network/udpsocket.cpp file | annotate | diff | comparison | revisions
--- 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;
--- 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<signed>(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<signed>(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<signed>(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<int>(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<signed>(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<signed>(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());
 }
 
 // -------------------------------------------------------------------------------------------------
--- 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);
--- 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 <vector>
+#include <string>
 #include "basics.h"
 #include "range.h"
 BEGIN_ZFC_NAMESPACE
@@ -44,7 +45,7 @@
 }
 
 using ByteArray = std::vector<unsigned char>;
-class String quote(const ByteArray& bytes);
+std::string quote(const ByteArray& bytes);
 
 template<typename T>
 T splice(const T& container, int start, int end, int step = 1)
--- 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<const unsigned char*>(buffer), strlen(buffer), checksum);
+	checksum[sizeof checksum - 1] = '\0';
+	return {checksum};
+}
+
 END_ZFC_NAMESPACE
\ No newline at end of file
--- 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 <string>
 #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
--- 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 <cstring>
 #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<signed>(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<float>(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<signed>(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<char> 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<int>(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<long> 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<const Vector<char>&>(bytes));
-}
-
-/*!
- * \returns the MD5-checksum of this string.
- */
-String String::md5() const
-{
-	char checksum[33];
-	CalculateMD5 (reinterpret_cast<const unsigned char*> (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<signed>(string.length() - 1))
+	{
+		string = string.substr (a, b - a + 1);
+	}
 }
 
 END_ZFC_NAMESPACE
--- 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>;
-
-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<char>& 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<char>& 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<std::string>;
+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<const unsigned char*>(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<long> to_int(const char* str, int base = 10);
+void normalize(std::string& string, int (*filter)(int) = std::isspace);
 
 END_ZFC_NAMESPACE
--- 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);
 	}
 }
--- 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 <stdexcept>
+#include <string>
 #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();
 	}
 };
 
--- 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<long> 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;
--- 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();
 		}
 	};
 
--- 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 <time.h>
 #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<int>(completes.size()), 8))
 						{
 							const int end = min(i + 8, static_cast<int>(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;
--- 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<sockaddr*> (&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;
 	}
 

mercurial