aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/base/String.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/base/String.cpp')
-rw-r--r--src/lib/base/String.cpp295
1 files changed, 295 insertions, 0 deletions
diff --git a/src/lib/base/String.cpp b/src/lib/base/String.cpp
new file mode 100644
index 0000000..97b8997
--- /dev/null
+++ b/src/lib/base/String.cpp
@@ -0,0 +1,295 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2014-2016 Symless Ltd.
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "arch/Arch.h"
+#include "base/String.h"
+#include "common/common.h"
+#include "common/stdvector.h"
+
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+#include <stdio.h>
+#include <cstdarg>
+#include <sstream>
+#include <iomanip>
+#include <algorithm>
+#include <cerrno>
+
+namespace barrier {
+namespace string {
+
+String
+format(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ String result = vformat(fmt, args);
+ va_end(args);
+ return result;
+}
+
+String
+vformat(const char* fmt, va_list args)
+{
+ // find highest indexed substitution and the locations of substitutions
+ std::vector<size_t> pos;
+ std::vector<size_t> width;
+ std::vector<size_t> index;
+ size_t maxIndex = 0;
+ for (const char* scan = fmt; *scan != '\0'; ++scan) {
+ if (*scan == '%') {
+ ++scan;
+ if (*scan == '\0') {
+ break;
+ }
+ else if (*scan == '%') {
+ // literal
+ index.push_back(0);
+ pos.push_back(static_cast<size_t>((scan - 1) - fmt));
+ width.push_back(2);
+ }
+ else if (*scan == '{') {
+ // get argument index
+ char* end;
+ errno = 0;
+ long i = strtol(scan + 1, &end, 10);
+ if (errno || (i < 0) || (*end != '}')) {
+ // invalid index -- ignore
+ scan = end - 1; // BUG if there are digits?
+ }
+ else {
+ index.push_back(i);
+ pos.push_back(static_cast<size_t>((scan - 1) - fmt));
+ width.push_back(static_cast<size_t>((end - scan) + 2));
+ if (i > maxIndex) {
+ maxIndex = i;
+ }
+ scan = end;
+ }
+ }
+ else {
+ // improper escape -- ignore
+ }
+ }
+ }
+
+ // get args
+ std::vector<const char*> value;
+ std::vector<size_t> length;
+ value.push_back("%");
+ length.push_back(1);
+ for (int i = 0; i < maxIndex; ++i) {
+ const char* arg = va_arg(args, const char*);
+ size_t len = strlen(arg);
+ value.push_back(arg);
+ length.push_back(len);
+ }
+
+ // compute final length
+ size_t resultLength = strlen(fmt);
+ const int n = static_cast<int>(pos.size());
+ for (int i = 0; i < n; ++i) {
+ resultLength -= width[i];
+ resultLength += length[index[i]];
+ }
+
+ // substitute
+ String result;
+ result.reserve(resultLength);
+ size_t src = 0;
+ for (int i = 0; i < n; ++i) {
+ result.append(fmt + src, pos[i] - src);
+ result.append(value[index[i]]);
+ src = pos[i] + width[i];
+ }
+ result.append(fmt + src);
+
+ return result;
+}
+
+String
+sprintf(const char* fmt, ...)
+{
+ char tmp[1024];
+ char* buffer = tmp;
+ int len = (int)(sizeof(tmp) / sizeof(tmp[0]));
+ String result;
+ while (buffer != NULL) {
+ // try printing into the buffer
+ va_list args;
+ va_start(args, fmt);
+ int n = ARCH->vsnprintf(buffer, len, fmt, args);
+ va_end(args);
+
+ // if the buffer wasn't big enough then make it bigger and try again
+ if (n < 0 || n > len) {
+ if (buffer != tmp) {
+ delete[] buffer;
+ }
+ len *= 2;
+ buffer = new char[len];
+ }
+
+ // if it was big enough then save the string and don't try again
+ else {
+ result = buffer;
+ if (buffer != tmp) {
+ delete[] buffer;
+ }
+ buffer = NULL;
+ }
+ }
+
+ return result;
+}
+
+void
+findReplaceAll(
+ String& subject,
+ const String& find,
+ const String& replace)
+{
+ size_t pos = 0;
+ while ((pos = subject.find(find, pos)) != String::npos) {
+ subject.replace(pos, find.length(), replace);
+ pos += replace.length();
+ }
+}
+
+String
+removeFileExt(String filename)
+{
+ size_t dot = filename.find_last_of('.');
+
+ if (dot == String::npos) {
+ return filename;
+ }
+
+ return filename.substr(0, dot);
+}
+
+void
+toHex(String& subject, int width, const char fill)
+{
+ std::stringstream ss;
+ ss << std::hex;
+ for (unsigned int i = 0; i < subject.length(); i++) {
+ ss << std::setw(width) << std::setfill(fill) << (int)(unsigned char)subject[i];
+ }
+
+ subject = ss.str();
+}
+
+void
+uppercase(String& subject)
+{
+ std::transform(subject.begin(), subject.end(), subject.begin(), ::toupper);
+}
+
+void
+removeChar(String& subject, const char c)
+{
+ subject.erase(std::remove(subject.begin(), subject.end(), c), subject.end());
+}
+
+String
+sizeTypeToString(size_t n)
+{
+ std::stringstream ss;
+ ss << n;
+ return ss.str();
+}
+
+size_t
+stringToSizeType(String string)
+{
+ std::istringstream iss(string);
+ size_t value;
+ iss >> value;
+ return value;
+}
+
+std::vector<String>
+splitString(String string, const char c)
+{
+ std::vector<String> results;
+
+ size_t head = 0;
+ size_t separator = string.find(c);
+ while (separator != String::npos) {
+ if (head!=separator) {
+ results.push_back(string.substr(head, separator - head));
+ }
+ head = separator + 1;
+ separator = string.find(c, head);
+ }
+
+ if (head < string.size()) {
+ results.push_back(string.substr(head, string.size() - head));
+ }
+
+ return results;
+}
+
+//
+// CaselessCmp
+//
+
+bool
+CaselessCmp::cmpEqual(
+ const String::value_type& a,
+ const String::value_type& b)
+{
+ // should use std::tolower but not in all versions of libstdc++ have it
+ return tolower(a) == tolower(b);
+}
+
+bool
+CaselessCmp::cmpLess(
+ const String::value_type& a,
+ const String::value_type& b)
+{
+ // should use std::tolower but not in all versions of libstdc++ have it
+ return tolower(a) < tolower(b);
+}
+
+bool
+CaselessCmp::less(const String& a, const String& b)
+{
+ return std::lexicographical_compare(
+ a.begin(), a.end(),
+ b.begin(), b.end(),
+ &barrier::string::CaselessCmp::cmpLess);
+}
+
+bool
+CaselessCmp::equal(const String& a, const String& b)
+{
+ return !(less(a, b) || less(b, a));
+}
+
+bool
+CaselessCmp::operator()(const String& a, const String& b) const
+{
+ return less(a, b);
+}
+
+}
+}