aboutsummaryrefslogtreecommitdiff
path: root/src/common/Utilities
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/Utilities')
-rw-r--r--src/common/Utilities/Containers.h23
-rw-r--r--src/common/Utilities/EventMap.h14
-rw-r--r--src/common/Utilities/EventProcessor.cpp80
-rw-r--r--src/common/Utilities/EventProcessor.h40
-rw-r--r--src/common/Utilities/MessageBuffer.h139
-rw-r--r--src/common/Utilities/Random.cpp8
-rw-r--r--src/common/Utilities/Random.h20
-rw-r--r--src/common/Utilities/StartProcess.cpp269
-rw-r--r--src/common/Utilities/StartProcess.h67
-rw-r--r--src/common/Utilities/StringFormat.h2
-rw-r--r--src/common/Utilities/TaskScheduler.h8
-rw-r--r--src/common/Utilities/Timer.h4
-rw-r--r--src/common/Utilities/Util.cpp76
-rw-r--r--src/common/Utilities/Util.h49
14 files changed, 698 insertions, 101 deletions
diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h
index f3e9432ca4c..5edb245fd87 100644
--- a/src/common/Utilities/Containers.h
+++ b/src/common/Utilities/Containers.h
@@ -20,6 +20,7 @@
#include "Define.h"
#include "Random.h"
+#include "Util.h"
#include <algorithm>
#include <functional>
#include <list>
@@ -30,9 +31,9 @@ namespace Trinity
namespace Containers
{
template<class T>
- void RandomResizeList(std::list<T> &list, uint32 size)
+ void RandomResizeList(std::list<T>& list, uint32 size)
{
- size_t list_size = list.size();
+ uint32 list_size = uint32(list.size());
while (list_size > size)
{
@@ -55,7 +56,7 @@ namespace Trinity
if (size)
RandomResizeList(listCopy, size);
- list = listCopy;
+ list = std::move(listCopy);
}
/*
@@ -67,7 +68,7 @@ namespace Trinity
typename C::value_type const& SelectRandomContainerElement(C const& container)
{
typename C::const_iterator it = container.begin();
- std::advance(it, urand(0, container.size() - 1));
+ std::advance(it, urand(0, uint32(container.size()) - 1));
return *it;
}
@@ -117,6 +118,19 @@ namespace Trinity
}
/**
+ * @fn void Trinity::Containers::RandomShuffle(C& container)
+ *
+ * @brief Reorder the elements of the container randomly.
+ *
+ * @param container Container to reorder
+ */
+ template <class C>
+ void RandomShuffle(C& container)
+ {
+ std::shuffle(container.begin(), container.end(), SFMTEngine::Instance());
+ }
+
+ /**
* @fn bool Trinity::Containers::Intersects(Iterator first1, Iterator last1, Iterator first2, Iterator last2)
*
* @brief Checks if two SORTED containers have a common element
@@ -156,7 +170,6 @@ namespace Trinity
++itr;
}
}
-
}
//! namespace Containers
}
diff --git a/src/common/Utilities/EventMap.h b/src/common/Utilities/EventMap.h
index a1aaa9af269..6a314a9e633 100644
--- a/src/common/Utilities/EventMap.h
+++ b/src/common/Utilities/EventMap.h
@@ -22,7 +22,7 @@
#include "Duration.h"
#include "Util.h"
-class EventMap
+class TC_COMMON_API EventMap
{
/**
* Internal storage type.
@@ -122,7 +122,7 @@ public:
*/
void ScheduleEvent(uint32 eventId, Milliseconds const& time, uint32 group = 0, uint8 phase = 0)
{
- ScheduleEvent(eventId, time.count(), group, phase);
+ ScheduleEvent(eventId, uint32(time.count()), group, phase);
}
/**
@@ -145,7 +145,7 @@ public:
*/
void RescheduleEvent(uint32 eventId, Milliseconds const& time, uint32 group = 0, uint8 phase = 0)
{
- RescheduleEvent(eventId, time.count(), group, phase);
+ RescheduleEvent(eventId, uint32(time.count()), group, phase);
}
/**
@@ -169,7 +169,7 @@ public:
*/
void Repeat(Milliseconds const& time)
{
- Repeat(time.count());
+ Repeat(uint32(time.count()));
}
/**
@@ -190,7 +190,7 @@ public:
*/
void Repeat(Milliseconds const& minTime, Milliseconds const& maxTime)
{
- Repeat(minTime.count(), maxTime.count());
+ Repeat(uint32(minTime.count()), uint32(maxTime.count()));
}
/**
@@ -218,7 +218,7 @@ public:
*/
void DelayEvents(Milliseconds const& delay)
{
- DelayEvents(delay.count());
+ DelayEvents(uint32(delay.count()));
}
/**
@@ -239,7 +239,7 @@ public:
*/
void DelayEvents(Milliseconds const& delay, uint32 group)
{
- DelayEvents(delay.count(), group);
+ DelayEvents(uint32(delay.count()), group);
}
/**
diff --git a/src/common/Utilities/EventProcessor.cpp b/src/common/Utilities/EventProcessor.cpp
index be74d58b790..2341d0a0872 100644
--- a/src/common/Utilities/EventProcessor.cpp
+++ b/src/common/Utilities/EventProcessor.cpp
@@ -17,11 +17,20 @@
*/
#include "EventProcessor.h"
+#include "Errors.h"
-EventProcessor::EventProcessor()
+void BasicEvent::ScheduleAbort()
{
- m_time = 0;
- m_aborting = false;
+ ASSERT(IsRunning()
+ && "Tried to scheduled the abortion of an event twice!");
+ m_abortState = AbortState::STATE_ABORT_SCHEDULED;
+}
+
+void BasicEvent::SetAborted()
+{
+ ASSERT(!IsAborted()
+ && "Tried to abort an already aborted event!");
+ m_abortState = AbortState::STATE_ABORTED;
}
EventProcessor::~EventProcessor()
@@ -39,55 +48,73 @@ void EventProcessor::Update(uint32 p_time)
while (((i = m_events.begin()) != m_events.end()) && i->first <= m_time)
{
// get and remove event from queue
- BasicEvent* Event = i->second;
+ BasicEvent* event = i->second;
m_events.erase(i);
- if (!Event->to_Abort)
+ if (event->IsRunning())
{
- if (Event->Execute(m_time, p_time))
+ if (event->Execute(m_time, p_time))
{
// completely destroy event if it is not re-added
- delete Event;
+ delete event;
}
+ continue;
}
- else
+
+ if (event->IsAbortScheduled())
{
- Event->Abort(m_time);
- delete Event;
+ event->Abort(m_time);
+ // Mark the event as aborted
+ event->SetAborted();
}
+
+ if (event->IsDeletable())
+ {
+ delete event;
+ continue;
+ }
+
+ // Reschedule non deletable events to be checked at
+ // the next update tick
+ AddEvent(event, CalculateTime(1), false);
}
}
void EventProcessor::KillAllEvents(bool force)
{
- // prevent event insertions
- m_aborting = true;
-
- // first, abort all existing events
- for (EventList::iterator i = m_events.begin(); i != m_events.end();)
+ for (auto itr = m_events.begin(); itr != m_events.end();)
{
- EventList::iterator i_old = i;
- ++i;
-
- i_old->second->to_Abort = true;
- i_old->second->Abort(m_time);
- if (force || i_old->second->IsDeletable())
+ // Abort events which weren't aborted already
+ if (!itr->second->IsAborted())
{
- delete i_old->second;
+ itr->second->SetAborted();
+ itr->second->Abort(m_time);
+ }
- if (!force) // need per-element cleanup
- m_events.erase (i_old);
+ // Skip non-deletable events when we are
+ // not forcing the event cancellation.
+ if (!force && !itr->second->IsDeletable())
+ {
+ ++itr;
+ continue;
}
+
+ delete itr->second;
+
+ if (force)
+ ++itr; // Clear the whole container when forcing
+ else
+ itr = m_events.erase(itr);
}
- // fast clear event list (in force case)
if (force)
m_events.clear();
}
void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime)
{
- if (set_addtime) Event->m_addTime = m_time;
+ if (set_addtime)
+ Event->m_addTime = m_time;
Event->m_execTime = e_time;
m_events.insert(std::pair<uint64, BasicEvent*>(e_time, Event));
}
@@ -96,4 +123,3 @@ uint64 EventProcessor::CalculateTime(uint64 t_offset) const
{
return(m_time + t_offset);
}
-
diff --git a/src/common/Utilities/EventProcessor.h b/src/common/Utilities/EventProcessor.h
index e5eafed79b9..57f3065f323 100644
--- a/src/common/Utilities/EventProcessor.h
+++ b/src/common/Utilities/EventProcessor.h
@@ -20,20 +20,27 @@
#define __EVENTPROCESSOR_H
#include "Define.h"
-
#include <map>
+class EventProcessor;
+
// Note. All times are in milliseconds here.
-class BasicEvent
+class TC_COMMON_API BasicEvent
{
+ friend class EventProcessor;
+
+ enum class AbortState : uint8
+ {
+ STATE_RUNNING,
+ STATE_ABORT_SCHEDULED,
+ STATE_ABORTED
+ };
+
public:
BasicEvent()
- {
- to_Abort = false;
- m_addTime = 0;
- m_execTime = 0;
- }
+ : m_abortState(AbortState::STATE_RUNNING), m_addTime(0), m_execTime(0) { }
+
virtual ~BasicEvent() { } // override destructor to perform some actions on event removal
// this method executes when the event is triggered
@@ -45,8 +52,16 @@ class BasicEvent
virtual void Abort(uint64 /*e_time*/) { } // this method executes when the event is aborted
- bool to_Abort; // set by externals when the event is aborted, aborted events don't execute
- // and get Abort call when deleted
+ // Aborts the event at the next update tick
+ void ScheduleAbort();
+
+ private:
+ void SetAborted();
+ bool IsRunning() const { return (m_abortState == AbortState::STATE_RUNNING); }
+ bool IsAbortScheduled() const { return (m_abortState == AbortState::STATE_ABORT_SCHEDULED); }
+ bool IsAborted() const { return (m_abortState == AbortState::STATE_ABORTED); }
+
+ AbortState m_abortState; // set by externals when the event is aborted, aborted events don't execute
// these can be used for time offset control
uint64 m_addTime; // time when the event was added to queue, filled by event handler
@@ -55,19 +70,20 @@ class BasicEvent
typedef std::multimap<uint64, BasicEvent*> EventList;
-class EventProcessor
+class TC_COMMON_API EventProcessor
{
public:
- EventProcessor();
+ EventProcessor() : m_time(0) { }
~EventProcessor();
void Update(uint32 p_time);
void KillAllEvents(bool force);
void AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime = true);
uint64 CalculateTime(uint64 t_offset) const;
+
protected:
uint64 m_time;
EventList m_events;
- bool m_aborting;
};
+
#endif
diff --git a/src/common/Utilities/MessageBuffer.h b/src/common/Utilities/MessageBuffer.h
new file mode 100644
index 00000000000..d08c4b25bab
--- /dev/null
+++ b/src/common/Utilities/MessageBuffer.h
@@ -0,0 +1,139 @@
+/*
+* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program 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/>.
+*/
+
+#ifndef __MESSAGEBUFFER_H_
+#define __MESSAGEBUFFER_H_
+
+#include "Define.h"
+#include <vector>
+#include <cstring>
+
+class MessageBuffer
+{
+ typedef std::vector<uint8>::size_type size_type;
+
+public:
+ MessageBuffer() : _wpos(0), _rpos(0), _storage()
+ {
+ _storage.resize(4096);
+ }
+
+ explicit MessageBuffer(std::size_t initialSize) : _wpos(0), _rpos(0), _storage()
+ {
+ _storage.resize(initialSize);
+ }
+
+ MessageBuffer(MessageBuffer const& right) : _wpos(right._wpos), _rpos(right._rpos), _storage(right._storage)
+ {
+ }
+
+ MessageBuffer(MessageBuffer&& right) : _wpos(right._wpos), _rpos(right._rpos), _storage(right.Move()) { }
+
+ void Reset()
+ {
+ _wpos = 0;
+ _rpos = 0;
+ }
+
+ void Resize(size_type bytes)
+ {
+ _storage.resize(bytes);
+ }
+
+ uint8* GetBasePointer() { return _storage.data(); }
+
+ uint8* GetReadPointer() { return GetBasePointer() + _rpos; }
+
+ uint8* GetWritePointer() { return GetBasePointer() + _wpos; }
+
+ void ReadCompleted(size_type bytes) { _rpos += bytes; }
+
+ void WriteCompleted(size_type bytes) { _wpos += bytes; }
+
+ size_type GetActiveSize() const { return _wpos - _rpos; }
+
+ size_type GetRemainingSpace() const { return _storage.size() - _wpos; }
+
+ size_type GetBufferSize() const { return _storage.size(); }
+
+ // Discards inactive data
+ void Normalize()
+ {
+ if (_rpos)
+ {
+ if (_rpos != _wpos)
+ memmove(GetBasePointer(), GetReadPointer(), GetActiveSize());
+ _wpos -= _rpos;
+ _rpos = 0;
+ }
+ }
+
+ // Ensures there's "some" free space, make sure to call Normalize() before this
+ void EnsureFreeSpace()
+ {
+ // resize buffer if it's already full
+ if (GetRemainingSpace() == 0)
+ _storage.resize(_storage.size() * 3 / 2);
+ }
+
+ void Write(void const* data, std::size_t size)
+ {
+ if (size)
+ {
+ memcpy(GetWritePointer(), data, size);
+ WriteCompleted(size);
+ }
+ }
+
+ std::vector<uint8>&& Move()
+ {
+ _wpos = 0;
+ _rpos = 0;
+ return std::move(_storage);
+ }
+
+ MessageBuffer& operator=(MessageBuffer const& right)
+ {
+ if (this != &right)
+ {
+ _wpos = right._wpos;
+ _rpos = right._rpos;
+ _storage = right._storage;
+ }
+
+ return *this;
+ }
+
+ MessageBuffer& operator=(MessageBuffer&& right)
+ {
+ if (this != &right)
+ {
+ _wpos = right._wpos;
+ _rpos = right._rpos;
+ _storage = right.Move();
+ }
+
+ return *this;
+ }
+
+private:
+ size_type _wpos;
+ size_type _rpos;
+ std::vector<uint8> _storage;
+};
+
+#endif /* __MESSAGEBUFFER_H_ */
diff --git a/src/common/Utilities/Random.cpp b/src/common/Utilities/Random.cpp
index cc013110b01..31318e8f52d 100644
--- a/src/common/Utilities/Random.cpp
+++ b/src/common/Utilities/Random.cpp
@@ -61,6 +61,14 @@ float frand(float min, float max)
return float(GetRng()->Random() * (max - min) + min);
}
+Milliseconds randtime(Milliseconds const& min, Milliseconds const& max)
+{
+ long long diff = max.count() - min.count();
+ ASSERT(diff >= 0);
+ ASSERT(diff <= (uint32)-1);
+ return min + Milliseconds(urand(0, diff));
+}
+
uint32 rand32()
{
return GetRng()->BRandom();
diff --git a/src/common/Utilities/Random.h b/src/common/Utilities/Random.h
index 5610651a83b..b3ca00219ef 100644
--- a/src/common/Utilities/Random.h
+++ b/src/common/Utilities/Random.h
@@ -19,29 +19,33 @@
#define Random_h__
#include "Define.h"
+#include "Duration.h"
#include <limits>
#include <random>
/* Return a random number in the range min..max. */
-int32 irand(int32 min, int32 max);
+TC_COMMON_API int32 irand(int32 min, int32 max);
/* Return a random number in the range min..max (inclusive). */
-uint32 urand(uint32 min, uint32 max);
+TC_COMMON_API uint32 urand(uint32 min, uint32 max);
/* Return a random millisecond value between min and max seconds. Functionally equivalent to urand(min*IN_MILLISECONDS, max*IN_MILLISECONDS). */
-uint32 urandms(uint32 min, uint32 max);
+TC_COMMON_API uint32 urandms(uint32 min, uint32 max);
/* Return a random number in the range 0 .. UINT32_MAX. */
-uint32 rand32();
+TC_COMMON_API uint32 rand32();
+
+/* Return a random time in the range min..max (up to millisecond precision). Only works for values where millisecond difference is a valid uint32. */
+TC_COMMON_API Milliseconds randtime(Milliseconds const& min, Milliseconds const& max);
/* Return a random number in the range min..max */
-float frand(float min, float max);
+TC_COMMON_API float frand(float min, float max);
/* Return a random double from 0.0 to 1.0 (exclusive). */
-double rand_norm();
+TC_COMMON_API double rand_norm();
/* Return a random double from 0.0 to 100.0 (exclusive). */
-double rand_chance();
+TC_COMMON_API double rand_chance();
/* Return true if a random roll fits in the specified chance (range 0-100). */
inline bool roll_chance_f(float chance)
@@ -58,7 +62,7 @@ inline bool roll_chance_i(int chance)
/*
* SFMT wrapper satisfying UniformRandomNumberGenerator concept for use in <random> algorithms
*/
-class SFMTEngine
+class TC_COMMON_API SFMTEngine
{
public:
typedef uint32 result_type;
diff --git a/src/common/Utilities/StartProcess.cpp b/src/common/Utilities/StartProcess.cpp
new file mode 100644
index 00000000000..f35c6de3b5c
--- /dev/null
+++ b/src/common/Utilities/StartProcess.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program 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 "StartProcess.h"
+
+#include <atomic>
+#include <thread>
+#include <functional>
+
+#include <boost/algorithm/string/join.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/iostreams/copy.hpp>
+#include <boost/iostreams/concepts.hpp>
+#include <boost/iostreams/device/file_descriptor.hpp>
+#include <boost/process.hpp>
+#include <boost/system/system_error.hpp>
+
+#include "Common.h"
+#include "Log.h"
+
+using namespace boost::process;
+using namespace boost::process::initializers;
+using namespace boost::iostreams;
+
+namespace Trinity {
+
+template<typename T>
+class TCLogSink
+{
+ T callback_;
+
+public:
+ typedef char char_type;
+ typedef sink_tag category;
+
+ // Requires a callback type which has a void(std::string) signature
+ TCLogSink(T callback)
+ : callback_(std::move(callback)) { }
+
+ std::streamsize write(const char* str, std::streamsize size)
+ {
+ callback_(std::string(str, size));
+ return size;
+ }
+};
+
+template<typename T>
+auto MakeTCLogSink(T&& callback)
+ -> TCLogSink<typename std::decay<T>::type>
+{
+ return { std::forward<T>(callback) };
+}
+
+template<typename T>
+static int CreateChildProcess(T waiter, std::string const& executable,
+ std::vector<std::string> const& args,
+ std::string const& logger, std::string const& input,
+ bool secure)
+{
+ auto outPipe = create_pipe();
+ auto errPipe = create_pipe();
+
+ Optional<file_descriptor_source> inputSource;
+
+ if (!secure)
+ {
+ TC_LOG_TRACE(logger, "Starting process \"%s\" with arguments: \"%s\".",
+ executable.c_str(), boost::algorithm::join(args, " ").c_str());
+ }
+
+ // Start the child process
+ child c = [&]
+ {
+ if (!input.empty())
+ {
+ inputSource = file_descriptor_source(input);
+
+ // With binding stdin
+ return execute(run_exe(boost::filesystem::absolute(executable)),
+ set_args(args),
+ inherit_env(),
+ bind_stdin(*inputSource),
+ bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)),
+ bind_stderr(file_descriptor_sink(errPipe.sink, close_handle)));
+ }
+ else
+ {
+ // Without binding stdin
+ return execute(run_exe(boost::filesystem::absolute(executable)),
+ set_args(args),
+ inherit_env(),
+ bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)),
+ bind_stderr(file_descriptor_sink(errPipe.sink, close_handle)));
+ }
+ }();
+
+ file_descriptor_source outFd(outPipe.source, close_handle);
+ file_descriptor_source errFd(errPipe.source, close_handle);
+
+ auto outInfo = MakeTCLogSink([&](std::string msg)
+ {
+ TC_LOG_INFO(logger, "%s", msg.c_str());
+ });
+
+ auto outError = MakeTCLogSink([&](std::string msg)
+ {
+ TC_LOG_ERROR(logger, "%s", msg.c_str());
+ });
+
+ copy(outFd, outInfo);
+ copy(errFd, outError);
+
+ // Call the waiter in the current scope to prevent
+ // the streams from closing too early on leaving the scope.
+ int const result = waiter(c);
+
+ if (!secure)
+ {
+ TC_LOG_TRACE(logger, ">> Process \"%s\" finished with return value %i.",
+ executable.c_str(), result);
+ }
+
+ if (inputSource)
+ inputSource->close();
+
+ return result;
+}
+
+int StartProcess(std::string const& executable, std::vector<std::string> const& args,
+ std::string const& logger, std::string input_file, bool secure)
+{
+ return CreateChildProcess([](child& c) -> int
+ {
+ try
+ {
+ return wait_for_exit(c);
+ }
+ catch (...)
+ {
+ return EXIT_FAILURE;
+ }
+ }, executable, args, logger, input_file, secure);
+}
+
+class AsyncProcessResultImplementation
+ : public AsyncProcessResult
+{
+ std::string const executable;
+ std::vector<std::string> const args;
+ std::string const logger;
+ std::string const input_file;
+ bool const is_secure;
+
+ std::atomic<bool> was_terminated;
+
+ // Workaround for missing move support in boost < 1.57
+ Optional<std::shared_ptr<std::future<int>>> result;
+ Optional<std::reference_wrapper<child>> my_child;
+
+public:
+ explicit AsyncProcessResultImplementation(std::string executable_, std::vector<std::string> args_,
+ std::string logger_, std::string input_file_,
+ bool secure)
+ : executable(std::move(executable_)), args(std::move(args_)),
+ logger(std::move(logger_)), input_file(input_file_),
+ is_secure(secure), was_terminated(false) { }
+
+ AsyncProcessResultImplementation(AsyncProcessResultImplementation const&) = delete;
+ AsyncProcessResultImplementation& operator= (AsyncProcessResultImplementation const&) = delete;
+ AsyncProcessResultImplementation(AsyncProcessResultImplementation&&) = delete;
+ AsyncProcessResultImplementation& operator= (AsyncProcessResultImplementation&&) = delete;
+
+ int StartProcess()
+ {
+ ASSERT(!my_child, "Process started already!");
+
+ return CreateChildProcess([&](child& c) -> int
+ {
+ int result;
+ my_child = std::reference_wrapper<child>(c);
+
+ try
+ {
+ result = wait_for_exit(c);
+ }
+ catch (...)
+ {
+ result = EXIT_FAILURE;
+ }
+
+ my_child.reset();
+ return was_terminated ? EXIT_FAILURE : result;
+
+ }, executable, args, logger, input_file, is_secure);
+ }
+
+ void SetFuture(std::future<int> result_)
+ {
+ result = std::make_shared<std::future<int>>(std::move(result_));
+ }
+
+ /// Returns the future which contains the result of the process
+ /// as soon it is finished.
+ std::future<int>& GetFutureResult() override
+ {
+ ASSERT(*result, "The process wasn't started!");
+ return **result;
+ }
+
+ /// Tries to terminate the process
+ void Terminate() override
+ {
+ if (!my_child)
+ {
+ was_terminated = true;
+ try
+ {
+ terminate(my_child->get());
+ }
+ catch(...)
+ {
+ // Do nothing
+ }
+ }
+ }
+};
+
+std::shared_ptr<AsyncProcessResult>
+ StartAsyncProcess(std::string executable, std::vector<std::string> args,
+ std::string logger, std::string input_file, bool secure)
+{
+ auto handle = std::make_shared<AsyncProcessResultImplementation>(
+ std::move(executable), std::move(args), std::move(logger), std::move(input_file), secure);
+
+ handle->SetFuture(std::async(std::launch::async, [handle] { return handle->StartProcess(); }));
+ return handle;
+}
+
+Optional<std::string> SearchExecutableInPath(std::string const& filename)
+{
+ try
+ {
+ auto result = search_path(filename);
+ if (result.empty())
+ return boost::none;
+ else
+ return result;
+ }
+ catch (...)
+ {
+ return boost::none;
+ }
+}
+
+} // namespace Trinity
diff --git a/src/common/Utilities/StartProcess.h b/src/common/Utilities/StartProcess.h
new file mode 100644
index 00000000000..3b380bd4f4e
--- /dev/null
+++ b/src/common/Utilities/StartProcess.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program 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/>.
+ */
+
+#ifndef Process_h__
+#define Process_h__
+
+#include <future>
+#include <memory>
+#include "Common.h"
+
+namespace Trinity {
+
+/// Starts a process with the given arguments and parameters and will block
+/// until the process is finished.
+/// When an input path is given, the file will be routed to the processes stdin.
+/// When the process is marked as secure no arguments are leaked to logs.
+/// Note that most executables expect it's name as the first argument.
+TC_COMMON_API int StartProcess(std::string const& executable, std::vector<std::string> const& args,
+ std::string const& logger, std::string input_file = "",
+ bool secure = false);
+
+/// Platform and library independent representation
+/// of asynchronous process results
+class AsyncProcessResult
+{
+public:
+ virtual ~AsyncProcessResult() { }
+
+ /// Returns the future which contains the result of the process
+ /// as soon it is finished.
+ virtual std::future<int>& GetFutureResult() = 0;
+
+ /// Tries to terminate the process
+ virtual void Terminate() = 0;
+};
+
+/// Starts a process asynchronously with the given arguments and parameters and
+/// returns an AsyncProcessResult immediately which is set, when the process exits.
+/// When an input path is given, the file will be routed to the processes stdin.
+/// When the process is marked as secure no arguments are leaked to logs.
+/// Note that most executables expect it's name as the first argument.
+TC_COMMON_API std::shared_ptr<AsyncProcessResult>
+ StartAsyncProcess(std::string executable, std::vector<std::string> args,
+ std::string logger, std::string input_file = "",
+ bool secure = false);
+
+/// Searches for the given executable in the PATH variable
+/// and returns a present optional when it was found.
+TC_COMMON_API Optional<std::string> SearchExecutableInPath(std::string const& filename);
+
+} // namespace Trinity
+
+#endif // Process_h__
diff --git a/src/common/Utilities/StringFormat.h b/src/common/Utilities/StringFormat.h
index d85523bc11f..e21b1024e87 100644
--- a/src/common/Utilities/StringFormat.h
+++ b/src/common/Utilities/StringFormat.h
@@ -19,7 +19,7 @@
#ifndef TRINITYCORE_STRING_FORMAT_H
#define TRINITYCORE_STRING_FORMAT_H
-#include "format.h"
+#include "cppformat/format.h"
namespace Trinity
{
diff --git a/src/common/Utilities/TaskScheduler.h b/src/common/Utilities/TaskScheduler.h
index 8cf5d914128..6784c968683 100644
--- a/src/common/Utilities/TaskScheduler.h
+++ b/src/common/Utilities/TaskScheduler.h
@@ -46,7 +46,7 @@ class TaskContext;
/// with the same duration or a new one.
/// It also provides access to the repeat counter which is useful for task that repeat itself often
/// but behave different every time (spoken event dialogs for example).
-class TaskScheduler
+class TC_COMMON_API TaskScheduler
{
friend class TaskContext;
@@ -131,7 +131,7 @@ class TaskScheduler
};
};
- class TaskQueue
+ class TC_COMMON_API TaskQueue
{
std::multiset<TaskContainer, Compare> container;
@@ -401,14 +401,14 @@ private:
auto const milli_max = std::chrono::duration_cast<std::chrono::milliseconds>(max);
// TC specific: use SFMT URandom
- return std::chrono::milliseconds(urand(milli_min.count(), milli_max.count()));
+ return std::chrono::milliseconds(urand(uint32(milli_min.count()), uint32(milli_max.count())));
}
/// Dispatch remaining tasks
void Dispatch(success_t const& callback);
};
-class TaskContext
+class TC_COMMON_API TaskContext
{
friend class TaskScheduler;
diff --git a/src/common/Utilities/Timer.h b/src/common/Utilities/Timer.h
index cdce08caaf0..f66bb90c98e 100644
--- a/src/common/Utilities/Timer.h
+++ b/src/common/Utilities/Timer.h
@@ -25,9 +25,9 @@ inline uint32 getMSTime()
{
using namespace std::chrono;
- static const system_clock::time_point ApplicationStartTime = system_clock::now();
+ static const steady_clock::time_point ApplicationStartTime = steady_clock::now();
- return uint32(duration_cast<milliseconds>(system_clock::now() - ApplicationStartTime).count());
+ return uint32(duration_cast<milliseconds>(steady_clock::now() - ApplicationStartTime).count());
}
inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp
index 1360253294f..3d8cda66d48 100644
--- a/src/common/Utilities/Util.cpp
+++ b/src/common/Utilities/Util.cpp
@@ -22,6 +22,7 @@
#include "utf8.h"
#include "Errors.h" // for ASSERT
#include <stdarg.h>
+#include <boost/algorithm/string/case_conv.hpp>
#if COMPILER == COMPILER_GNU
#include <sys/socket.h>
@@ -218,22 +219,29 @@ bool IsIPAddress(char const* ipaddress)
}
/// create PID file
-uint32 CreatePIDFile(const std::string& filename)
+uint32 CreatePIDFile(std::string const& filename)
{
- FILE* pid_file = fopen (filename.c_str(), "w" );
+ FILE* pid_file = fopen(filename.c_str(), "w");
if (pid_file == NULL)
return 0;
+ uint32 pid = GetPID();
+
+ fprintf(pid_file, "%u", pid);
+ fclose(pid_file);
+
+ return pid;
+}
+
+uint32 GetPID()
+{
#ifdef _WIN32
DWORD pid = GetCurrentProcessId();
#else
pid_t pid = getpid();
#endif
- fprintf(pid_file, "%u", pid );
- fclose(pid_file);
-
- return (uint32)pid;
+ return uint32(pid);
}
size_t utf8length(std::string& utf8str)
@@ -418,7 +426,7 @@ bool utf8ToConsole(const std::string& utf8str, std::string& conStr)
return false;
conStr.resize(wstr.size());
- CharToOemBuffW(&wstr[0], &conStr[0], wstr.size());
+ CharToOemBuffW(&wstr[0], &conStr[0], uint32(wstr.size()));
#else
// not implemented yet
conStr = utf8str;
@@ -432,7 +440,7 @@ bool consoleToUtf8(const std::string& conStr, std::string& utf8str)
#if PLATFORM == PLATFORM_WINDOWS
std::wstring wstr;
wstr.resize(conStr.size());
- OemToCharBuffW(&conStr[0], &wstr[0], conStr.size());
+ OemToCharBuffW(&conStr[0], &wstr[0], uint32(conStr.size()));
return WStrToUtf8(wstr, utf8str);
#else
@@ -450,7 +458,7 @@ bool Utf8FitTo(const std::string& str, std::wstring const& search)
return false;
// converting to lower case
- wstrToLower( temp );
+ wstrToLower(temp);
if (temp.find(search) == std::wstring::npos)
return false;
@@ -469,10 +477,10 @@ void utf8printf(FILE* out, const char *str, ...)
void vutf8printf(FILE* out, const char *str, va_list* ap)
{
#if PLATFORM == PLATFORM_WINDOWS
- char temp_buf[32*1024];
- wchar_t wtemp_buf[32*1024];
+ char temp_buf[32 * 1024];
+ wchar_t wtemp_buf[32 * 1024];
- size_t temp_len = vsnprintf(temp_buf, 32*1024, str, *ap);
+ size_t temp_len = vsnprintf(temp_buf, 32 * 1024, str, *ap);
//vsnprintf returns -1 if the buffer is too small
if (temp_len == size_t(-1))
temp_len = 32*1024-1;
@@ -480,13 +488,24 @@ void vutf8printf(FILE* out, const char *str, va_list* ap)
size_t wtemp_len = 32*1024-1;
Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len);
- CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len+1);
+ CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], uint32(wtemp_len + 1));
fprintf(out, "%s", temp_buf);
#else
vfprintf(out, str, *ap);
#endif
}
+bool Utf8ToUpperOnlyLatin(std::string& utf8String)
+{
+ std::wstring wstr;
+ if (!Utf8toWStr(utf8String, wstr))
+ return false;
+
+ std::transform(wstr.begin(), wstr.end(), wstr.begin(), wcharToUpperOnlyLatin);
+
+ return WStrToUtf8(wstr, utf8String);
+}
+
std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */)
{
int32 init = 0;
@@ -510,3 +529,34 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse
return ss.str();
}
+
+void HexStrToByteArray(std::string const& str, uint8* out, bool reverse /*= false*/)
+{
+ // string must have even number of characters
+ if (str.length() & 1)
+ return;
+
+ int32 init = 0;
+ int32 end = int32(str.length());
+ int8 op = 1;
+
+ if (reverse)
+ {
+ init = int32(str.length() - 2);
+ end = -2;
+ op = -1;
+ }
+
+ uint32 j = 0;
+ for (int32 i = init; i != end; i += 2 * op)
+ {
+ char buffer[3] = { str[i], str[i + 1], '\0' };
+ out[j++] = uint8(strtoul(buffer, NULL, 16));
+ }
+}
+
+bool StringToBool(std::string const& str)
+{
+ std::string lowerStr = boost::algorithm::to_lower_copy(str);
+ return lowerStr == "1" || lowerStr == "true" || lowerStr == "yes";
+}
diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h
index ab5cabca8d2..cc68f3b2237 100644
--- a/src/common/Utilities/Util.h
+++ b/src/common/Utilities/Util.h
@@ -40,7 +40,7 @@ template<typename T, class S> struct Finder
bool operator()(const std::pair<int, S> &obj) { return obj.second.*idMember_ == val_; }
};
-class Tokenizer
+class TC_COMMON_API Tokenizer
{
public:
typedef std::vector<char const*> StorageType;
@@ -68,15 +68,15 @@ private:
StorageType m_storage;
};
-void stripLineInvisibleChars(std::string &src);
+TC_COMMON_API void stripLineInvisibleChars(std::string &src);
-int32 MoneyStringToMoney(const std::string& moneyString);
+TC_COMMON_API int32 MoneyStringToMoney(const std::string& moneyString);
-struct tm* localtime_r(const time_t* time, struct tm *result);
+TC_COMMON_API struct tm* localtime_r(const time_t* time, struct tm *result);
-std::string secsToTimeString(uint64 timeInSecs, bool shortText = false, bool hoursOnly = false);
-uint32 TimeStringToSecs(const std::string& timestring);
-std::string TimeToTimestampStr(time_t t);
+TC_COMMON_API std::string secsToTimeString(uint64 timeInSecs, bool shortText = false, bool hoursOnly = false);
+TC_COMMON_API uint32 TimeStringToSecs(const std::string& timestring);
+TC_COMMON_API std::string TimeToTimestampStr(time_t t);
inline void ApplyPercentModFloatVar(float& var, float val, bool apply)
{
@@ -111,20 +111,20 @@ inline T RoundToInterval(T& num, T floor, T ceil)
}
// UTF8 handling
-bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr);
+TC_COMMON_API bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr);
// in wsize==max size of buffer, out wsize==real string size
-bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize);
+TC_COMMON_API bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize);
inline bool Utf8toWStr(const std::string& utf8str, wchar_t* wstr, size_t& wsize)
{
return Utf8toWStr(utf8str.c_str(), utf8str.size(), wstr, wsize);
}
-bool WStrToUtf8(std::wstring const& wstr, std::string& utf8str);
+TC_COMMON_API bool WStrToUtf8(std::wstring const& wstr, std::string& utf8str);
// size==real string size
-bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str);
+TC_COMMON_API bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str);
-size_t utf8length(std::string& utf8str); // set string to "" if invalid utf8 sequence
-void utf8truncate(std::string& utf8str, size_t len);
+TC_COMMON_API size_t utf8length(std::string& utf8str); // set string to "" if invalid utf8 sequence
+TC_COMMON_API void utf8truncate(std::string& utf8str, size_t len);
inline bool isBasicLatinCharacter(wchar_t wchar)
{
@@ -303,19 +303,24 @@ inline void wstrToLower(std::wstring& str)
std::transform( str.begin(), str.end(), str.begin(), wcharToLower );
}
-std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension);
+TC_COMMON_API std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension);
-bool utf8ToConsole(const std::string& utf8str, std::string& conStr);
-bool consoleToUtf8(const std::string& conStr, std::string& utf8str);
-bool Utf8FitTo(const std::string& str, std::wstring const& search);
-void utf8printf(FILE* out, const char *str, ...);
-void vutf8printf(FILE* out, const char *str, va_list* ap);
+TC_COMMON_API bool utf8ToConsole(const std::string& utf8str, std::string& conStr);
+TC_COMMON_API bool consoleToUtf8(const std::string& conStr, std::string& utf8str);
+TC_COMMON_API bool Utf8FitTo(const std::string& str, std::wstring const& search);
+TC_COMMON_API void utf8printf(FILE* out, const char *str, ...);
+TC_COMMON_API void vutf8printf(FILE* out, const char *str, va_list* ap);
+TC_COMMON_API bool Utf8ToUpperOnlyLatin(std::string& utf8String);
-bool IsIPAddress(char const* ipaddress);
+TC_COMMON_API bool IsIPAddress(char const* ipaddress);
-uint32 CreatePIDFile(const std::string& filename);
+TC_COMMON_API uint32 CreatePIDFile(std::string const& filename);
+TC_COMMON_API uint32 GetPID();
-std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false);
+TC_COMMON_API std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false);
+TC_COMMON_API void HexStrToByteArray(std::string const& str, uint8* out, bool reverse = false);
+
+TC_COMMON_API bool StringToBool(std::string const& str);
// simple class for not-modifyable list
template <typename T>