summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/MTS_Buffer.cpp159
-rw-r--r--src/MTS_Condition.cpp115
-rw-r--r--src/MTS_Lock.cpp114
-rw-r--r--src/MTS_Logger.cpp312
-rw-r--r--src/MTS_Object.cpp41
-rw-r--r--src/MTS_SignalThread.cpp103
-rw-r--r--src/MTS_System.cpp156
-rw-r--r--src/MTS_Text.cpp701
-rw-r--r--src/MTS_Thread.cpp227
-rw-r--r--src/MTS_Timer.cpp103
-rw-r--r--src/MTS_TimerThread.cpp116
11 files changed, 2147 insertions, 0 deletions
diff --git a/src/MTS_Buffer.cpp b/src/MTS_Buffer.cpp
new file mode 100644
index 0000000..91ece42
--- /dev/null
+++ b/src/MTS_Buffer.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_Buffer.h>
+#include <stdexcept>
+#include <string>
+
+using namespace MTS;
+
+const uint32_t Buffer::DEFAULT_CAPACITY = 80;
+
+Buffer::Buffer(uint32_t capacity) {
+ setCapacity(capacity);
+}
+
+Buffer::Buffer(const uint8_t* bytes, uint32_t count)
+: m_vBuffer(bytes, bytes + count) {
+
+}
+
+Buffer::Buffer(const Buffer& other)
+: m_vBuffer(other.m_vBuffer.begin(), other.m_vBuffer.end()) {
+
+}
+
+Buffer::~Buffer() {
+
+}
+
+Buffer&
+Buffer::operator=(const Buffer& other) {
+ if (&other == this) {
+ return *this;
+ }
+ m_vBuffer = other.m_vBuffer;
+ return *this;
+}
+
+const uint8_t*
+Buffer::getBuffer() const {
+ return &m_vBuffer.at(0);
+}
+
+std::string Buffer::str() const {
+ return std::string(reinterpret_cast<const char*>(&m_vBuffer.at(0)), m_vBuffer.size());
+}
+
+uint32_t Buffer::getSize() const {
+ return m_vBuffer.size();
+}
+
+void Buffer::setSize(uint32_t newSize) {
+ m_vBuffer.resize(newSize);
+}
+
+uint32_t Buffer::getCapacity() const {
+ return m_vBuffer.capacity();
+}
+
+void Buffer::setCapacity(uint32_t newCapacity) {
+ m_vBuffer.reserve(newCapacity);
+}
+
+void Buffer::clear() {
+ m_vBuffer.clear();
+}
+
+void Buffer::compact() {
+ m_vBuffer.resize(m_vBuffer.size());
+}
+
+uint8_t Buffer::operator[](uint32_t index) const {
+ return m_vBuffer[index];
+}
+
+uint8_t Buffer::operator[](uint32_t index) {
+ return m_vBuffer[index];
+}
+
+const uint8_t&
+Buffer::at(uint32_t index) const {
+ return m_vBuffer.at(index);
+}
+
+uint8_t&
+Buffer::at(uint32_t index) {
+ return m_vBuffer.at(index);
+}
+
+Buffer&
+Buffer::append(uint8_t byte) {
+ m_vBuffer.push_back(byte);
+ return *this;
+}
+
+Buffer& Buffer::append(const uint8_t* bytes, uint32_t count) {
+ m_vBuffer.resize(m_vBuffer.size() + count);
+ std::copy(bytes, bytes + count, std::back_inserter(m_vBuffer));
+ return *this;
+}
+
+Buffer&
+Buffer::insert(uint32_t index, uint8_t byte) {
+ m_vBuffer.insert(m_vBuffer.begin() + index, byte);
+ return *this;
+}
+
+Buffer&
+Buffer::insert(uint32_t index, const uint8_t* bytes, uint32_t count) {
+ m_vBuffer.insert(m_vBuffer.begin() + index, bytes, bytes + count);
+ return *this;
+}
+
+Buffer&
+Buffer::remove(uint32_t index) {
+ m_vBuffer.erase(m_vBuffer.begin() + index);
+ return *this;
+}
+
+Buffer&
+Buffer::remove(uint32_t start, uint32_t end) {
+ m_vBuffer.erase(m_vBuffer.begin() + start, m_vBuffer.begin() + end);
+ return *this;
+}
+
+Buffer&
+Buffer::replace(uint32_t start, uint32_t end, const uint8_t* bytes,
+uint32_t count) {
+ if (end - start == count) {
+ if (start > end || end > m_vBuffer.size()) {
+ throw std::out_of_range("Buffer| index out of bounds");
+ }
+ std::copy(bytes, bytes + count, m_vBuffer.begin());
+ return *this;
+ }
+ return remove(start, end).insert(start, bytes, count);
+}
+
+Buffer* Buffer::clone() const {
+ return new Buffer(*this);
+}
+
diff --git a/src/MTS_Condition.cpp b/src/MTS_Condition.cpp
new file mode 100644
index 0000000..d238d50
--- /dev/null
+++ b/src/MTS_Condition.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_Condition.h>
+#include <mts/MTS_Lock.h>
+#include <mts/MTS_System.h>
+#include <mts/MTS_Logger.h>
+#include <cassert>
+#include <cerrno>
+#include <stdexcept>
+
+using namespace MTS;
+
+Condition::Condition(Lock* pLock)
+: m_pLock(pLock) {
+ if (pLock == 0) {
+ throw std::invalid_argument("Condition| constructing lock is null");
+ }
+#ifdef WIN32
+ m_apCondition.reset(CreateEvent(NULL, FALSE, FALSE, NULL));
+ if (m_pCondition.get() == NULL) {
+ throw std::bad_alloc();
+ }
+#else
+ m_apCondition.reset(new pthread_cond_t());
+ const uint32_t result = pthread_cond_init(m_apCondition.get(), NULL);
+ if (result != 0) {
+ throw std::runtime_error("Condition| failed to initialize condition");
+ }
+#endif
+}
+
+Condition::~Condition() {
+ if (!m_apCondition.isNull()) {
+#ifdef WIN32
+ const BOOL ok = CloseHandle(m_apCondition.get());
+ assert(ok);
+#else
+ const uint32_t result = pthread_cond_destroy(m_apCondition.get());
+ if (result != 0) {
+ printWarning("Condition| failed to destroy condition");
+ }
+ assert(result == 0);
+#endif
+ }
+}
+
+void Condition::wait() {
+#ifdef WIN32
+ wait(INFINITE);
+#else
+ const uint32_t result = pthread_cond_wait(m_apCondition.get(),
+ m_pLock->m_apMutex.get());
+ if (result != 0) {
+ printWarning("Condition| failed to wait on condition");
+ }
+ assert(result == 0);
+#endif
+}
+
+void Condition::wait(uint32_t millis) {
+ assert(m_pLock->isLocked());
+ if(!m_pLock->isLocked()) {
+ printWarning("Condition| lock was not locked. not waiting on signal.");
+ return;
+ }
+#ifdef WIN32
+ ResetEvent(m_apCondition.get());
+ m_pLock->unlock();
+ const DWORD waitResult = WaitForSingleObject(m_apCondition.get(), millis);
+ assert(waitResult == WAIT_OBJECT_0 || waitResult == WAIT_TIMEOUT);
+ m_pLock->lock();
+#else
+ timespec abstime;
+ int64_t micros = System::timeMicros() + (millis * 1000);
+ abstime.tv_sec = static_cast<long>(micros / 1000000);
+ abstime.tv_nsec = static_cast<long>((micros % 1000000) * 1000);
+ const uint32_t result = pthread_cond_timedwait(m_apCondition.get(),
+ m_pLock->m_apMutex.get(), &abstime);
+ if (result != 0 && result != ETIMEDOUT) {
+ printWarning("Condition| failed to time wait on condition");
+ }
+ assert(result == 0 || result == ETIMEDOUT);
+#endif
+}
+
+void Condition::signal() {
+#ifdef WIN32
+ const BOOL ok = SetEvent(m_apCondition.get());
+ assert(ok);
+#else
+ const uint32_t result = pthread_cond_broadcast(m_apCondition.get());
+ if (result != 0) {
+ printWarning("Condition| failed to signal condition");
+ }
+ assert(result == 0);
+#endif
+}
diff --git a/src/MTS_Lock.cpp b/src/MTS_Lock.cpp
new file mode 100644
index 0000000..dc2e7c0
--- /dev/null
+++ b/src/MTS_Lock.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_Lock.h>
+#include <mts/MTS_Logger.h>
+#include <cassert>
+#include <stdexcept>
+
+using namespace MTS;
+
+Lock::Lock()
+: m_bLocked(false) {
+#ifdef WIN32
+ m_apMutex.reset(CreateMutex(NULL, FALSE, NULL));
+ if (m_apMutex.get() == NULL) {
+ throw std::bad_alloc();
+ }
+#else
+ m_apMutexAttr.reset(new pthread_mutexattr_t());
+ int result = pthread_mutexattr_init(m_apMutexAttr.get());
+ if (result != 0) {
+ throw std::runtime_error("failed to initialize mutex attributes");
+ }
+ result = pthread_mutexattr_settype(m_apMutexAttr.get(),
+ PTHREAD_MUTEX_RECURSIVE);
+ if (result != 0) {
+ throw std::runtime_error("failed to set mutex recursive");
+ }
+ m_apMutex.reset(new pthread_mutex_t());
+ result = pthread_mutex_init(m_apMutex.get(), m_apMutexAttr.get());
+ if (result != 0) {
+ throw std::runtime_error("failed to initialize mutex");
+ }
+#endif
+
+}
+
+Lock::~Lock() {
+ if (isLocked()) {
+ unlock();
+ }
+#ifdef WIN32
+ const BOOL ok = CloseHandle(m_apMutex.release());
+ assert(ok);
+#else
+ if (!m_apMutex.isNull()) {
+ const int result = pthread_mutex_destroy(m_apMutex.get());
+ if (result != 0) {
+ printWarning("Lock| Failed to destroy mutex");
+ }
+ assert(result == 0);
+ }
+ if (!m_apMutexAttr.isNull()) {
+ const int result = pthread_mutexattr_destroy(m_apMutexAttr.get());
+ if (result != 0) {
+ printWarning("Lock| Failed to destroy mutex attributes");
+ }
+ assert(result == 0);
+ }
+#endif
+}
+
+void Lock::lock() {
+#ifdef WIN32
+ const DWORD waitResult = WaitForSingleObject(m_apMutex.get(), INFINITE);
+ assert(waitResult == WAIT_OBJECT_0);
+#else
+ const int result = pthread_mutex_lock(m_apMutex.get());
+ if (result != 0) {
+ printWarning("Lock| Failed to lock mutex");
+ }
+ assert(result == 0);
+#endif
+ m_bLocked = true;
+}
+
+void Lock::unlock() {
+ m_bLocked = false;
+#ifdef WIN32
+ const BOOL ok = ReleaseMutex(m_apMutex.get());
+ assert(ok);
+#else
+ const int result = pthread_mutex_unlock(m_apMutex.get());
+ if (result != 0) {
+ printWarning("Lock| Failed to unlock mutex");
+ }
+ assert(result == 0);
+#endif
+}
+
+bool Lock::isLocked() const {
+ return m_bLocked;
+}
+
+Condition* Lock::createCondition() {
+ return new Condition(this);
+}
diff --git a/src/MTS_Logger.cpp b/src/MTS_Logger.cpp
new file mode 100644
index 0000000..93775fe
--- /dev/null
+++ b/src/MTS_Logger.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_Logger.h>
+#include <mts/MTS_Lock.h>
+#include <mts/MTS_Text.h>
+#include <mts/MTS_System.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include <iostream>
+
+using namespace MTS;
+
+const char* Logger::PrintLevel::OFF_LABEL = "OFF";
+const char* Logger::PrintLevel::FATAL_LABEL = "FATAL";
+const char* Logger::PrintLevel::ERROR_LABEL = "ERROR";
+const char* Logger::PrintLevel::WARNING_LABEL = "WARNING";
+const char* Logger::PrintLevel::INFO_LABEL = "INFO";
+const char* Logger::PrintLevel::CONFIG_LABEL = "CONFIG";
+const char* Logger::PrintLevel::DEBUG_LABEL = "DEBUG";
+const char* Logger::PrintLevel::TRACE_LABEL = "TRACE";
+const char* Logger::PrintLevel::MAXIMUM_LABEL = "MAXIMUM";
+
+const int Logger::PrintLevel::OFF_LEVEL = 0;
+const int Logger::PrintLevel::MINIMUM_LEVEL = 1;
+const int Logger::PrintLevel::FATAL_LEVEL = 1;
+const int Logger::PrintLevel::ERROR_LEVEL = 10;
+const int Logger::PrintLevel::WARNING_LEVEL = 20;
+const int Logger::PrintLevel::INFO_LEVEL = 30;
+const int Logger::PrintLevel::CONFIG_LEVEL = 40;
+const int Logger::PrintLevel::DEBUG_LEVEL = 50;
+const int Logger::PrintLevel::TRACE_LEVEL = 60;
+const int Logger::PrintLevel::MAXIMUM_LEVEL = 100;
+
+volatile int Logger::m_iPrintLevel = Logger::PrintLevel::MAXIMUM_LEVEL;
+std::string Logger::m_sPrintLevel = Logger::PrintLevel::MAXIMUM_LABEL;
+Logger::PrintMode Logger::m_eMode = Logger::PrintMode::STDOUT_ONLY;
+FILE* Logger::m_pFile = NULL;
+int Logger::m_iLogFacility = -1;
+Lock Logger::m_oPrintLock;
+std::string Logger::m_sIdent;
+std::string Logger::m_sFileName;
+
+int Logger::getPrintLevel() {
+ return m_iPrintLevel;
+}
+
+const std::string& Logger::getPrintLevelString() {
+ if (m_iPrintLevel == PrintLevel::OFF_LEVEL)
+ m_sPrintLevel = std::string(PrintLevel::OFF_LABEL);
+ else if (m_iPrintLevel == PrintLevel::FATAL_LEVEL)
+ m_sPrintLevel = std::string(PrintLevel::FATAL_LABEL);
+ else if (m_iPrintLevel > PrintLevel::FATAL_LEVEL && m_iPrintLevel <= PrintLevel::ERROR_LEVEL)
+ m_sPrintLevel = std::string(PrintLevel::ERROR_LABEL);
+ else if (m_iPrintLevel > PrintLevel::ERROR_LEVEL && m_iPrintLevel <= PrintLevel::WARNING_LEVEL)
+ m_sPrintLevel = std::string(PrintLevel::WARNING_LABEL);
+ else if (m_iPrintLevel > PrintLevel::WARNING_LEVEL && m_iPrintLevel <= PrintLevel::INFO_LEVEL)
+ m_sPrintLevel = std::string(PrintLevel::INFO_LABEL);
+ else if (m_iPrintLevel > PrintLevel::INFO_LEVEL && m_iPrintLevel <= PrintLevel::CONFIG_LEVEL)
+ m_sPrintLevel = std::string(PrintLevel::CONFIG_LABEL);
+ else if (m_iPrintLevel > PrintLevel::CONFIG_LEVEL && m_iPrintLevel <= PrintLevel::DEBUG_LEVEL)
+ m_sPrintLevel = std::string(PrintLevel::DEBUG_LABEL);
+ else if (m_iPrintLevel > PrintLevel::DEBUG_LEVEL && m_iPrintLevel <= PrintLevel::TRACE_LEVEL)
+ m_sPrintLevel = std::string(PrintLevel::TRACE_LABEL);
+ else
+ m_sPrintLevel = std::string(PrintLevel::MAXIMUM_LABEL);
+
+ return m_sPrintLevel;
+}
+
+void Logger::setPrintLevel(int32_t level, bool silent) {
+ m_iPrintLevel = level;
+ if (!silent) {
+ printf(level, "Logger Level Changed to %d\n", level);
+ }
+}
+
+bool Logger::isPrintable(int32_t level) {
+ int32_t currentLevel = getPrintLevel();
+ return (level <= currentLevel) && (currentLevel > PrintLevel::OFF_LEVEL);
+}
+
+int32_t Logger::syslogPrintLevelConversion(const int32_t& level) {
+ if (level < 10) {
+ return LOG_EMERG;
+ } else if (level < 20) {
+ return LOG_ERR;
+ } else if (level < 30) {
+ return LOG_WARNING;
+ } else if (level < 50) {
+ return LOG_INFO;
+ } else {
+ return LOG_DEBUG;
+ }
+}
+
+void Logger::printMessage(const int32_t& level, const char* label, const char* format, va_list argptr) {
+
+ m_oPrintLock.lock();
+ switch (m_eMode) {
+ case Logger::PrintMode::STDOUT_ONLY:
+ ::printf("%s|%s|", MTS::Text::time(MTS::System::timeMicros()).c_str(), label);
+ vprintf(format, argptr);
+ ::printf("\n");
+ break;
+
+ case Logger::PrintMode::FILE_ONLY:
+ fprintf(m_pFile, "%s|%s| ", MTS::Text::time(MTS::System::timeMicros()).c_str(), label);
+ vfprintf(m_pFile, format, argptr);
+ fprintf(m_pFile, "\n");
+ fflush(m_pFile);
+ break;
+
+ case Logger::PrintMode::SYSLOG_ONLY:
+ if (level <= Logger::PrintLevel::TRACE_LEVEL) {
+ vsyslog(syslogPrintLevelConversion(level), format, argptr);
+ }
+ break;
+
+ case Logger::PrintMode::STDOUT_AND_FILE: {
+ const std::string timestr(MTS::Text::time(MTS::System::timeMicros()));
+ va_list argptr2;
+ va_copy(argptr2, argptr);
+ ::printf("%s|%s|", timestr.c_str(), label);
+ vprintf(format, argptr);
+ ::printf("\n");
+ fprintf(m_pFile, "%s|%s| ", timestr.c_str(), label);
+ vfprintf(m_pFile, format, argptr2);
+ fprintf(m_pFile, "\n");
+ fflush(m_pFile);
+ va_end(argptr2);
+ }
+ break;
+
+ case Logger::PrintMode::STDOUT_AND_SYSLOG: {
+ if (level <= Logger::PrintLevel::TRACE_LEVEL) {
+ va_list argptr2;
+ va_copy(argptr2, argptr);
+ vsyslog(syslogPrintLevelConversion(level), format, argptr2);
+ va_end(argptr2);
+ }
+ ::printf("%s|", MTS::Text::time(MTS::System::timeMicros()).c_str());
+ ::printf("%s|", label);
+ vprintf(format, argptr);
+ ::printf("\n");
+ }
+ break;
+
+ case Logger::PrintMode::NO_PRINTING:
+ default:
+ break;
+
+ }
+ m_oPrintLock.unlock();
+}
+
+void Logger::printfFatal(const char* format, ...) {
+ if (isPrintable(PrintLevel::FATAL_LEVEL)) {
+ va_list argptr;
+ va_start(argptr, format);
+ printMessage(PrintLevel::FATAL_LEVEL, PrintLevel::FATAL_LABEL, format, argptr);
+ va_end(argptr);
+ }
+}
+
+void Logger::printfError(const char* format, ...) {
+ if (isPrintable(PrintLevel::ERROR_LEVEL)) {
+ va_list argptr;
+ va_start(argptr, format);
+ printMessage(PrintLevel::ERROR_LEVEL, PrintLevel::ERROR_LABEL, format, argptr);
+ va_end(argptr);
+ }
+}
+
+void Logger::printfWarning(const char* format, ...) {
+ if (isPrintable(PrintLevel::WARNING_LEVEL)) {
+ va_list argptr;
+ va_start(argptr, format);
+ printMessage(PrintLevel::WARNING_LEVEL, PrintLevel::WARNING_LABEL, format, argptr);
+ va_end(argptr);
+ }
+}
+
+void Logger::printfInfo(const char* format, ...) {
+ if (isPrintable(PrintLevel::INFO_LEVEL)) {
+ va_list argptr;
+ va_start(argptr, format);
+ printMessage(PrintLevel::INFO_LEVEL, PrintLevel::INFO_LABEL, format, argptr);
+ va_end(argptr);
+ }
+}
+
+void Logger::printfConfig(const char* format, ...) {
+ if (isPrintable(PrintLevel::CONFIG_LEVEL)) {
+ va_list argptr;
+ va_start(argptr, format);
+ printMessage(PrintLevel::CONFIG_LEVEL, PrintLevel::CONFIG_LABEL, format, argptr);
+ va_end(argptr);
+ }
+}
+
+void Logger::printfDebug(const char* format, ...) {
+ if (isPrintable(PrintLevel::DEBUG_LEVEL)) {
+ va_list argptr;
+ va_start(argptr, format);
+ printMessage(PrintLevel::DEBUG_LEVEL, PrintLevel::DEBUG_LABEL, format, argptr);
+ va_end(argptr);
+ }
+}
+
+void Logger::printfTrace(const char* format, ...) {
+ if (isPrintable(PrintLevel::TRACE_LEVEL)) {
+ va_list argptr;
+ va_start(argptr, format);
+ printMessage(PrintLevel::TRACE_LEVEL, PrintLevel::TRACE_LABEL, format, argptr);
+ va_end(argptr);
+ }
+}
+
+void Logger::printfGeneric(int level, const char* label, const char* format, ...) {
+ va_list argptr;
+ va_start(argptr, format);
+ printMessage(level, label, format, argptr);
+ va_end(argptr);
+}
+
+void Logger::printf(int level, const char* format, ...) {
+ if (isPrintable(level)) {
+ va_list argptr;
+ va_start(argptr, format);
+ m_oPrintLock.lock();
+ vprintf(format, argptr);
+ m_oPrintLock.unlock();
+ va_end(argptr);
+ }
+}
+
+void Logger::printf(const char* format, ...) {
+ if (isPrintable(PrintLevel::MAXIMUM_LEVEL)) {
+ va_list argptr;
+ va_start(argptr, format);
+ m_oPrintLock.lock();
+ vprintf(format, argptr);
+ m_oPrintLock.unlock();
+ va_end(argptr);
+ }
+}
+
+bool Logger::setup(const PrintMode& mode) {
+ m_oPrintLock.lock();
+ m_eMode = mode;
+ m_oPrintLock.unlock();
+ return true;
+}
+
+bool Logger::setup(const PrintMode& mode, const std::string& filename) {
+ /* close the handle and reopen it each time setup() is called in case
+ * we are being used with programs like logrotate, etc
+ *
+ * if the file is different, switch to the new file */
+
+ m_oPrintLock.lock();
+ if (m_pFile) {
+ fclose(m_pFile);
+ }
+ if (m_sFileName != filename) {
+ m_sFileName = filename;
+ }
+ m_pFile = fopen(m_sFileName.c_str(), "a");
+ m_iLogFacility = -1;
+ m_oPrintLock.unlock();
+
+ if (!m_pFile) {
+ fprintf(stderr, "Error opening logfile %s\n", m_sFileName.c_str());
+ return false;
+ }
+ m_eMode = mode;
+ return true;
+}
+
+bool Logger::setup(const PrintMode& mode, const std::string& ident, const int& option, const int& facility) {
+ m_oPrintLock.lock();
+ m_pFile = NULL;
+ m_sFileName = "";
+ m_iLogFacility = facility;
+ m_sIdent = ident;
+ m_eMode = mode;
+ m_oPrintLock.unlock();
+ openlog(m_sIdent.c_str(), option, m_iLogFacility);
+ return true;
+}
+
diff --git a/src/MTS_Object.cpp b/src/MTS_Object.cpp
new file mode 100644
index 0000000..c798c70
--- /dev/null
+++ b/src/MTS_Object.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_Object.h>
+#include <sstream>
+#include <typeinfo>
+
+using namespace MTS;
+
+Object::Object() {
+}
+
+Object::~Object() {
+}
+
+std::string Object::toString() const {
+ return std::string("MTS::Object");
+}
+
+std::string Object::toIDD() const {
+ std::stringstream ss;
+ ss << typeid(*this).name() << "@" << reinterpret_cast<const void*>(this);
+ return ss.str().erase(0, 6);
+}
diff --git a/src/MTS_SignalThread.cpp b/src/MTS_SignalThread.cpp
new file mode 100644
index 0000000..99975c0
--- /dev/null
+++ b/src/MTS_SignalThread.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_SignalThread.h>
+#include <mts/MTS_Logger.h>
+
+using namespace MTS;
+
+SignalThread::SignalThread(const std::string& name)
+: Thread(name, true)
+, m_bShouldExecute(false)
+, m_bCurrentlyExecuting(false)
+, m_ui32WaitMillis(200)
+{
+ init();
+}
+
+SignalThread::SignalThread(const std::string& name, uint32_t waitMillis)
+: Thread(name, true)
+, m_bShouldExecute(false)
+, m_bCurrentlyExecuting(false)
+, m_ui32WaitMillis(waitMillis)
+{
+ init();
+}
+
+void SignalThread::init()
+{
+ printConfig("SignalThread| %s - starting up", Thread::getName().c_str());
+ m_apStateLock.reset(new MTS::Lock);
+ m_apConditionLock.reset(new MTS::Lock);
+ m_apCondition.reset(m_apConditionLock->createCondition());
+}
+
+SignalThread::~SignalThread()
+{
+ stop();
+ m_apStateLock.reset();
+ m_apConditionLock.reset();
+ m_apCondition.reset();
+ printConfig("SignalThread| %s - shutting down", Thread::getName().c_str());
+}
+
+void SignalThread::signal()
+{
+ m_apConditionLock->lock();
+ m_bShouldExecute = true;
+ m_apCondition->signal();
+ m_apConditionLock->unlock();
+}
+
+void SignalThread::run()
+{
+ while (! Thread::isCanceled())
+ {
+ m_apConditionLock->lock();
+ if (! m_bShouldExecute)
+ {
+ m_apCondition->wait(m_ui32WaitMillis);
+ }
+ if (m_bShouldExecute)
+ {
+ printTrace("SignalThread| %s - starting execute() function", Thread::getName().c_str());
+ m_apStateLock->lock();
+ m_bCurrentlyExecuting = true;
+ m_apStateLock->unlock();
+ execute();
+ m_apStateLock->lock();
+ m_bCurrentlyExecuting = false;
+ m_apStateLock->unlock();
+ printTrace("SignalThread| %s - finished execute() function", Thread::getName().c_str());
+ }
+ m_bShouldExecute = false;
+ m_apConditionLock->unlock();
+ }
+}
+
+bool SignalThread::isExecuting() const
+{
+ bool retval = false;
+ m_apStateLock->lock();
+ retval = m_bCurrentlyExecuting;
+ m_apStateLock->unlock();
+
+ return retval;
+}
diff --git a/src/MTS_System.cpp b/src/MTS_System.cpp
new file mode 100644
index 0000000..e1ed348
--- /dev/null
+++ b/src/MTS_System.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_System.h>
+#include <fstream>
+#include <sstream>
+#include <cassert>
+
+#ifdef WIN32
+#include <windows.h>
+
+//WIN32: FILETIME structure has a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601.
+
+static int64_t getEpochTimeMicros() {
+ const SYSTEMTIME EPOCH = {1970, 1, 4, 1, 0, 0, 0, 0};
+ FILETIME ft;
+ BOOL ok = SystemTimeToFileTime(&EPOCH, &ft);
+ assert(ok);
+ int64_t epochTimeMicros = ((static_cast<uint64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) / 10;
+ return epochTimeMicros;
+}
+
+static int64_t getSystemTimeMicros() {
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ FILETIME ft;
+ BOOL ok = SystemTimeToFileTime(&st, &ft);
+ assert(ok);
+ int64_t systemTimeMicros = ((static_cast<uint64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) / 10;
+ return systemTimeMicros;
+}
+
+static int64_t getClockFrequency() {
+ LARGE_INTEGER freq;
+ BOOL ok = QueryPerformanceFrequency(&freq);
+ assert(ok);
+ return freq.QuadPart;
+}
+
+static int64_t getClockValue() {
+ LARGE_INTEGER value;
+ BOOL ok = QueryPerformanceCounter(&value);
+ assert(ok);
+ return value.QuadPart;
+}
+
+#else
+#include <time.h>
+#endif
+
+using namespace MTS;
+
+uint64_t System::timeMicros() {
+ int64_t micros = 0;
+#ifdef WIN32
+ static const int64_t EPOCH_TIME_MICROS = getEpochTimeMicros();
+ micros = getSystemTimeMicros() - EPOCH_TIME_MICROS;
+#else
+ timespec ts;
+ int result = clock_gettime(CLOCK_REALTIME, &ts);
+ if (result == 0) {
+ micros = (static_cast<int64_t>(ts.tv_sec) * 1000000)
+ + (ts.tv_nsec / 1000);
+ }
+#endif
+ return micros;
+}
+
+uint64_t System::precisionTimeMicros() {
+ int64_t micros = 0;
+#ifdef WIN32
+ static const double TO_MICROS = 1000000.0 / getClockFrequency();
+ int64_t value = getClockValue();
+ micros = static_cast<int64_t>(value * TO_MICROS);
+#else
+ micros = timeMicros();
+#endif
+ return micros;
+}
+
+bool System::isBigEndian() {
+ static union {
+ uint32_t i;
+ char c[4];
+ } endian = { 0x01020304 };
+
+ return endian.c[0] == 1;
+}
+
+void System::swapBytes(uint8_t* const pBuffer, const uint32_t iSize) {
+ if (iSize > 1 && pBuffer != 0) {
+ uint8_t cByte = 0;
+ uint32_t i;
+ uint32_t j;
+ for (i = 0, j = iSize - 1; i < j; i++, j--) {
+ cByte = pBuffer[i];
+ pBuffer[i] = pBuffer[j];
+ pBuffer[j] = cByte;
+ }
+ }
+}
+
+int32_t System::cmd(const std::string& cmd, std::string& result) {
+ std::string output;
+ FILE * stream;
+ const int max_buffer = 256;
+ char buffer[max_buffer];
+ int32_t code = -1;
+
+ stream = popen(cmd.c_str(), "r");
+ if (stream) {
+ while (!feof(stream))
+ if (fgets(buffer, max_buffer, stream) != NULL)
+ output.append(buffer);
+ code = pclose(stream);
+ }
+
+ result = output;
+
+ return code;
+}
+
+int32_t System::readFile(const std::string& path, std::string& result) {
+ std::ifstream infile(path.c_str());
+ std::stringstream ss;
+
+ if (!infile.is_open()) {
+ return -1;
+ }
+
+ ss << infile.rdbuf();
+
+ infile.close();
+
+ result = ss.str();
+
+ return 0;
+}
+
diff --git a/src/MTS_Text.cpp b/src/MTS_Text.cpp
new file mode 100644
index 0000000..d823bfe
--- /dev/null
+++ b/src/MTS_Text.cpp
@@ -0,0 +1,701 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_Text.h>
+//#include <mts/MTS_Logger.h>
+#include <algorithm>
+#include <sstream>
+#include <iostream>
+#include <limits>
+
+using namespace MTS;
+
+//strftime
+//%a Abbreviated weekday name * Thu
+//%A Full weekday name * Thursday
+//%b Abbreviated month name * Aug
+//%B Full month name * August
+//%c Date and time representation * Thu Aug 23 14:55:02 2001
+//%d Day of the month (01-31) 23
+//%H Hour in 24h format (00-23) 14
+//%I Hour in 12h format (01-12) 02
+//%j Day of the year (001-366) 235
+//%m Month as a decimal number (01-12) 08
+//%M Minute (00-59) 55
+//%p AM or PM designation PM
+//%S Second (00-61) 02
+//%U Week number with the first Sunday as the first day of week one (00-53) 33
+//%w Weekday as a decimal number with Sunday as 0 (0-6) 4
+//%W Week number with the first Monday as the first day of week one (00-53) 34
+//%x Date representation * 08/23/01
+//%X Time representation * 14:55:02
+//%y Year, last two digits (00-99) 01
+//%Y Year 2001
+//%Z Timezone name or abbreviation CDT
+//%% A % sign %
+
+//Example
+///* strftime example */
+//#include <stdio.h>
+//#include <time.h>
+//
+//int main ()
+//{
+// time_t rawtime;
+// struct tm * timeinfo;
+// char buffer [80];
+//
+// time ( &rawtime );
+// timeinfo = localtime ( &rawtime );
+//
+// strftime (buffer,80,"Now it's %I:%M%p.",timeinfo);
+// puts (buffer);
+//
+// return 0;
+//}
+
+std::string Text::time(const uint64_t& iTimeMicros, const TIMEFORMAT& eTime) {
+ int64_t now = iTimeMicros / 1000;
+ int64_t millis = now % 1000;
+ int64_t secs = (now / 1000) % 60;
+ int64_t mins = (now / 60000) % 60;
+ int64_t hours = (now / 3600000) % 24;
+ std::stringstream sBuffer;
+
+ switch (eTime) {
+ case HHcMMcSScmmm:
+ sBuffer << hours << ":" << mins << ":" << secs << ":" << millis;
+ return sBuffer.str();
+ break;
+ case HHcMMcSS:
+ sBuffer << (hours < 10 ? "0" : "") << hours << ":" << (mins < 10 ? "0" : "") << mins << ":" << (secs < 10 ? "0" : "") << secs;
+ return sBuffer.str();
+ break;
+
+ }
+ return std::string("UNKNOWN-TIME-FORMAT");
+}
+
+std::string Text::date(const tm& stTime, const DATEFORMAT& eDate) {
+ char buffer[80];
+
+ switch (eDate) {
+ case MMsDDsYY:
+ strftime(buffer, 80, "%x", &stTime);
+ return std::string(buffer);
+ break;
+ case MMsDDsYY_HHcMMcSS:
+ strftime(buffer, 80, "%m/%d/%Y %H:%M:%S", &stTime);
+ return std::string(buffer);
+ break;
+ case RFC_1123:
+ std::stringstream sBuffer;
+ //Thu, 01 Jan 1970 00:00:01 GMT
+ //Week
+ switch (stTime.tm_wday) {
+ case 0:
+ sBuffer << "Sun, ";
+ break;
+ case 1:
+ sBuffer << "Mon, ";
+ break;
+ case 2:
+ sBuffer << "Tue, ";
+ break;
+ case 3:
+ sBuffer << "Wed, ";
+ break;
+ case 4:
+ sBuffer << "Thu, ";
+ break;
+ case 5:
+ sBuffer << "Fri, ";
+ break;
+ case 6:
+ sBuffer << "Sat, ";
+ break;
+ }
+
+ //Day of Month
+ sBuffer << (stTime.tm_mday < 10 ? "0" : "") << stTime.tm_mday;
+
+ //Month
+ switch (stTime.tm_mon) {
+ case 0:
+ sBuffer << " Jan ";
+ break;
+ case 1:
+ sBuffer << " Feb ";
+ break;
+ case 2:
+ sBuffer << " Mar ";
+ break;
+ case 3:
+ sBuffer << " Apr ";
+ break;
+ case 4:
+ sBuffer << " May ";
+ break;
+ case 5:
+ sBuffer << " Jun ";
+ break;
+ case 6:
+ sBuffer << " Jul ";
+ break;
+ case 7:
+ sBuffer << " Aug ";
+ break;
+ case 8:
+ sBuffer << " Sep ";
+ break;
+ case 9:
+ sBuffer << " Oct ";
+ break;
+ case 10:
+ sBuffer << " Nov ";
+ break;
+ case 11:
+ sBuffer << " Dec ";
+ break;
+ }
+
+ sBuffer << (stTime.tm_year + 1900);
+ sBuffer << (stTime.tm_hour < 10 ? " 0" : " ") << stTime.tm_hour << ":" << (stTime.tm_min < 10 ? "0" : "") << stTime.tm_min << ":" << (stTime.tm_sec < 10 ? "0" : "")
+ << stTime.tm_sec;
+ sBuffer << " GMT";
+ return sBuffer.str();
+ break;
+ }
+ return std::string("UNKNOWN-DATE-FORMAT");
+}
+
+bool Text::datetimeIsBefore(const std::string& time1, const std::string& time2) {
+
+ struct tm tm1;
+ struct tm tm2;
+
+ strptime(time1.c_str(), "%x %T", &tm1);
+ strptime(time2.c_str(), "%x %T", &tm2);
+
+ return difftime(mktime(&tm2), mktime(&tm1)) > 0;
+}
+
+std::vector<std::string> Text::split(const std::string& str, char delimiter, int limit) {
+ return split(str, std::string(1, delimiter), limit);
+}
+
+std::vector<std::string> Text::split(const std::string& str, const std::string& delimiter, int limit) {
+ std::vector<std::string> result;
+ if(str.size() == 0) {
+ return result;
+ }
+ if (limit <= 0) {
+ limit = std::numeric_limits<int>::max();
+ }
+ size_t start = 0;
+ size_t end = str.find(delimiter, start);
+ for (int i = 1; (i < limit) && (end != std::string::npos); ++i) {
+ result.push_back(str.substr(start, end - start));
+ start = end + delimiter.length();
+ end = str.find(delimiter, start);
+ }
+ result.push_back(str.substr(start));
+ return result;
+}
+
+std::string Text::join(std::vector<std::string> list, char delimiter) {
+
+ std::stringstream ss;
+ for (uint32_t i = 0; i < list.size(); i++) {
+ ss << list[i];
+ if (i < list.size() - 1)
+ ss << delimiter;
+ }
+ return ss.str();
+}
+
+std::string Text::replace(const std::string& original, const std::string& from, const std::string& to) {
+ size_t start_pos = 0;
+ std::string str(original);
+ while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
+ str.replace(start_pos, from.length(), to);
+ start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
+ }
+ return str;
+}
+
+uint32_t Text::count(const std::string& str, const std::string& element) {
+ uint32_t count = 0;
+ size_t start_pos = 0;
+ while ((start_pos = str.find(element, start_pos)) != std::string::npos) {
+ start_pos++;
+ count++;
+ }
+ return count;
+}
+
+uint32_t Text::count(const std::string& str, const uint8_t& element) {
+ uint32_t count = 0;
+ size_t start_pos = 0;
+ while ((start_pos = str.find(element, start_pos)) != std::string::npos) {
+ start_pos++;
+ count++;
+ }
+ return count;
+}
+
+bool Text::endsWith(const std::string& str, const std::string& key) {
+ if (key.size() > str.size()) return false;
+ return std::equal(str.begin() + str.size() - key.size(), str.end(), key.begin());
+}
+
+std::string Text::getLine(const std::string& source, const size_t& start, size_t& cursor) {
+ char delimiters[2];
+ delimiters[0] = '\n';
+ delimiters[1] = '\r';
+ if(start > source.size()) {
+ cursor = std::string::npos;
+ return "";
+ }
+ size_t end = source.find_first_of(delimiters, start, 2);
+ std::string line(source.substr(start, end - start));
+ //printDebug("[TEXT] Start [%d] Cursor[%d] Size[%d] Line: %s", start, end, source.size(), line.c_str());
+ if (end < source.size()) {
+ if (end < source.size() - 1)
+ if ((source[end] == '\n' && source[end + 1] == '\r') || (source[end] == '\r' && source[end + 1] == '\n')) {
+ //Advance an additional character in scenarios where lines end in \r\n or \n\r
+ end++;
+ }
+ end++;
+ }
+ cursor = end;
+ return line;
+}
+
+std::string Text::trim(const std::string& str) {
+ size_t length = str.length();
+ size_t start = length;
+ for (size_t i = 0; i < length; ++i) {
+ if (!isspace(static_cast<unsigned char>(str[i]))) {
+ start = i;
+ break;
+ }
+ }
+ size_t end = std::string::npos;
+ for (size_t i = length - 1; i != std::string::npos; --i) {
+ if (!isspace(static_cast<unsigned char>(str[i]))) {
+ end = i + 1;
+ break;
+ }
+ }
+ return str.substr(start, end - start);
+}
+
+std::string Text::trim(const std::string& str, const uint8_t& element) {
+ size_t length = str.length();
+ size_t start = length;
+ for (size_t i = 0; i < length; ++i) {
+ if (static_cast<unsigned char>(str[i]) != element) {
+ start = i;
+ break;
+ }
+ }
+ size_t end = std::string::npos;
+ for (size_t i = length - 1; i != std::string::npos; --i) {
+ if (static_cast<unsigned char>(str[i]) != element) {
+ end = i + 1;
+ break;
+ }
+ }
+ return str.substr(start, end - start);
+}
+
+
+std::string Text::strip(const std::string& str, const std::vector<uint8_t>& elements) {
+ std::string result(str);
+ for (uint32_t i = 0; i < elements.size(); i++) {
+ result.erase (std::remove(result.begin(), result.end(), elements[i]), result.end());
+ }
+ return result;
+}
+
+std::string Text::strip(const std::string& str, const uint8_t& element) {
+ std::string result(str);
+ result.erase (std::remove(result.begin(), result.end(), element), result.end());
+ return result;
+}
+
+std::string Text::toLowerCase(const std::string& str) {
+ std::string result(str);
+ size_t length = result.length();
+ for (size_t i = 0; i < length; ++i) {
+ result[i] = static_cast<char>(tolower(static_cast<unsigned char>(result[i])));
+ }
+ return result;
+}
+
+std::string Text::toUpperCase(const std::string& str) {
+ std::string result(str);
+ size_t length = result.length();
+ for (size_t i = 0; i < length; ++i) {
+ result[i] = static_cast<char>(toupper(static_cast<unsigned char>(result[i])));
+ }
+ return result;
+}
+
+std::string Text::toCapitalized(const std::string& str) {
+ std::string result;
+ result = str;
+ if (str.size() == 0)
+ return result;
+ else if (str.size() == 1)
+ return toUpperCase(result);
+ else
+ return toUpperCase(result.substr(0, 1)) + toLowerCase(result.substr(1));
+}
+
+std::string Text::toCamelCase(const std::string& str) {
+ std::string result;
+ if (str.size() == 0) {
+ return result;
+ }
+
+ std::vector<std::string> parts = MTS::Text::split(str, ' ');
+
+ if (parts.size() == 0 || parts[0].size() == 0) {
+ return result;
+ }
+ result.append(MTS::Text::toLowerCase(parts[0]));
+
+ for (uint32_t i = 1; i < parts.size(); i++) {
+ result.append(MTS::Text::toCapitalized(parts[i]));
+ }
+
+ return result;
+}
+
+std::string Text::toCommandLineEscaped(const std::string& str) {
+ std::string result(str);
+ result = Text::replace(result, "#", "\\#");
+ result = Text::replace(result, ".", "\\.");
+ result = Text::replace(result, "&", "\\&");
+ result = Text::replace(result, "?", "\\?");
+ return result;
+}
+
+std::wstring Text::widen(const std::string& str) {
+ std::wstringstream wss;
+ size_t length = str.length();
+ for (size_t i = 0; i < length; ++i) {
+ wss << wss.widen(str[i]);
+ }
+ return wss.str();
+}
+
+std::string Text::narrow(const std::wstring& str) {
+ std::wstringstream wss;
+ std::stringstream ss;
+ size_t length = str.length();
+ for (size_t i = 0; i < length; ++i) {
+ ss << wss.narrow(str[i], '?');
+ }
+ return ss.str();
+}
+
+std::string Text::format(bool value) {
+ std::stringstream ss;
+ ss.setf(ss.boolalpha);
+ ss << value;
+ return ss.str();
+}
+
+std::string Text::format(double value, std::streamsize percision) {
+ std::stringstream ss;
+ ss.setf(ss.fixed, ss.floatfield);
+ ss.precision(percision);
+ ss << value;
+ std::string str = ss.str();
+ // strip trailing zeros
+ size_t pos = str.find_last_not_of('0');
+ if (pos != std::string::npos) {
+ if (str[pos] == '.') {
+ pos += 2;
+ } else {
+ pos += 1;
+ }
+ }
+ return str.substr(0, pos);
+}
+
+std::string Text::format(int8_t value) {
+ return format(static_cast<int64_t>(value));
+}
+
+std::string Text::format(int16_t value) {
+ return format(static_cast<int64_t>(value));
+}
+
+std::string Text::format(int32_t value) {
+ return format(static_cast<int64_t>(value));
+}
+
+std::string Text::format(int64_t value) {
+ std::stringstream ss;
+ ss.setf(ss.dec, ss.basefield);
+ ss << value;
+ return ss.str();
+}
+
+std::string Text::format(uint8_t value) {
+ return format(static_cast<uint64_t>(value));
+}
+
+std::string Text::format(uint16_t value) {
+ return format(static_cast<uint64_t>(value));
+}
+
+std::string Text::format(uint32_t value) {
+ return format(static_cast<uint64_t>(value));
+}
+
+std::string Text::format(uint64_t value) {
+ std::stringstream ss;
+ ss.setf(ss.dec, ss.basefield);
+ ss << value;
+ return ss.str();
+}
+
+static std::string toHexString(uint64_t value, bool pad, std::streamsize padSize) {
+ std::stringstream ss;
+ ss.unsetf(ss.showbase);
+ ss.setf(ss.hex, ss.basefield);
+ ss.setf(ss.uppercase);
+ if (pad) {
+ ss.width(padSize);
+ ss.fill('0');
+ }
+ ss << value;
+ return ss.str();
+}
+
+std::string Text::formatHex(int8_t value, bool pad) {
+ return formatHex(static_cast<uint8_t>(value), pad);
+}
+
+std::string Text::formatHex(int16_t value, bool pad) {
+ return formatHex(static_cast<uint16_t>(value), pad);
+}
+
+std::string Text::formatHex(int32_t value, bool pad) {
+ return formatHex(static_cast<uint32_t>(value), pad);
+}
+
+std::string Text::formatHex(int64_t value, bool pad) {
+ return formatHex(static_cast<uint64_t>(value), pad);
+}
+
+std::string Text::formatHex(uint8_t value, bool pad) {
+ return toHexString(value, pad, 2);
+}
+
+std::string Text::formatHex(uint16_t value, bool pad) {
+ return toHexString(value, pad, 4);
+}
+
+std::string Text::formatHex(uint32_t value, bool pad) {
+ return toHexString(value, pad, 8);
+}
+
+std::string Text::formatHex(uint64_t value, bool pad) {
+ return toHexString(value, pad, 16);
+}
+
+std::string Text::formatHex(const Buffer& value) {
+ char hex[4];
+ std::string hexstr;
+ for (uint32_t i = 0; i < value.getSize(); i++) {
+ sprintf(hex, "%X", value.at(i));
+ hexstr.append(hex);
+ }
+ return hexstr;
+}
+
+bool Text::parse(bool& value, const std::string& str) {
+ if (str.empty()) {
+ return false;
+ }
+ std::istringstream ss(str);
+ ss.setf(ss.boolalpha);
+ ss.unsetf(ss.skipws);
+ ss >> value;
+ return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK);
+}
+
+bool Text::parse(double& value, const std::string& str) {
+ if (str.empty()) {
+ return false;
+ }
+ std::istringstream ss(str);
+ ss.setf(ss.fixed, ss.basefield);
+ ss.unsetf(ss.skipws);
+ ss >> value;
+ return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK);
+}
+
+bool Text::parse(int8_t& value, const std::string& str) {
+ int64_t i64 = 0;
+ if (!parse(i64, str)) {
+ return false;
+ }
+ if (i64 < INT8_MIN || i64 > INT8_MAX) {
+ return false;
+ }
+ value = static_cast<int8_t>(i64);
+ return true;
+}
+
+bool Text::parse(int16_t& value, const std::string& str) {
+ int64_t i64 = 0;
+ if (!parse(i64, str)) {
+ return false;
+ }
+ if (i64 < INT16_MIN || i64 > INT16_MAX) {
+ return false;
+ }
+ value = static_cast<int16_t>(i64);
+ return true;
+}
+
+bool Text::parse(int32_t& value, const std::string& str) {
+ int64_t i64 = 0;
+ if (!parse(i64, str)) {
+ return false;
+ }
+ if (i64 < INT32_MIN || i64 > INT32_MAX) {
+ return false;
+ }
+ value = static_cast<int32_t>(i64);
+ return true;
+}
+
+bool Text::parse(int64_t& value, const std::string& str) {
+ if (str.empty()) {
+ return false;
+ }
+ std::istringstream ss(str);
+ ss.setf(ss.dec, ss.basefield);
+ ss.unsetf(ss.skipws);
+ ss >> value;
+ return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK);
+}
+
+bool Text::parse(uint8_t& value, const std::string& str) {
+ uint64_t u64 = 0;
+ if (!parse(u64, str)) {
+ return false;
+ }
+ if (u64 > UINT8_MAX) {
+ return false;
+ }
+ value = static_cast<uint8_t>(u64);
+ return true;
+}
+
+bool Text::parse(uint16_t& value, const std::string& str) {
+ uint64_t u64 = 0;
+ if (!parse(u64, str)) {
+ return false;
+ }
+ if (u64 > UINT16_MAX) {
+ return false;
+ }
+ value = static_cast<uint16_t>(u64);
+ return true;
+}
+
+bool Text::parse(uint32_t& value, const std::string& str) {
+ uint64_t u64 = 0;
+ if (!parse(u64, str)) {
+ return false;
+ }
+ if (u64 > UINT32_MAX) {
+ return false;
+ }
+ value = static_cast<uint32_t>(u64);
+ return true;
+}
+
+bool Text::parse(uint64_t& value, const std::string& str) {
+ if (str.empty()) {
+ return false;
+ }
+ std::istringstream ss(str);
+ ss.setf(ss.dec, ss.basefield);
+ ss.unsetf(ss.skipws);
+ ss >> value;
+ return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK);
+}
+
+bool Text::parseHex(uint8_t& value, const std::string& str) {
+ uint64_t u64 = 0;
+ if (!parseHex(u64, str)) {
+ return false;
+ }
+ if (u64 > UINT8_MAX) {
+ return false;
+ }
+ value = static_cast<uint8_t>(u64);
+ return true;
+}
+
+bool Text::parseHex(uint16_t& value, const std::string& str) {
+ uint64_t u64 = 0;
+ if (!parseHex(u64, str)) {
+ return false;
+ }
+ if (u64 > UINT16_MAX) {
+ return false;
+ }
+ value = static_cast<uint16_t>(u64);
+ return true;
+}
+
+bool Text::parseHex(uint32_t& value, const std::string& str) {
+ uint64_t u64 = 0;
+ if (!parseHex(u64, str)) {
+ return false;
+ }
+ if (u64 > UINT32_MAX) {
+ return false;
+ }
+ value = static_cast<uint32_t>(u64);
+ return true;
+}
+
+bool Text::parseHex(uint64_t& value, const std::string& str) {
+
+ if (str.empty()) {
+ return false;
+ }
+ std::istringstream ss(str);
+ ss >> std::hex >> value;
+ return ((uint8_t) ss.rdstate() == RDSTATE_SUCCESS_MASK);
+}
+
diff --git a/src/MTS_Thread.cpp b/src/MTS_Thread.cpp
new file mode 100644
index 0000000..3537731
--- /dev/null
+++ b/src/MTS_Thread.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_Thread.h>
+#include <mts/MTS_Logger.h>
+#include <new>
+#include <cassert>
+
+using namespace MTS;
+
+Thread::Thread(const std::string& name, bool managed)
+: m_pThread(NULL)
+, m_sName(name)
+, m_bManaged(managed)
+, m_bComplete(true)
+, m_bCanceled(true)
+{
+ printConfig("Thread| %s()", getName().c_str());
+ m_apThreadLock.reset(new Lock());
+ m_apStateLock.reset(new Lock());
+ m_apCompleteCondition.reset(m_apStateLock->createCondition());
+}
+
+Thread::~Thread() {
+ m_bCanceled = true;
+ Thread::stop();
+ m_apCompleteCondition.reset();
+ m_apStateLock.reset();
+ m_apThreadLock.reset();
+ printConfig("Thread| %s - deconstructed", getName().c_str());
+}
+
+void Thread::sleep(uint32_t millis) {
+#ifdef WIN32
+ Sleep(millis);
+#else
+ Lock lock;
+ Condition* condition = lock.createCondition();
+ lock.lock();
+ condition->wait(millis);
+ lock.unlock();
+ delete condition;
+#endif
+}
+
+const std::string& Thread::getName() const {
+ return m_sName;
+}
+
+void Thread::start() {
+ m_apThreadLock->lock();
+ try {
+ if (m_pThread == NULL) {
+ reset();
+#ifdef WIN32
+ m_pThread = CreateThread(NULL, 0, &doInBackground, this, 0, NULL);
+#else
+ m_pThread = new (std::nothrow) pthread_t;
+ if (m_pThread != NULL) {
+ const int result = pthread_create(m_pThread, NULL,
+ &doInBackground, this);
+ assert(result == 0);
+ if (result != 0) {
+ delete m_pThread;
+ m_pThread = NULL;
+ }
+ }
+
+#endif
+ assert(m_pThread != NULL);
+ if (m_pThread != NULL) {
+ printConfig("Thread| %s - started (%p)",
+ getName().c_str(), m_pThread);
+ } else {
+ printWarning("Thread| Failed to start runnable %s",
+ getName().c_str());
+ m_apStateLock->lock();
+ m_bCanceled = true;
+ m_bComplete = true;
+ m_apStateLock->unlock();
+ }
+ }
+ } catch (...) {
+ printWarning("Thread| Failed to start runnable %s", getName().c_str());
+ assert(false);
+ }
+ m_apThreadLock->unlock();
+}
+
+void Thread::stop() {
+ m_apThreadLock->lock();
+ cancel();
+ if (m_pThread != NULL) {
+ wait(1500);
+
+#ifdef WIN32
+ if (!isDone()) {
+ TerminateThread(m_pThread, 1);
+ printConfig("Thread| %s - terminated", getName().c_str());
+ }
+ const BOOL ok = CloseHandle(m_pThread);
+ assert(ok);
+#else
+ if (!isDone()) {
+ printConfig("Thread| %s - terminated", getName().c_str());
+ }
+ delete m_pThread;
+#endif
+ m_pThread = NULL;
+ } else if (!isDone()) {
+ done();
+ }
+ m_apThreadLock->unlock();
+}
+
+void Thread::wait() {
+ m_apStateLock->lock();
+ if (!m_bComplete) {
+ m_apCompleteCondition->wait();
+ }
+ m_apStateLock->unlock();
+}
+
+void Thread::wait(uint32_t millis) {
+ m_apStateLock->lock();
+ if (!m_bComplete) {
+ m_apCompleteCondition->wait(millis);
+ }
+ m_apStateLock->unlock();
+}
+
+bool Thread::isAlive() const {
+ bool result = false;
+ m_apThreadLock->lock();
+ result = (m_pThread != NULL);
+ m_apThreadLock->unlock();
+ return result;
+}
+
+bool Thread::isCanceled() const {
+ bool result = false;
+ m_apStateLock->lock();
+ result = m_bCanceled;
+ m_apStateLock->unlock();
+ return result;
+}
+
+void Thread::cancel() {
+ m_apStateLock->lock();
+ if (!m_bCanceled) {
+ m_bCanceled = true;
+ printConfig("Thread| %s - cancelled", getName().c_str());
+ }
+ m_apStateLock->unlock();
+}
+
+bool Thread::isDone() const {
+ bool result = false;
+ m_apStateLock->lock();
+ result = m_bComplete;
+ m_apStateLock->unlock();
+ return result;
+}
+
+void Thread::done() {
+ m_apStateLock->lock();
+ m_bComplete = true;
+ m_apCompleteCondition->signal();
+ printConfig("Thread| %s - done", getName().c_str());
+ m_apStateLock->unlock();
+}
+
+void Thread::reset() {
+ m_apStateLock->lock();
+ m_bCanceled = false;
+ m_bComplete = false;
+ m_apStateLock->unlock();
+}
+
+bool Thread::isManaged() const {
+ return m_bManaged;
+}
+
+#ifdef WIN32
+DWORD WINAPI Thread::doInBackground(__in LPVOID parameter) {
+#else
+void* Thread::doInBackground(void* parameter) {
+#endif
+
+ Thread* runnable = static_cast<Thread*>(parameter);
+ assert(runnable != NULL);
+ if (runnable != NULL) {
+ printConfig("Thread| %s - initializing\n", runnable->getName().c_str());
+ try {
+ runnable->run();
+ } catch (...) {
+ printWarning("Thread| exception caught while running %s",
+ runnable->getName().c_str());
+ }
+ printConfig("Thread| %s - finalizing", runnable->getName().c_str());
+ bool managed = runnable->isManaged();
+ runnable->done();
+ if (!managed) {
+ printConfig("Thread| %s - deleted", runnable->getName().c_str());
+ delete runnable;
+ }
+ }
+ return 0;
+}
+
diff --git a/src/MTS_Timer.cpp b/src/MTS_Timer.cpp
new file mode 100644
index 0000000..2158c29
--- /dev/null
+++ b/src/MTS_Timer.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_Timer.h>
+#include <mts/MTS_System.h>
+
+using namespace MTS;
+
+Timer::Timer()
+: m_iStart(0)
+, m_iPause(0)
+, m_bStarted(false)
+, m_bPaused(false)
+{
+
+}
+
+Timer::~Timer() {
+
+}
+
+void Timer::start() {
+ if(m_bStarted) {
+ return;
+ }
+
+ m_iStart = System::timeMicros();
+ m_bStarted = true;
+ m_bPaused = false;
+}
+
+void Timer::stop() {
+ m_bStarted = false;
+}
+
+void Timer::pause() {
+ if(m_bPaused || !m_bStarted) {
+ return;
+ }
+
+ m_iPause = System::timeMicros();
+ m_bPaused = true;
+}
+
+void Timer::resume() {
+ if(!m_bPaused) {
+ return;
+ }
+
+ m_iStart += System::timeMicros() + m_iPause;
+ m_bPaused = false;
+}
+
+void Timer::reset() {
+ m_iStart = System::timeMicros();
+ m_bPaused = false;
+}
+
+bool Timer::isRunning() {
+ return !m_bPaused && m_bStarted;
+}
+
+uint64_t Timer::getMicros() {
+ if(!m_bStarted) {
+ return 0;
+ }
+
+ if(m_bPaused) {
+ return m_iPause - m_iStart;
+ }
+
+ return System::timeMicros() - m_iStart;
+}
+
+uint64_t Timer::getMillis() {
+ return getMicros() / 1000;
+}
+
+uint64_t Timer::getSeconds() {
+ return getMicros() / 1000000;
+}
+
+uint64_t Timer::getMinutes() {
+ return getMicros() / (1000000*60);
+}
+
diff --git a/src/MTS_TimerThread.cpp b/src/MTS_TimerThread.cpp
new file mode 100644
index 0000000..5a69c46
--- /dev/null
+++ b/src/MTS_TimerThread.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of libmts.
+ *
+ * libmts is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_TimerThread.h>
+#include <mts/MTS_Logger.h>
+
+using namespace MTS;
+
+TimerThread::TimerThread(const std::string& name)
+: Thread(name, true)
+, m_bCurrentlyExecuting(false)
+, m_bExecutionStopped(false)
+, m_ui32IntervalMillis(1000)
+{
+ init();
+}
+
+TimerThread::TimerThread(const std::string& name, uint32_t intervalMillis)
+: Thread(name, true)
+, m_bCurrentlyExecuting(false)
+, m_bExecutionStopped(false)
+, m_ui32IntervalMillis(intervalMillis)
+{
+ init();
+}
+
+void TimerThread::init()
+{
+ printConfig("TimerThread| %s - starting up", Thread::getName().c_str());
+ m_apStateLock.reset(new MTS::Lock);
+}
+
+TimerThread::~TimerThread()
+{
+ stop();
+ m_apStateLock.reset();
+ printConfig("TimerThread| %s - shutting down", Thread::getName().c_str());
+}
+
+void TimerThread::stopExecution()
+{
+ m_apStateLock->lock();
+ m_bExecutionStopped = true;
+ m_apStateLock->unlock();
+ printDebug("TimerThread| %s - stopping execution of task", Thread::getName().c_str());
+}
+
+void TimerThread::restartExecution()
+{
+ m_apStateLock->lock();
+ m_bExecutionStopped = false;
+ m_apStateLock->unlock();
+ printDebug("TimerThread| %s - restarting execution of task", Thread::getName().c_str());
+}
+
+void TimerThread::run()
+{
+ uint32_t intervalMillis;
+ bool executionStopped;
+
+ while (! Thread::isCanceled())
+ {
+ m_apStateLock->lock();
+ intervalMillis = m_ui32IntervalMillis;
+ executionStopped = m_bExecutionStopped;
+ m_apStateLock->unlock();
+
+ if (! executionStopped)
+ {
+ printTrace("TimerThread| %s - starting execute() function", Thread::getName().c_str());
+ m_apStateLock->lock();
+ m_bCurrentlyExecuting = true;
+ m_apStateLock->unlock();
+ execute();
+ m_apStateLock->lock();
+ m_bCurrentlyExecuting = false;
+ m_apStateLock->unlock();
+ printTrace("TimerThread| %s - finished execute() function", Thread::getName().c_str());
+ }
+ Thread::sleep(intervalMillis);
+ }
+}
+
+bool TimerThread::isExecuting() const
+{
+ bool retval = false;
+ m_apStateLock->lock();
+ retval = m_bCurrentlyExecuting;
+ m_apStateLock->unlock();
+
+ return retval;
+}
+
+void TimerThread::updateIntervalMillis(uint32_t newMillis)
+{
+ m_apStateLock->lock();
+ m_ui32IntervalMillis = newMillis;
+ m_apStateLock->unlock();
+}