diff options
Diffstat (limited to 'src/common/Utilities')
| -rw-r--r-- | src/common/Utilities/Containers.h | 23 | ||||
| -rw-r--r-- | src/common/Utilities/EventMap.h | 14 | ||||
| -rw-r--r-- | src/common/Utilities/EventProcessor.cpp | 80 | ||||
| -rw-r--r-- | src/common/Utilities/EventProcessor.h | 40 | ||||
| -rw-r--r-- | src/common/Utilities/MessageBuffer.h | 139 | ||||
| -rw-r--r-- | src/common/Utilities/Random.cpp | 8 | ||||
| -rw-r--r-- | src/common/Utilities/Random.h | 20 | ||||
| -rw-r--r-- | src/common/Utilities/StartProcess.cpp | 269 | ||||
| -rw-r--r-- | src/common/Utilities/StartProcess.h | 67 | ||||
| -rw-r--r-- | src/common/Utilities/StringFormat.h | 2 | ||||
| -rw-r--r-- | src/common/Utilities/TaskScheduler.h | 8 | ||||
| -rw-r--r-- | src/common/Utilities/Timer.h | 4 | ||||
| -rw-r--r-- | src/common/Utilities/Util.cpp | 76 | ||||
| -rw-r--r-- | src/common/Utilities/Util.h | 49 |
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> |
