diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt index 40f55285889..0d38d543180 100644 --- a/dep/CMakeLists.txt +++ b/dep/CMakeLists.txt @@ -35,6 +35,7 @@ if(SERVERS OR TOOLS) endif() if(SERVERS) + add_subdirectory(cppformat) add_subdirectory(gsoap) add_subdirectory(zmqpp) endif() diff --git a/dep/PackageList.txt b/dep/PackageList.txt index a2cddda888d..d6264b2a5e8 100644 --- a/dep/PackageList.txt +++ b/dep/PackageList.txt @@ -8,6 +8,10 @@ bzip2 (a freely available, patent free, high-quality data compressor) http://www.bzip.org/ Version: 1.0.6 +cppformat (type safe format library) + https://github.com/cppformat/cppformat + Version: 1.1.0 da547f5533f338cc0c65877b44ca40adf31754f7 + G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License) http://g3d.sourceforge.net/ Version: 9.0-Release r4036 diff --git a/dep/cppformat/CMakeLists.txt b/dep/cppformat/CMakeLists.txt index 3be3e5f6dbb..7f17bf69582 100644 --- a/dep/cppformat/CMakeLists.txt +++ b/dep/cppformat/CMakeLists.txt @@ -6,7 +6,12 @@ set(FMT_SOURCES format.cc format.h) # Use variadic templates add_definitions(-DFMT_VARIADIC_TEMPLATES=1) -# Use deleted functions +# Check if initializer lists are supported. +check_cxx_source_compiles(" + #include + int main() {}" FMT_INITIALIZER_LIST) + +# Use delete add_definitions(-DFMT_USE_DELETED_FUNCTIONS=1) # Use static assert diff --git a/dep/cppformat/ChangeLog.rst b/dep/cppformat/ChangeLog.rst index 89d5af8e9c7..fe780ae010c 100644 --- a/dep/cppformat/ChangeLog.rst +++ b/dep/cppformat/ChangeLog.rst @@ -71,7 +71,7 @@ `#96 `_ and `#114 `_). -* Added `changelog `_ +* Added `changelog `_ (`#103 `_). 1.0.0 - 2015-02-05 diff --git a/dep/cppformat/LICENSE b/dep/cppformat/LICENSE new file mode 100644 index 00000000000..2ee9ec93495 --- /dev/null +++ b/dep/cppformat/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2014 - 2015, Victor Zverovich +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dep/cppformat/format.cc b/dep/cppformat/format.cc index 86b86c741b5..865b78cfab0 100644 --- a/dep/cppformat/format.cc +++ b/dep/cppformat/format.cc @@ -35,18 +35,11 @@ #include #include -#if defined(_WIN32) && defined(__MINGW32__) -# include -#endif - -#if FMT_USE_WINDOWS_H -# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) -# include -# else -# define NOMINMAX -# include -# undef NOMINMAX +#ifdef _WIN32 +# ifdef __MINGW32__ +# include # endif +# include #endif using fmt::internal::Arg; @@ -73,8 +66,10 @@ using fmt::internal::Arg; #ifndef FMT_THROW # if FMT_EXCEPTIONS # define FMT_THROW(x) throw x +# define FMT_RETURN_AFTER_THROW(x) # else # define FMT_THROW(x) assert(false) +# define FMT_RETURN_AFTER_THROW(x) return x # endif #endif @@ -88,21 +83,8 @@ using fmt::internal::Arg; # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4702) // unreachable code -// Disable deprecation warning for strerror. The latter is not called but -// MSVC fails to detect it. -# pragma warning(disable: 4996) #endif -// Dummy implementations of strerror_r and strerror_s called if corresponding -// system functions are not available. -static inline fmt::internal::None<> strerror_r(int, char *, ...) { - return fmt::internal::None<>(); -} -static inline fmt::internal::None<> strerror_s(char *, std::size_t, ...) { - return fmt::internal::None<>(); -} - -namespace fmt { namespace { #ifndef _MSC_VER @@ -158,61 +140,36 @@ typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef); // Buffer should be at least of size 1. int safe_strerror( int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { - FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); - - class StrError { - private: - int error_code_; - char *&buffer_; - std::size_t buffer_size_; - - // A noop assignment operator to avoid bogus warnings. - void operator=(const StrError &) {} - - // Handle the result of XSI-compliant version of strerror_r. - int handle(int result) { - // glibc versions before 2.13 return result in errno. - return result == -1 ? errno : result; - } - - // Handle the result of GNU-specific version of strerror_r. - int handle(char *message) { - // If the buffer is full then the message is probably truncated. - if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) - return ERANGE; - buffer_ = message; - return 0; - } - - // Handle the case when strerror_r is not available. - int handle(fmt::internal::None<>) { - return fallback(strerror_s(buffer_, buffer_size_, error_code_)); - } - - // Fallback to strerror_s when strerror_r is not available. - int fallback(int result) { - // If the buffer is full then the message is probably truncated. - return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? - ERANGE : result; - } - - // Fallback to strerror if strerror_r and strerror_s are not available. - int fallback(fmt::internal::None<>) { - errno = 0; - buffer_ = strerror(error_code_); - return errno; - } - - public: - StrError(int error_code, char *&buffer, std::size_t buffer_size) - : error_code_(error_code), buffer_(buffer), buffer_size_(buffer_size) {} - - int run() { - strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. - return handle(strerror_r(error_code_, buffer_, buffer_size_)); - } - }; - return StrError(error_code, buffer, buffer_size).run(); + assert(buffer != 0 && buffer_size != 0); + int result = 0; +#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__ + // XSI-compliant version of strerror_r. + result = strerror_r(error_code, buffer, buffer_size); + if (result != 0) + result = errno; +#elif _GNU_SOURCE + // GNU-specific version of strerror_r. + char *message = strerror_r(error_code, buffer, buffer_size); + // If the buffer is full then the message is probably truncated. + if (message == buffer && strlen(buffer) == buffer_size - 1) + result = ERANGE; + buffer = message; +#elif __MINGW32__ + errno = 0; + (void)buffer_size; + buffer = strerror(error_code); + result = errno; +#elif _WIN32 + result = strerror_s(buffer, buffer_size, error_code); + // If the buffer is full then the message is probably truncated. + if (result == 0 && std::strlen(buffer) == buffer_size - 1) + result = ERANGE; +#else + result = strerror_r(error_code, buffer, buffer_size); + if (result == -1) + result = errno; // glibc versions before 2.13 return result in errno. +#endif + return result; } void format_error_code(fmt::Writer &out, int error_code, @@ -222,14 +179,14 @@ void format_error_code(fmt::Writer &out, int error_code, // bad_alloc. out.clear(); static const char SEP[] = ": "; - static const char ERROR_STR[] = "error "; + static const char ERR[] = "error "; fmt::internal::IntTraits::MainType ec_value = error_code; - // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. - std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - error_code_size += fmt::internal::count_digits(ec_value); + // Subtract 2 to account for terminating null characters in SEP and ERR. + std::size_t error_code_size = + sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2; if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) out << message << SEP; - out << ERROR_STR << error_code; + out << ERR << error_code; assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); } @@ -270,11 +227,6 @@ int parse_nonnegative_int(const Char *&s) { return value; } -template -inline bool is_name_start(Char c) { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; -} - inline void require_numeric_argument(const Arg &arg, char spec) { if (arg.type > Arg::LAST_NUMERIC_TYPE) { std::string message = @@ -305,8 +257,9 @@ class WidthHandler : public fmt::internal::ArgVisitor { public: explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} - void report_unhandled_arg() { + unsigned visit_unhandled_arg() { FMT_THROW(fmt::FormatError("width is not integer")); + FMT_RETURN_AFTER_THROW(0); } template @@ -326,8 +279,9 @@ class WidthHandler : public fmt::internal::ArgVisitor { class PrecisionHandler : public fmt::internal::ArgVisitor { public: - void report_unhandled_arg() { + unsigned visit_unhandled_arg() { FMT_THROW(fmt::FormatError("precision is not integer")); + FMT_RETURN_AFTER_THROW(0); } template @@ -395,139 +349,24 @@ class CharConverter : public fmt::internal::ArgVisitor { arg_.int_value = static_cast(value); } }; + +// This function template is used to prevent compile errors when handling +// incompatible string arguments, e.g. handling a wide string in a narrow +// string formatter. +template +Arg::StringValue ignore_incompatible_str(Arg::StringValue); + +template <> +inline Arg::StringValue ignore_incompatible_str( + Arg::StringValue) { return Arg::StringValue(); } + +template <> +inline Arg::StringValue ignore_incompatible_str( + Arg::StringValue s) { return s; } } // namespace -namespace internal { - -template -class BasicArgFormatter : public ArgVisitor { - private: - BasicWriter &writer_; - FormatSpec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter); - - protected: - BasicWriter &writer() { return writer_; } - const FormatSpec &spec() const { return spec_; } - - public: - BasicArgFormatter(BasicWriter &w, FormatSpec &s) - : writer_(w), spec_(s) {} - - template - void visit_any_int(T value) { writer_.write_int(value, spec_); } - - template - void visit_any_double(T value) { writer_.write_double(value, spec_); } - - void visit_bool(bool value) { - if (spec_.type_) { - writer_.write_int(value, spec_); - return; - } - const char *str_value = value ? "true" : "false"; - Arg::StringValue str = { str_value, strlen(str_value) }; - writer_.write_str(str, spec_); - } - - void visit_char(int value) { - if (spec_.type_ && spec_.type_ != 'c') { - spec_.flags_ |= CHAR_FLAG; - writer_.write_int(value, spec_); - return; - } - if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) - FMT_THROW(FormatError("invalid format specifier for char")); - typedef typename BasicWriter::CharPtr CharPtr; - Char fill = internal::CharTraits::cast(spec_.fill()); - CharPtr out = CharPtr(); - if (spec_.width_ > 1) { - out = writer_.grow_buffer(spec_.width_); - if (spec_.align_ == ALIGN_RIGHT) { - std::fill_n(out, spec_.width_ - 1, fill); - out += spec_.width_ - 1; - } else if (spec_.align_ == ALIGN_CENTER) { - out = writer_.fill_padding(out, spec_.width_, 1, fill); - } else { - std::fill_n(out + 1, spec_.width_ - 1, fill); - } - } else { - out = writer_.grow_buffer(1); - } - *out = internal::CharTraits::cast(value); - } - - void visit_string(Arg::StringValue value) { - writer_.write_str(value, spec_); - } - - using ArgVisitor::visit_wstring; - - void visit_wstring(Arg::StringValue value) { - writer_.write_str(value, spec_); - } - - void visit_pointer(const void *value) { - if (spec_.type_ && spec_.type_ != 'p') - report_unknown_type(spec_.type_, "pointer"); - spec_.flags_ = HASH_FLAG; - spec_.type_ = 'x'; - writer_.write_int(reinterpret_cast(value), spec_); - } -}; - -// An argument formatter. -template -class ArgFormatter : public BasicArgFormatter, Char> { - private: - BasicFormatter &formatter_; - const Char *format_; - - public: - ArgFormatter(BasicFormatter &f, FormatSpec &s, const Char *fmt) - : BasicArgFormatter, Char>(f.writer(), s), - formatter_(f), format_(fmt) {} - - void visit_custom(Arg::CustomValue c) { - c.format(&formatter_, c.value, &format_); - } -}; - -template -class PrintfArgFormatter : - public BasicArgFormatter, Char> { - public: - PrintfArgFormatter(BasicWriter &w, FormatSpec &s) - : BasicArgFormatter, Char>(w, s) {} - - void visit_char(int value) { - const FormatSpec &spec = this->spec(); - BasicWriter &writer = this->writer(); - if (spec.type_ && spec.type_ != 'c') - writer.write_int(value, spec); - typedef typename BasicWriter::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (spec.width_ > 1) { - Char fill = ' '; - out = writer.grow_buffer(spec.width_); - if (spec.align_ != ALIGN_LEFT) { - std::fill_n(out, spec.width_ - 1, fill); - out += spec.width_ - 1; - } else { - std::fill_n(out + 1, spec.width_ - 1, fill); - } - } else { - out = writer.grow_buffer(1); - } - *out = static_cast(value); - } -}; -} // namespace internal -} // namespace fmt - FMT_FUNC void fmt::SystemError::init( - int err_code, CStringRef format_str, ArgList args) { + int err_code, StringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; internal::format_system_error(w, err_code, format(format_str, args)); @@ -598,7 +437,6 @@ const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { }; FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { - (void)type; if (std::isprint(static_cast(code))) { FMT_THROW(fmt::FormatError( fmt::format("unknown format code '{}' for {}", code, type))); @@ -608,20 +446,19 @@ FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { static_cast(code), type))); } -#if FMT_USE_WINDOWS_H +#ifdef _WIN32 FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { int length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), 0, 0); + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_.resize(length + 1); + buffer_.resize(length); length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), &buffer_[0], length); + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_[length] = 0; } FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { @@ -632,20 +469,19 @@ FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { } FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { - int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), 0, 0, 0, 0); + int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); if (length == 0) return GetLastError(); - buffer_.resize(length + 1); + buffer_.resize(length); length = WideCharToMultiByte( - CP_UTF8, 0, s.data(), s.size(), &buffer_[0], length, 0, 0); + CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0); if (length == 0) return GetLastError(); - buffer_[length] = 0; return 0; } FMT_FUNC void fmt::WindowsError::init( - int err_code, CStringRef format_str, ArgList args) { + int err_code, StringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; internal::format_windows_error(w, err_code, format(format_str, args)); @@ -653,6 +489,30 @@ FMT_FUNC void fmt::WindowsError::init( base = std::runtime_error(w.str()); } +#endif + +FMT_FUNC void fmt::internal::format_system_error( + fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT { + FMT_TRY { + MemoryBuffer buffer; + buffer.resize(INLINE_BUFFER_SIZE); + for (;;) { + char *system_message = &buffer[0]; + int result = safe_strerror(error_code, system_message, buffer.size()); + if (result == 0) { + out << message << ": " << system_message; + return; + } + if (result != ERANGE) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +#ifdef _WIN32 FMT_FUNC void fmt::internal::format_windows_error( fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT { @@ -681,74 +541,81 @@ FMT_FUNC void fmt::internal::format_windows_error( } FMT_CATCH(...) {} format_error_code(out, error_code, message); } +#endif -#endif // FMT_USE_WINDOWS_H - -FMT_FUNC void fmt::internal::format_system_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { - FMT_TRY { - MemoryBuffer buffer; - buffer.resize(INLINE_BUFFER_SIZE); - for (;;) { - char *system_message = &buffer[0]; - int result = safe_strerror(error_code, system_message, buffer.size()); - if (result == 0) { - out << message << ": " << system_message; - return; - } - if (result != ERANGE) - break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } FMT_CATCH(...) {} - format_error_code(out, error_code, message); -} - +// An argument formatter. template -void fmt::internal::ArgMap::init(const ArgList &args) { - if (!map_.empty()) - return; - typedef internal::NamedArg NamedArg; - const NamedArg *named_arg = 0; - bool use_values = - args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; - if (use_values) { - for (unsigned i = 0;/*nothing*/; ++i) { - internal::Arg::Type arg_type = args.type(i); - switch (arg_type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.values_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; - } - } - return; - } - for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { - internal::Arg::Type arg_type = args.type(i); - if (arg_type == internal::Arg::NAMED_ARG) { - named_arg = static_cast(args.args_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); - } - } - for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { - switch (args.args_[i].type) { - case internal::Arg::NONE: +class fmt::internal::ArgFormatter : + public fmt::internal::ArgVisitor, void> { + private: + fmt::BasicFormatter &formatter_; + fmt::BasicWriter &writer_; + fmt::FormatSpec &spec_; + const Char *format_; + + FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter); + + public: + ArgFormatter( + fmt::BasicFormatter &f,fmt::FormatSpec &s, const Char *fmt) + : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {} + + template + void visit_any_int(T value) { writer_.write_int(value, spec_); } + + template + void visit_any_double(T value) { writer_.write_double(value, spec_); } + + void visit_char(int value) { + if (spec_.type_ && spec_.type_ != 'c') { + spec_.flags_ |= CHAR_FLAG; + writer_.write_int(value, spec_); return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.args_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; } + if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) + FMT_THROW(FormatError("invalid format specifier for char")); + typedef typename fmt::BasicWriter::CharPtr CharPtr; + Char fill = static_cast(spec_.fill()); + if (spec_.precision_ == 0) { + std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill); + return; + } + CharPtr out = CharPtr(); + if (spec_.width_ > 1) { + out = writer_.grow_buffer(spec_.width_); + if (spec_.align_ == fmt::ALIGN_RIGHT) { + std::fill_n(out, spec_.width_ - 1, fill); + out += spec_.width_ - 1; + } else if (spec_.align_ == fmt::ALIGN_CENTER) { + out = writer_.fill_padding(out, spec_.width_, 1, fill); + } else { + std::fill_n(out + 1, spec_.width_ - 1, fill); + } + } else { + out = writer_.grow_buffer(1); + } + *out = static_cast(value); } -} + + void visit_string(Arg::StringValue value) { + writer_.write_str(value, spec_); + } + void visit_wstring(Arg::StringValue value) { + writer_.write_str(ignore_incompatible_str(value), spec_); + } + + void visit_pointer(const void *value) { + if (spec_.type_ && spec_.type_ != 'p') + fmt::internal::report_unknown_type(spec_.type_, "pointer"); + spec_.flags_ = fmt::HASH_FLAG; + spec_.type_ = 'x'; + writer_.write_int(reinterpret_cast(value), spec_); + } + + void visit_custom(Arg::CustomValue c) { + c.format(&formatter_, c.value, &format_); + } +}; template void fmt::internal::FixedBuffer::grow(std::size_t) { @@ -777,19 +644,6 @@ void fmt::BasicWriter::write_str( write_str(str_value, str_size, spec); } -template -inline Arg fmt::BasicFormatter::get_arg( - BasicStringRef arg_name, const char *&error) { - if (check_no_auto_index(error)) { - map_.init(args()); - const Arg *arg = map_.find(arg_name); - if (arg) - return *arg; - error = "argument not found"; - } - return Arg(); -} - template inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { const char *error = 0; @@ -802,33 +656,11 @@ inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { return arg; } -template -inline Arg fmt::BasicFormatter::parse_arg_name(const Char *&s) { - assert(is_name_start(*s)); - const Char *start = s; - Char c; - do { - c = *++s; - } while (is_name_start(c) || ('0' <= c && c <= '9')); - const char *error = 0; - Arg arg = get_arg(fmt::BasicStringRef(start, s - start), error); - if (error) - FMT_THROW(fmt::FormatError(error)); - return arg; -} - FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( unsigned arg_index, const char *&error) { Arg arg = args_[arg_index]; - switch (arg.type) { - case Arg::NONE: + if (arg.type == Arg::NONE) error = "argument index out of range"; - break; - case Arg::NAMED_ARG: - arg = *static_cast(arg.pointer); - default: - /*nothing*/; - } return arg; } @@ -839,19 +671,14 @@ inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) { return Arg(); } -inline bool fmt::internal::FormatterBase::check_no_auto_index( - const char *&error) { - if (next_arg_index_ > 0) { - error = "cannot switch from automatic to manual argument indexing"; - return false; - } - next_arg_index_ = -1; - return true; -} - inline Arg fmt::internal::FormatterBase::get_arg( unsigned arg_index, const char *&error) { - return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); + if (next_arg_index_ <= 0) { + next_arg_index_ = -1; + return do_get_arg(arg_index, error); + } + error = "cannot switch from automatic to manual argument indexing"; + return Arg(); } template @@ -884,7 +711,6 @@ void fmt::internal::PrintfFormatter::parse_flags( template Arg fmt::internal::PrintfFormatter::get_arg( const Char *s, unsigned arg_index) { - (void)s; const char *error = 0; Arg arg = arg_index == UINT_MAX ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); @@ -929,7 +755,7 @@ unsigned fmt::internal::PrintfFormatter::parse_header( template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicCStringRef format_str, + BasicWriter &writer, BasicStringRef format_str, const ArgList &args) { const Char *start = format_str.c_str(); set_args(args); @@ -1023,7 +849,73 @@ void fmt::internal::PrintfFormatter::format( start = s; // Format argument. - internal::PrintfArgFormatter(writer, spec).visit(arg); + switch (arg.type) { + case Arg::INT: + writer.write_int(arg.int_value, spec); + break; + case Arg::UINT: + writer.write_int(arg.uint_value, spec); + break; + case Arg::LONG_LONG: + writer.write_int(arg.long_long_value, spec); + break; + case Arg::ULONG_LONG: + writer.write_int(arg.ulong_long_value, spec); + break; + case Arg::CHAR: { + if (spec.type_ && spec.type_ != 'c') + writer.write_int(arg.int_value, spec); + typedef typename BasicWriter::CharPtr CharPtr; + CharPtr out = CharPtr(); + if (spec.width_ > 1) { + Char fill = ' '; + out = writer.grow_buffer(spec.width_); + if (spec.align_ != ALIGN_LEFT) { + std::fill_n(out, spec.width_ - 1, fill); + out += spec.width_ - 1; + } else { + std::fill_n(out + 1, spec.width_ - 1, fill); + } + } else { + out = writer.grow_buffer(1); + } + *out = static_cast(arg.int_value); + break; + } + case Arg::DOUBLE: + writer.write_double(arg.double_value, spec); + break; + case Arg::LONG_DOUBLE: + writer.write_double(arg.long_double_value, spec); + break; + case Arg::CSTRING: + arg.string.size = 0; + writer.write_str(arg.string, spec); + break; + case Arg::STRING: + writer.write_str(arg.string, spec); + break; + case Arg::WSTRING: + writer.write_str(ignore_incompatible_str(arg.wstring), spec); + break; + case Arg::POINTER: + if (spec.type_ && spec.type_ != 'p') + internal::report_unknown_type(spec.type_, "pointer"); + spec.flags_= HASH_FLAG; + spec.type_ = 'x'; + writer.write_int(reinterpret_cast(arg.pointer), spec); + break; + case Arg::CUSTOM: { + if (spec.type_) + internal::report_unknown_type(spec.type_, "object"); + const void *str_format = "s"; + arg.custom.format(&writer, arg.custom.value, &str_format); + break; + } + default: + assert(false); + break; + } } write(writer, start, s); } @@ -1095,47 +987,16 @@ const Char *fmt::BasicFormatter::format( ++s; } - // Parse zero flag. - if (*s == '0') { - require_numeric_argument(arg, '0'); - spec.align_ = ALIGN_NUMERIC; - spec.fill_ = '0'; - ++s; - } - - // Parse width. + // Parse width and zero flag. if ('0' <= *s && *s <= '9') { - spec.width_ = parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - Arg width_arg = is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); - if (*s++ != '}') - FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (width_arg.type) { - case Arg::INT: - if (width_arg.int_value < 0) - FMT_THROW(FormatError("negative width")); - value = width_arg.int_value; - break; - case Arg::UINT: - value = width_arg.uint_value; - break; - case Arg::LONG_LONG: - if (width_arg.long_long_value < 0) - FMT_THROW(FormatError("negative width")); - value = width_arg.long_long_value; - break; - case Arg::ULONG_LONG: - value = width_arg.ulong_long_value; - break; - default: - FMT_THROW(FormatError("width is not integer")); + if (*s == '0') { + require_numeric_argument(arg, '0'); + spec.align_ = ALIGN_NUMERIC; + spec.fill_ = '0'; } - if (value > INT_MAX) - FMT_THROW(FormatError("number is too big")); - spec.width_ = static_cast(value); + // Zero may be parsed again as a part of the width, but it is simpler + // and more efficient than checking if the next char is a digit. + spec.width_ = parse_nonnegative_int(s); } // Parse precision. @@ -1146,8 +1007,7 @@ const Char *fmt::BasicFormatter::format( spec.precision_ = parse_nonnegative_int(s); } else if (*s == '{') { ++s; - Arg precision_arg = - is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); + const Arg &precision_arg = parse_arg_index(s); if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); ULongLong value = 0; @@ -1177,7 +1037,7 @@ const Char *fmt::BasicFormatter::format( } else { FMT_THROW(FormatError("missing precision specifier")); } - if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { + if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { FMT_THROW(FormatError( fmt::format("precision not allowed in {} format specifier", arg.type == Arg::POINTER ? "pointer" : "integer"))); @@ -1200,7 +1060,7 @@ const Char *fmt::BasicFormatter::format( template void fmt::BasicFormatter::format( - BasicCStringRef format_str, const ArgList &args) { + BasicStringRef format_str, const ArgList &args) { const Char *s = start_ = format_str.c_str(); set_args(args); while (*s) { @@ -1214,7 +1074,7 @@ void fmt::BasicFormatter::format( if (c == '}') FMT_THROW(FormatError("unmatched '}' in format string")); write(writer_, start_, s - 1); - Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); + Arg arg = parse_arg_index(s); s = format(s, arg); } write(writer_, start_, s); @@ -1225,30 +1085,30 @@ FMT_FUNC void fmt::report_system_error( report_error(internal::format_system_error, error_code, message); } -#if FMT_USE_WINDOWS_H +#ifdef _WIN32 FMT_FUNC void fmt::report_windows_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT { report_error(internal::format_windows_error, error_code, message); } #endif -FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) { +FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } -FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) { +FMT_FUNC void fmt::print(StringRef format_str, ArgList args) { print(stdout, format_str, args); } -FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) { +FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); os.write(w.data(), w.size()); } -FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { +FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) { char escape[] = "\x1b[30m"; escape[3] = '0' + static_cast(c); std::fputs(escape, stdout); @@ -1256,7 +1116,7 @@ FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { std::fputs(RESET_COLOR, stdout); } -FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { +FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) { MemoryWriter w; printf(w, format, args); std::size_t size = w.size(); @@ -1265,8 +1125,6 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { #ifndef FMT_HEADER_ONLY -template struct fmt::internal::BasicData; - // Explicit instantiations for char. template void fmt::internal::FixedBuffer::grow(std::size_t); @@ -1275,10 +1133,10 @@ template const char *fmt::BasicFormatter::format( const char *&format_str, const fmt::internal::Arg &arg); template void fmt::BasicFormatter::format( - CStringRef format, const ArgList &args); + BasicStringRef format, const ArgList &args); template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, CStringRef format, const ArgList &args); + BasicWriter &writer, BasicStringRef format, const ArgList &args); template int fmt::internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, @@ -1296,10 +1154,10 @@ template const wchar_t *fmt::BasicFormatter::format( const wchar_t *&format_str, const fmt::internal::Arg &arg); template void fmt::BasicFormatter::format( - BasicCStringRef format, const ArgList &args); + BasicStringRef format, const ArgList &args); template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, WCStringRef format, + BasicWriter &writer, BasicStringRef format, const ArgList &args); template int fmt::internal::CharTraits::format_float( diff --git a/dep/cppformat/format.h b/dep/cppformat/format.h index dfe95a77931..fb414ca3639 100644 --- a/dep/cppformat/format.h +++ b/dep/cppformat/format.h @@ -39,7 +39,6 @@ #include #include #include -#include #if _SECURE_SCL # include @@ -101,7 +100,6 @@ inline uint32_t clzll(uint64_t x) { #endif #ifdef __clang__ -# pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdocumentation" #endif @@ -153,34 +151,26 @@ inline uint32_t clzll(uint64_t x) { #endif // Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). -#ifndef FMT_NOEXCEPT -# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) -# define FMT_NOEXCEPT noexcept -# else -# define FMT_NOEXCEPT throw() -# endif +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) +# define FMT_NOEXCEPT noexcept +#else +# define FMT_NOEXCEPT throw() #endif // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 -# define FMT_DELETED_OR_UNDEFINED = delete # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ TypeName& operator=(const TypeName&) = delete #else -# define FMT_DELETED_OR_UNDEFINED # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ TypeName& operator=(const TypeName&) #endif -#ifndef FMT_ASSERT -# define FMT_ASSERT(condition, message) assert((condition) && message) -#endif - namespace fmt { // Fix the warning about long long on older versions of GCC @@ -206,7 +196,8 @@ void format(BasicFormatter &f, const Char *&format_str, const T &value); /** \rst - A string reference. It can be constructed from a C string or ``std::string``. + A string reference. It can be constructed from a C string or + ``std::string``. You can use one of the following typedefs for common character types: @@ -235,39 +226,39 @@ class BasicStringRef { std::size_t size_; public: - /** Constructs a string reference object from a C string and a size. */ + /** + Constructs a string reference object from a C string and a size. + */ BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} /** - \rst Constructs a string reference object from a C string computing the size with ``std::char_traits::length``. - \endrst */ BasicStringRef(const Char *s) : data_(s), size_(std::char_traits::length(s)) {} /** - \rst - Constructs a string reference from an ``std::string`` object. - \endrst + Constructs a string reference from an `std::string` object. */ BasicStringRef(const std::basic_string &s) : data_(s.c_str()), size_(s.size()) {} /** - \rst - Converts a string reference to an ``std::string`` object. - \endrst + Converts a string reference to an `std::string` object. */ - std::basic_string to_string() const { - return std::basic_string(data_, size_); + operator std::basic_string() const { + return std::basic_string(data_, size()); } - /** Returns the pointer to a C string. */ - const Char *data() const { return data_; } + /** + Returns the pointer to a C string. + */ + const Char *c_str() const { return data_; } - /** Returns the string size. */ + /** + Returns the string size. + */ std::size_t size() const { return size_; } friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { @@ -276,74 +267,22 @@ class BasicStringRef { friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.data_ != rhs.data_; } - friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { - return std::lexicographical_compare( - lhs.data_, lhs.data_ + lhs.size_, rhs.data_, rhs.data_ + rhs.size_); - } }; typedef BasicStringRef StringRef; typedef BasicStringRef WStringRef; - -/** - \rst - A reference to a null terminated string. It can be constructed from a C - string or ``std::string``. - - You can use one of the following typedefs for common character types: - - +-------------+--------------------------+ - | Type | Definition | - +=============+==========================+ - | CStringRef | BasicCStringRef | - +-------------+--------------------------+ - | WCStringRef | BasicCStringRef | - +-------------+--------------------------+ - - This class is most useful as a parameter type to allow passing - different types of strings to a function, for example:: - - template - std::string format(CStringRef format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ -template -class BasicCStringRef { - private: - const Char *data_; - - public: - /** Constructs a string reference object from a C string. */ - BasicCStringRef(const Char *s) : data_(s) {} - - /** - \rst - Constructs a string reference from an ``std::string`` object. - \endrst - */ - BasicCStringRef(const std::basic_string &s) : data_(s.c_str()) {} - - /** Returns the pointer to a C string. */ - const Char *c_str() const { return data_; } -}; - -typedef BasicCStringRef CStringRef; -typedef BasicCStringRef WCStringRef; - /** A formatting error such as invalid format string. */ class FormatError : public std::runtime_error { public: - explicit FormatError(CStringRef message) + explicit FormatError(StringRef message) : std::runtime_error(message.c_str()) {} }; namespace internal { + // The number of characters to store in the MemoryBuffer object itself // to avoid dynamic memory allocation. enum { INLINE_BUFFER_SIZE = 500 }; @@ -358,13 +297,8 @@ inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { template inline T *make_ptr(T *ptr, std::size_t) { return ptr; } #endif -} // namespace internal -/** - \rst - A buffer supporting a subset of ``std::vector``'s operations. - \endrst - */ +// A buffer for POD types. It supports a subset of std::vector's operations. template class Buffer { private: @@ -378,37 +312,25 @@ class Buffer { Buffer(T *ptr = 0, std::size_t capacity = 0) : ptr_(ptr), size_(0), capacity_(capacity) {} - /** - \rst - Increases the buffer capacity to hold at least *size* elements updating - ``ptr_`` and ``capacity_``. - \endrst - */ virtual void grow(std::size_t size) = 0; public: virtual ~Buffer() {} - /** Returns the size of this buffer. */ + // Returns the size of this buffer. std::size_t size() const { return size_; } - /** Returns the capacity of this buffer. */ + // Returns the capacity of this buffer. std::size_t capacity() const { return capacity_; } - /** - Resizes the buffer. If T is a POD type new elements may not be initialized. - */ + // Resizes the buffer. If T is a POD type new elements are not initialized. void resize(std::size_t new_size) { if (new_size > capacity_) grow(new_size); size_ = new_size; } - /** - \rst - Reserves space to store at least *capacity* elements. - \endrst - */ + // Reserves space to store at least capacity elements. void reserve(std::size_t capacity) { if (capacity > capacity_) grow(capacity); @@ -422,26 +344,22 @@ class Buffer { ptr_[size_++] = value; } - /** Appends data to the end of the buffer. */ - template - void append(const U *begin, const U *end); + // Appends data to the end of the buffer. + void append(const T *begin, const T *end); T &operator[](std::size_t index) { return ptr_[index]; } const T &operator[](std::size_t index) const { return ptr_[index]; } }; template -template -void Buffer::append(const U *begin, const U *end) { +void Buffer::append(const T *begin, const T *end) { std::ptrdiff_t num_elements = end - begin; if (size_ + num_elements > capacity_) grow(size_ + num_elements); - std::copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_); + std::copy(begin, end, make_ptr(ptr_, capacity_) + size_); size_ += num_elements; } -namespace internal { - // A memory buffer for POD types with the first SIZE elements stored in // the object itself. template > @@ -520,9 +438,10 @@ void MemoryBuffer::grow(std::size_t size) { // A fixed-size buffer. template -class FixedBuffer : public fmt::Buffer { +class FixedBuffer : public fmt::internal::Buffer { public: - FixedBuffer(Char *array, std::size_t size) : fmt::Buffer(array, size) {} + FixedBuffer(Char *array, std::size_t size) + : fmt::internal::Buffer(array, size) {} protected: void grow(std::size_t size); @@ -558,9 +477,7 @@ inline int getsign(double value) { return sign; } inline int isinfinity(double x) { return !_finite(x); } -inline int isinfinity(long double x) { - return !_finite(static_cast(x)); -} +inline int isinfinity(long double x) { return !_finite(static_cast(x)); } #endif template @@ -571,7 +488,6 @@ class BasicCharTraits { #else typedef Char *CharPtr; #endif - static Char cast(wchar_t value) { return static_cast(value); } }; template @@ -583,7 +499,7 @@ class CharTraits : public BasicCharTraits { // Conversion from wchar_t to char is not allowed. static char convert(wchar_t); - public: +public: static char convert(char value) { return value; } // Formats a floating-point number. @@ -732,15 +648,7 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { buffer[0] = Data::DIGITS[index]; } -#ifndef _WIN32 -# define FMT_USE_WINDOWS_H 0 -#elif !defined(FMT_USE_WINDOWS_H) -# define FMT_USE_WINDOWS_H 1 -#endif - -// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. -// All the functionality that relies on it will be disabled too. -#if FMT_USE_WINDOWS_H +#ifdef _WIN32 // A converter from UTF-8 to UTF-16. // It is only provided for Windows since other systems support UTF-8 natively. class UTF8ToUTF16 { @@ -774,15 +682,30 @@ class UTF16ToUTF8 { // in case of memory allocation error. int convert(WStringRef s); }; - -void format_windows_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; #endif void format_system_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; -// A formatting argument value. +#ifdef _WIN32 +void format_windows_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; +#endif + +// Computes max(Arg, 1) at compile time. It is used to avoid errors about +// allocating an array of 0 size. +template +struct NonZero { + enum { VALUE = Arg }; +}; + +template <> +struct NonZero<0> { + enum { VALUE = 1 }; +}; + +// The value of a formatting argument. It is a POD type to allow storage in +// internal::MemoryBuffer. struct Value { template struct StringValue { @@ -812,27 +735,21 @@ struct Value { StringValue wstring; CustomValue custom; }; +}; +struct Arg : Value { enum Type { - NONE, NAMED_ARG, + NONE, // Integer types should go first, - INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, + INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, // followed by floating-point types. DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, CSTRING, STRING, WSTRING, POINTER, CUSTOM }; -}; - -// A formatting argument. It is a POD type to allow storage in -// internal::MemoryBuffer. -struct Arg : Value { Type type; }; -template -struct NamedArg; - -template +template struct None {}; // A helper class template to enable or disable overloads taking wide @@ -856,45 +773,22 @@ class IsConvertibleToInt { typedef char no[2]; static const T &get(); - - static yes &check(fmt::ULongLong); + static yes &check(int); static no &check(...); - + public: enum { value = (sizeof(check(get())) == sizeof(yes)) }; }; -#define FMT_CONVERTIBLE_TO_INT(Type) \ - template <> \ - class IsConvertibleToInt { \ - public: \ - enum { value = 1 }; \ - } - -// Silence warnings about convering float to int. -FMT_CONVERTIBLE_TO_INT(float); -FMT_CONVERTIBLE_TO_INT(double); -FMT_CONVERTIBLE_TO_INT(long double); - template struct EnableIf {}; template struct EnableIf { typedef T type; }; -template -struct Conditional { typedef T type; }; - -template -struct Conditional { typedef F type; }; - -// A helper function to suppress bogus "conditional expression is constant" -// warnings. -inline bool check(bool value) { return value; } - -// Makes an Arg object from any type. +// Makes a Value object from any type. template -class MakeValue : public Arg { +class MakeValue : public Value { private: // The following two methods are private to disallow formatting of // arbitrary pointers. If you want to output a pointer cast it to @@ -917,12 +811,12 @@ class MakeValue : public Arg { MakeValue(typename WCharHelper::Unsupported); void set_string(StringRef str) { - string.value = str.data(); + string.value = str.c_str(); string.size = str.size(); } void set_string(WStringRef str) { - wstring.value = str.data(); + wstring.value = str.c_str(); wstring.size = str.size(); } @@ -938,14 +832,11 @@ class MakeValue : public Arg { public: MakeValue() {} -#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ - MakeValue(Type value) { field = rhs; } \ +#define FMT_MAKE_VALUE(Type, field, TYPE) \ + MakeValue(Type value) { field = value; } \ static uint64_t type(Type) { return Arg::TYPE; } -#define FMT_MAKE_VALUE(Type, field, TYPE) \ - FMT_MAKE_VALUE_(Type, field, TYPE, value) - - FMT_MAKE_VALUE(bool, int_value, BOOL) + FMT_MAKE_VALUE(bool, int_value, INT) FMT_MAKE_VALUE(short, int_value, INT) FMT_MAKE_VALUE(unsigned short, uint_value, UINT) FMT_MAKE_VALUE(int, int_value, INT) @@ -954,7 +845,7 @@ class MakeValue : public Arg { MakeValue(long value) { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. - if (check(sizeof(long) == sizeof(int))) + if (sizeof(long) == sizeof(int)) int_value = static_cast(value); else long_long_value = value; @@ -964,7 +855,7 @@ class MakeValue : public Arg { } MakeValue(unsigned long value) { - if (check(sizeof(unsigned long) == sizeof(unsigned))) + if (sizeof(unsigned long) == sizeof(unsigned)) uint_value = static_cast(value); else ulong_long_value = value; @@ -998,7 +889,6 @@ class MakeValue : public Arg { FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) FMT_MAKE_STR_VALUE(const std::string &, STRING) FMT_MAKE_STR_VALUE(StringRef, STRING) - FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ MakeValue(typename WCharHelper::Supported value) { \ @@ -1031,25 +921,6 @@ class MakeValue : public Arg { static uint64_t type(const T &) { return IsConvertibleToInt::value ? Arg::INT : Arg::CUSTOM; } - - // Additional template param `Char_` is needed here because make_type always - // uses MakeValue. - template - MakeValue(const NamedArg &value) { pointer = &value; } - - template - static uint64_t type(const NamedArg &) { return Arg::NAMED_ARG; } -}; - -template -struct NamedArg : Arg { - BasicStringRef name; - - template - NamedArg(BasicStringRef name, const T &value) - : name(name), Arg(MakeValue(value)) { - type = static_cast(MakeValue::type(value)); - } }; #define FMT_DISPATCH(call) static_cast(this)->call @@ -1077,12 +948,7 @@ struct NamedArg : Arg { template class ArgVisitor { public: - void report_unhandled_arg() {} - - Result visit_unhandled_arg() { - FMT_DISPATCH(report_unhandled_arg()); - return Result(); - } + Result visit_unhandled_arg() { return Result(); } Result visit_int(int value) { return FMT_DISPATCH(visit_any_int(value)); @@ -1096,9 +962,6 @@ class ArgVisitor { Result visit_ulong_long(ULongLong value) { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_bool(bool value) { - return FMT_DISPATCH(visit_any_int(value)); - } Result visit_char(int value) { return FMT_DISPATCH(visit_any_int(value)); } @@ -1134,7 +997,7 @@ class ArgVisitor { Result visit(const Arg &arg) { switch (arg.type) { default: - FMT_ASSERT(false, "invalid argument type"); + assert(false); return Result(); case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); @@ -1144,16 +1007,14 @@ class ArgVisitor { return FMT_DISPATCH(visit_long_long(arg.long_long_value)); case Arg::ULONG_LONG: return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); - case Arg::BOOL: - return FMT_DISPATCH(visit_bool(arg.int_value)); - case Arg::CHAR: - return FMT_DISPATCH(visit_char(arg.int_value)); case Arg::DOUBLE: return FMT_DISPATCH(visit_double(arg.double_value)); case Arg::LONG_DOUBLE: return FMT_DISPATCH(visit_long_double(arg.long_double_value)); + case Arg::CHAR: + return FMT_DISPATCH(visit_char(arg.int_value)); case Arg::CSTRING: { - Arg::StringValue str = arg.string; + Value::StringValue str = arg.string; str.size = 0; return FMT_DISPATCH(visit_string(str)); } @@ -1174,77 +1035,46 @@ class RuntimeError : public std::runtime_error { RuntimeError() : std::runtime_error("") {} }; -template -class BasicArgFormatter; - template -class PrintfArgFormatter; - -template -class ArgMap; +class ArgFormatter; } // namespace internal -/** An argument list. */ +/** + An argument list. + */ class ArgList { private: - // To reduce compiled code size per formatting function call, types of first - // MAX_PACKED_ARGS arguments are passed in the types_ field. uint64_t types_; - union { - // If the number of arguments is less than MAX_PACKED_ARGS, the argument - // values are stored in values_, otherwise they are stored in args_. - // This is done to reduce compiled code size as storing larger objects - // may require more code (at least on x86-64) even if the same amount of - // data is actually copied to stack. It saves ~10% on the bloat test. - const internal::Value *values_; - const internal::Arg *args_; - }; - - internal::Arg::Type type(unsigned index) const { - unsigned shift = index * 4; - uint64_t mask = 0xf; - return static_cast( - (types_ & (mask << shift)) >> shift); - } - - template - friend class internal::ArgMap; + const internal::Value *values_; public: - // Maximum number of arguments with packed types. - enum { MAX_PACKED_ARGS = 16 }; + // Maximum number of arguments that can be passed in ArgList. + enum { MAX_ARGS = 16 }; ArgList() : types_(0) {} - ArgList(ULongLong types, const internal::Value *values) : types_(types), values_(values) {} - ArgList(ULongLong types, const internal::Arg *args) - : types_(types), args_(args) {} - /** Returns the argument at specified index. */ + /** + Returns the argument at specified index. + */ internal::Arg operator[](unsigned index) const { using internal::Arg; Arg arg; - bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; - if (index < MAX_PACKED_ARGS) { - Arg::Type arg_type = type(index); - internal::Value &val = arg; - if (arg_type != Arg::NONE) - val = use_values ? values_[index] : args_[index]; - arg.type = arg_type; - return arg; - } - if (use_values) { - // The index is greater than the number of arguments that can be stored - // in values, so return a "none" argument. + if (index >= MAX_ARGS) { arg.type = Arg::NONE; return arg; } - for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type == Arg::NONE) - return args_[i]; + unsigned shift = index * 4; + uint64_t mask = 0xf; + Arg::Type type = + static_cast((types_ & (mask << shift)) >> shift); + arg.type = type; + if (type != Arg::NONE) { + internal::Value &value = arg; + value = values_[index]; } - return args_[index]; + return arg; } }; @@ -1252,23 +1082,6 @@ struct FormatSpec; namespace internal { -template -class ArgMap { - private: - typedef std::map, internal::Arg> MapType; - typedef typename MapType::value_type Pair; - - MapType map_; - - public: - void init(const ArgList &args); - - const internal::Arg* find(const fmt::BasicStringRef &name) const { - typename MapType::const_iterator it = map_.find(name); - return it != map_.end() ? &it->second : 0; - } -}; - class FormatterBase { private: ArgList args_; @@ -1278,8 +1091,6 @@ class FormatterBase { Arg do_get_arg(unsigned arg_index, const char *&error); protected: - const ArgList &args() const { return args_; } - void set_args(const ArgList &args) { args_ = args; next_arg_index_ = 0; @@ -1292,8 +1103,6 @@ class FormatterBase { // specified index. Arg get_arg(unsigned arg_index, const char *&error); - bool check_no_auto_index(const char *&error); - template void write(BasicWriter &w, const Char *start, const Char *end) { if (start != end) @@ -1317,7 +1126,7 @@ class PrintfFormatter : private FormatterBase { public: void format(BasicWriter &writer, - BasicCStringRef format_str, const ArgList &args); + BasicStringRef format_str, const ArgList &args); }; } // namespace internal @@ -1327,28 +1136,18 @@ class BasicFormatter : private internal::FormatterBase { private: BasicWriter &writer_; const Char *start_; - internal::ArgMap map_; FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); - using FormatterBase::get_arg; - - // Checks if manual indexing is used and returns the argument with - // specified name. - internal::Arg get_arg(BasicStringRef arg_name, const char *&error); - // Parses argument index and returns corresponding argument. internal::Arg parse_arg_index(const Char *&s); - // Parses argument name and returns corresponding argument. - internal::Arg parse_arg_name(const Char *&s); - public: explicit BasicFormatter(BasicWriter &w) : writer_(w) {} BasicWriter &writer() { return writer_; } - void format(BasicCStringRef format_str, const ArgList &args); + void format(BasicStringRef format_str, const ArgList &args); const Char *format(const Char *&format_str, const internal::Arg &arg); }; @@ -1440,19 +1239,16 @@ class IntFormatSpec : public SpecT { }; // A string format specifier. -template +template class StrFormatSpec : public AlignSpec { private: - const Char *str_; + const T *str_; public: - template - StrFormatSpec(const Char *str, unsigned width, FillChar fill) - : AlignSpec(width, fill), str_(str) { - internal::CharTraits::convert(FillChar()); - } + StrFormatSpec(const T *str, unsigned width, wchar_t fill) + : AlignSpec(width, fill), str_(str) {} - const Char *str() const { return str_; } + const T *str() const { return str_; } }; /** @@ -1599,64 +1395,11 @@ inline uint64_t make_type() { return 0; } template inline uint64_t make_type(const T &arg) { return MakeValue::type(arg); } -template -struct ArgArray { - // Computes the argument array size by adding 1 to N, which is the number of - // arguments, if N is zero, because array of zero size is invalid, or if N - // is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra - // argument that marks the end of the list. - enum { SIZE = N + (N == 0 || N >= ArgList::MAX_PACKED_ARGS ? 1 : 0) }; - - typedef typename Conditional< - (N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE]; -}; - #if FMT_USE_VARIADIC_TEMPLATES template inline uint64_t make_type(const Arg &first, const Args & ... tail) { return make_type(first) | (make_type(tail...) << 4); } - -inline void do_set_types(Arg *) {} - -template -inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) { - args->type = static_cast(MakeValue::type(arg)); - do_set_types(args + 1, tail...); -} - -template -inline void set_types(Arg *array, const Args & ... args) { - if (check(sizeof...(Args) > ArgList::MAX_PACKED_ARGS)) - do_set_types(array, args...); - array[sizeof...(Args)].type = Arg::NONE; -} - -template -inline void set_types(Value *, const Args & ...) { - // Do nothing as types are passed separately from values. -} - -template -inline void store_args(Value *) {} - -template -inline void store_args(Arg *args, const T &arg, const Args & ... tail) { - // Assign only the Value subobject of Arg and don't overwrite type (if any) - // that is assigned by set_types. - Value &value = *args; - value = MakeValue(arg); - store_args(args + 1, tail...); -} - -template -ArgList make_arg_list(typename ArgArray::Type array, - const Args & ... args) { - if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS)) - set_types(array, args...); - store_args(array, args...); - return ArgList(make_type(args...), array); -} #else struct ArgType { @@ -1689,17 +1432,24 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { // Defines a variadic function returning void. # define FMT_VARIADIC_VOID(func, arg_type) \ template \ - void func(arg_type arg0, const Args & ... args) { \ - typename fmt::internal::ArgArray::Type array; \ - func(arg0, fmt::internal::make_arg_list(array, args...)); \ + void func(arg_type arg1, const Args & ... args) { \ + const fmt::internal::Value values[ \ + fmt::internal::NonZero::VALUE] = { \ + fmt::internal::MakeValue(args)... \ + }; \ + func(arg1, ArgList(fmt::internal::make_type(args...), values)); \ } // Defines a variadic constructor. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ template \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - typename fmt::internal::ArgArray::Type array; \ - func(arg0, arg1, fmt::internal::make_arg_list(array, args...)); \ + using fmt::internal::MakeValue; \ + const fmt::internal::Value values[ \ + fmt::internal::NonZero::VALUE] = { \ + MakeValue(args)... \ + }; \ + func(arg0, arg1, ArgList(fmt::internal::make_type(args...), values)); \ } #else @@ -1712,9 +1462,9 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { # define FMT_WRAP1(func, arg_type, n) \ template \ inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ + const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ func(arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ } // Emulates a variadic function returning void on a pre-C++11 compiler. @@ -1729,9 +1479,9 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { # define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ template \ ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ + const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ func(arg0, arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ } // Emulates a variadic constructor on a pre-C++11 compiler. @@ -1776,7 +1526,7 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { */ class SystemError : public internal::RuntimeError { private: - void init(int err_code, CStringRef format_str, ArgList args); + void init(int err_code, StringRef format_str, ArgList args); protected: int error_code_; @@ -1811,10 +1561,10 @@ class SystemError : public internal::RuntimeError { throw fmt::SystemError(errno, "cannot open file '{}'", filename); \endrst */ - SystemError(int error_code, CStringRef message) { + SystemError(int error_code, StringRef message) { init(error_code, message, ArgList()); } - FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) + FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) int error_code() const { return error_code_; } }; @@ -1841,7 +1591,7 @@ template class BasicWriter { private: // Output buffer. - Buffer &buffer_; + internal::Buffer &buffer_; FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); @@ -1914,22 +1664,18 @@ class BasicWriter { template void append_float_length(Char *&, T) {} - template - friend class internal::BasicArgFormatter; - - friend class internal::PrintfArgFormatter; + friend class internal::ArgFormatter; + friend class internal::PrintfFormatter; protected: /** Constructs a ``BasicWriter`` object. */ - explicit BasicWriter(Buffer &b) : buffer_(b) {} + explicit BasicWriter(internal::Buffer &b) : buffer_(b) {} public: /** - \rst Destroys a ``BasicWriter`` object. - \endrst */ virtual ~BasicWriter() {} @@ -1956,9 +1702,7 @@ class BasicWriter { } /** - \rst Returns the content of the output buffer as an `std::string`. - \endrst */ std::basic_string str() const { return std::basic_string(&buffer_[0], buffer_.size()); @@ -1989,10 +1733,10 @@ class BasicWriter { See also :ref:`syntax`. \endrst */ - void write(BasicCStringRef format, ArgList args) { + void write(BasicStringRef format, ArgList args) { BasicFormatter(*this).format(format, args); } - FMT_VARIADIC_VOID(write, BasicCStringRef) + FMT_VARIADIC_VOID(write, BasicStringRef) BasicWriter &operator<<(int value) { return *this << IntFormatSpec(value); @@ -2011,9 +1755,7 @@ class BasicWriter { } /** - \rst Formats *value* and writes it to the stream. - \endrst */ BasicWriter &operator<<(ULongLong value) { return *this << IntFormatSpec(value); @@ -2025,10 +1767,8 @@ class BasicWriter { } /** - \rst Formats *value* using the general format for floating-point numbers (``'g'``) and writes it to the stream. - \endrst */ BasicWriter &operator<<(long double value) { write_double(value, FormatSpec()); @@ -2050,19 +1790,10 @@ class BasicWriter { } /** - \rst Writes *value* to the stream. - \endrst */ BasicWriter &operator<<(fmt::BasicStringRef value) { - const Char *str = value.data(); - buffer_.append(str, str + value.size()); - return *this; - } - - BasicWriter &operator<<( - typename internal::WCharHelper::Supported value) { - const char *str = value.data(); + const Char *str = value.c_str(); buffer_.append(str, str + value.size()); return *this; } @@ -2077,6 +1808,7 @@ class BasicWriter { template BasicWriter &operator<<(const StrFormatSpec &spec) { const StrChar *s = spec.str(); + // TODO: error if fill is not convertible to Char write_str(s, std::char_traits::length(s), spec); return *this; } @@ -2091,7 +1823,7 @@ typename BasicWriter::CharPtr BasicWriter::write_str( CharPtr out = CharPtr(); if (spec.width() > size) { out = grow_buffer(spec.width()); - Char fill = internal::CharTraits::cast(spec.fill()); + Char fill = static_cast(spec.fill()); if (spec.align() == ALIGN_RIGHT) { std::fill_n(out, spec.width() - size, fill); out += spec.width() - size; @@ -2114,7 +1846,7 @@ typename BasicWriter::CharPtr std::size_t content_size, wchar_t fill) { std::size_t padding = total_size - content_size; std::size_t left_padding = padding / 2; - Char fill_char = internal::CharTraits::cast(fill); + Char fill_char = static_cast(fill); std::fill_n(buffer, left_padding, fill_char); buffer += left_padding; CharPtr content = buffer; @@ -2130,7 +1862,7 @@ typename BasicWriter::CharPtr const char *prefix, unsigned prefix_size) { unsigned width = spec.width(); Alignment align = spec.align(); - Char fill = internal::CharTraits::cast(spec.fill()); + Char fill = static_cast(spec.fill()); if (spec.precision() > static_cast(num_digits)) { // Octal prefix '0' is counted as a digit, so ignore it if precision // is specified. @@ -2369,7 +2101,7 @@ void BasicWriter::write_double( *format_ptr = '\0'; // Format using snprintf. - Char fill = internal::CharTraits::cast(spec.fill()); + Char fill = static_cast(spec.fill()); for (;;) { std::size_t buffer_size = buffer_.capacity() - offset; #if _MSC_VER @@ -2522,7 +2254,8 @@ class BasicArrayWriter : public BasicWriter { BasicArrayWriter(Char *array, std::size_t size) : BasicWriter(buffer_), buffer_(array, size) {} - /** + // FIXME: this is temporary undocumented due to a bug in Sphinx + /* \rst Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the size known at compile time. @@ -2541,8 +2274,10 @@ template void format(BasicFormatter &f, const Char *&format_str, const T &value) { std::basic_ostringstream os; os << value; + internal::Arg arg; + internal::Value &arg_value = arg; std::basic_string str = os.str(); - internal::Arg arg = internal::MakeValue(str); + arg_value = internal::MakeValue(str); arg.type = static_cast( internal::MakeValue::type(str)); format_str = f.format(format_str, arg); @@ -2552,12 +2287,12 @@ void format(BasicFormatter &f, const Char *&format_str, const T &value) { // Can be used to report errors from destructors. void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; -#if FMT_USE_WINDOWS_H +#ifdef _WIN32 /** A Windows error. */ class WindowsError : public SystemError { private: - void init(int error_code, CStringRef format_str, ArgList args); + void init(int error_code, StringRef format_str, ArgList args); public: /** @@ -2588,10 +2323,10 @@ class WindowsError : public SystemError { } \endrst */ - WindowsError(int error_code, CStringRef message) { + WindowsError(int error_code, StringRef message) { init(error_code, message, ArgList()); } - FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) + FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) }; // Reports a Windows error without throwing an exception. @@ -2608,7 +2343,7 @@ enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; Example: PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23; */ -void print_colored(Color c, CStringRef format, ArgList args); +void print_colored(Color c, StringRef format, ArgList args); /** \rst @@ -2619,13 +2354,13 @@ void print_colored(Color c, CStringRef format, ArgList args); std::string message = format("The answer is {}", 42); \endrst */ -inline std::string format(CStringRef format_str, ArgList args) { +inline std::string format(StringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); return w.str(); } -inline std::wstring format(WCStringRef format_str, ArgList args) { +inline std::wstring format(WStringRef format_str, ArgList args) { WMemoryWriter w; w.write(format_str, args); return w.str(); @@ -2640,7 +2375,7 @@ inline std::wstring format(WCStringRef format_str, ArgList args) { print(stderr, "Don't {}!", "panic"); \endrst */ -void print(std::FILE *f, CStringRef format_str, ArgList args); +void print(std::FILE *f, StringRef format_str, ArgList args); /** \rst @@ -2651,7 +2386,7 @@ void print(std::FILE *f, CStringRef format_str, ArgList args); print("Elapsed time: {0:.2f} seconds", 1.23); \endrst */ -void print(CStringRef format_str, ArgList args); +void print(StringRef format_str, ArgList args); /** \rst @@ -2662,10 +2397,10 @@ void print(CStringRef format_str, ArgList args); print(cerr, "Don't {}!", "panic"); \endrst */ -void print(std::ostream &os, CStringRef format_str, ArgList args); +void print(std::ostream &os, StringRef format_str, ArgList args); template -void printf(BasicWriter &w, BasicCStringRef format, ArgList args) { +void printf(BasicWriter &w, BasicStringRef format, ArgList args) { internal::PrintfFormatter().format(w, format, args); } @@ -2678,7 +2413,7 @@ void printf(BasicWriter &w, BasicCStringRef format, ArgList args) { std::string message = fmt::sprintf("The answer is %d", 42); \endrst */ -inline std::string sprintf(CStringRef format, ArgList args) { +inline std::string sprintf(StringRef format, ArgList args) { MemoryWriter w; printf(w, format, args); return w.str(); @@ -2693,7 +2428,7 @@ inline std::string sprintf(CStringRef format, ArgList args) { fmt::fprintf(stderr, "Don't %s!", "panic"); \endrst */ -int fprintf(std::FILE *f, CStringRef format, ArgList args); +int fprintf(std::FILE *f, StringRef format, ArgList args); /** \rst @@ -2704,7 +2439,7 @@ int fprintf(std::FILE *f, CStringRef format, ArgList args); fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ -inline int printf(CStringRef format, ArgList args) { +inline int printf(StringRef format, ArgList args) { return fprintf(stdout, format, args); } @@ -2780,9 +2515,7 @@ class FormatInt { } /** - \rst - Returns the content of the output buffer as an ``std::string``. - \endrst + Returns the content of the output buffer as an `std::string`. */ std::string str() const { return std::string(str_, size()); } }; @@ -2811,33 +2544,6 @@ inline void format_decimal(char *&buffer, T value) { internal::format_decimal(buffer, abs_value, num_digits); buffer += num_digits; } - -/** - \rst - Returns a named argument for formatting functions. - - **Example**:: - - print("Elapsed time: {s:.2f} seconds", arg("s", 1.23)); - - \endrst - */ -template -inline internal::NamedArg arg(StringRef name, const T &arg) { - return internal::NamedArg(name, arg); -} - -template -inline internal::NamedArg arg(WStringRef name, const T &arg) { - return internal::NamedArg(name, arg); -} - -// The following two functions are deleted intentionally to disable -// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. -template -void arg(StringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; -template -void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; } #if FMT_GCC_VERSION @@ -2872,9 +2578,12 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; template \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ const Args & ... args) { \ - typename fmt::internal::ArgArray::Type array; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::internal::make_arg_list(array, args...)); \ + using fmt::internal::Value; \ + const Value values[fmt::internal::NonZero::VALUE] = { \ + fmt::internal::MakeValue(args)... \ + }; \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ + fmt::internal::make_type(args...), values)); \ } #else // Defines a wrapper for a function taking __VA_ARGS__ arguments @@ -2883,9 +2592,9 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; template \ inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ FMT_GEN(n, FMT_MAKE_ARG)) { \ - fmt::internal::ArgArray::Type arr = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ + const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ } # define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ @@ -2942,38 +2651,16 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; #define FMT_VARIADIC_W(ReturnType, func, ...) \ FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) -#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) - -#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id) - -/** - \rst - Convenient macro to capture the arguments' names and values into several - ``fmt::arg(name, value)``. - - **Example**:: - - int x = 1, y = 2; - print("point: ({x}, {y})", FMT_CAPTURE(x, y)); - // same as: - // print("point: ({x}, {y})", arg("x", x), arg("y", y)); - - \endrst - */ -#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__) - -#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) - namespace fmt { -FMT_VARIADIC(std::string, format, CStringRef) -FMT_VARIADIC_W(std::wstring, format, WCStringRef) -FMT_VARIADIC(void, print, CStringRef) -FMT_VARIADIC(void, print, std::FILE *, CStringRef) -FMT_VARIADIC(void, print, std::ostream &, CStringRef) -FMT_VARIADIC(void, print_colored, Color, CStringRef) -FMT_VARIADIC(std::string, sprintf, CStringRef) -FMT_VARIADIC(int, printf, CStringRef) -FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) +FMT_VARIADIC(std::string, format, StringRef) +FMT_VARIADIC_W(std::wstring, format, WStringRef) +FMT_VARIADIC(void, print, StringRef) +FMT_VARIADIC(void, print, std::FILE *, StringRef) +FMT_VARIADIC(void, print, std::ostream &, StringRef) +FMT_VARIADIC(void, print_colored, Color, StringRef) +FMT_VARIADIC(std::string, sprintf, StringRef) +FMT_VARIADIC(int, printf, StringRef) +FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) } // Restore warnings. diff --git a/dep/cppformat/posix.cc b/dep/cppformat/posix.cc index d36871f43a3..4c086af6ab0 100644 --- a/dep/cppformat/posix.cc +++ b/dep/cppformat/posix.cc @@ -45,17 +45,16 @@ # define O_CREAT _O_CREAT # define O_TRUNC _O_TRUNC -# ifndef S_IRUSR -# define S_IRUSR _S_IREAD -# endif +#ifndef S_IRUSR +# define S_IRUSR _S_IREAD +#endif -# ifndef S_IWUSR -# define S_IWUSR _S_IWRITE -# endif +#ifndef S_IWUSR +# define S_IWUSR _S_IWRITE +#endif # ifdef __MINGW32__ # define _SH_DENYNO 0x40 -# undef fileno # endif #endif // _WIN32 @@ -83,8 +82,7 @@ fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT { fmt::report_system_error(errno, "cannot close file"); } -fmt::BufferedFile::BufferedFile( - fmt::CStringRef filename, fmt::CStringRef mode) { +fmt::BufferedFile::BufferedFile(fmt::StringRef filename, fmt::StringRef mode) { FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); if (!file_) throw SystemError(errno, "cannot open file {}", filename); @@ -99,19 +97,16 @@ void fmt::BufferedFile::close() { throw SystemError(errno, "cannot close file"); } -// A macro used to prevent expansion of fileno on broken versions of MinGW. -#define FMT_ARGS - int fmt::BufferedFile::fileno() const { - int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); + int fd = FMT_POSIX_CALL(fileno(file_)); if (fd == -1) throw SystemError(errno, "cannot get file descriptor"); return fd; } -fmt::File::File(fmt::CStringRef path, int oflag) { +fmt::File::File(fmt::StringRef path, int oflag) { int mode = S_IRUSR | S_IWUSR; -#if defined(_WIN32) && !defined(__MINGW32__) +#ifdef _WIN32 fd_ = -1; FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); #else @@ -141,19 +136,13 @@ void fmt::File::close() { fmt::LongLong fmt::File::size() const { #ifdef _WIN32 - // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT - // is less than 0x0500 as is the case with some default MinGW builds. - // Both functions support large file sizes. - DWORD size_upper = 0; + LARGE_INTEGER filesize = {}; HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); - DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); - if (size_lower == INVALID_FILE_SIZE) { - DWORD error = GetLastError(); - if (error != NO_ERROR) - throw WindowsError(GetLastError(), "cannot get file size"); - } - fmt::ULongLong long_size = size_upper; - return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; + if (!FMT_SYSTEM(GetFileSizeEx(handle, &filesize))) + throw WindowsError(GetLastError(), "cannot get file size"); + FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(filesize.QuadPart), + "return type of File::size is not large enough"); + return filesize.QuadPart; #else typedef struct stat Stat; Stat file_stat = Stat(); diff --git a/dep/cppformat/posix.h b/dep/cppformat/posix.h index 722690a8b33..e16ac521642 100644 --- a/dep/cppformat/posix.h +++ b/dep/cppformat/posix.h @@ -28,11 +28,6 @@ #ifndef FMT_POSIX_H_ #define FMT_POSIX_H_ -#ifdef __MINGW32__ -// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. -# undef __STRICT_ANSI__ -#endif - #include #include // for O_RDONLY #include @@ -41,8 +36,12 @@ #include "format.h" +#ifdef FMT_INCLUDE_POSIX_TEST +# include "test/posix-test.h" +#endif + #ifndef FMT_POSIX -# if defined(_WIN32) && !defined(__MINGW32__) +# ifdef _WIN32 // Fix warnings about deprecated symbols. # define FMT_POSIX(call) _##call # else @@ -181,7 +180,7 @@ public: #endif // Opens a file. - BufferedFile(CStringRef filename, CStringRef mode); + BufferedFile(fmt::StringRef filename, fmt::StringRef mode); // Closes the file. void close(); @@ -189,14 +188,12 @@ public: // Returns the pointer to a FILE object representing this file. FILE *get() const FMT_NOEXCEPT { return file_; } - // We place parentheses around fileno to workaround a bug in some versions - // of MinGW that define fileno as a macro. - int (fileno)() const; + int fileno() const; - void print(CStringRef format_str, const ArgList &args) { + void print(fmt::StringRef format_str, const ArgList &args) { fmt::print(file_, format_str, args); } - FMT_VARIADIC(void, print, CStringRef) + FMT_VARIADIC(void, print, fmt::StringRef) }; // A file. Closed file is represented by a File object with descriptor -1. @@ -224,7 +221,7 @@ class File { File() FMT_NOEXCEPT : fd_(-1) {} // Opens a file and constructs a File object representing this file. - File(CStringRef path, int oflag); + File(fmt::StringRef path, int oflag); #if !FMT_USE_RVALUE_REFERENCES // Emulate a move constructor and a move assignment operator if rvalue @@ -296,7 +293,7 @@ class File { void close(); // Returns the file size. - LongLong size() const; + fmt::LongLong size() const; // Attempts to read count bytes from the file into the specified buffer. std::size_t read(void *buffer, std::size_t count); diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index edd87a5c347..077cd15404b 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -43,6 +43,7 @@ endif() include_directories( ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration ${CMAKE_SOURCE_DIR}/src/server/shared/Database @@ -78,6 +79,7 @@ endif() target_link_libraries(authserver shared + format ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt index 293f05d1988..84f7de76543 100644 --- a/src/server/collision/CMakeLists.txt +++ b/src/server/collision/CMakeLists.txt @@ -35,6 +35,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include + ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index a00cd07caf8..53b906ff1d9 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3184,7 +3184,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui std::list list; me->GetCreatureListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist); - if (list.size() > 0) + if (!list.empty()) creature = list.front(); } @@ -3215,7 +3215,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui std::list list; me->GetGameObjectListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist); - if (list.size() > 0) + if (!list.empty()) gameobject = list.front(); } diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 1897f2027a1..38e515a9609 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -110,6 +110,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT + ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/dep/zlib ${CMAKE_SOURCE_DIR}/dep/zmqpp ${CMAKE_SOURCE_DIR}/src/server/collision diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index b53c09181b8..2b2d776b486 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -104,17 +104,6 @@ ChatCommand* ChatHandler::getCommandTable() return commandTableCache; } -std::string ChatHandler::PGetParseString(uint32 entry, ...) const -{ - const char *format = GetTrinityString(entry); - char str[1024]; - va_list ap; - va_start(ap, entry); - vsnprintf(str, 1024, format, ap); - va_end(ap); - return std::string(str); -} - char const* ChatHandler::GetTrinityString(uint32 entry) const { return m_session->GetTrinityString(entry); @@ -258,27 +247,6 @@ void ChatHandler::SendSysMessage(uint32 entry) SendSysMessage(GetTrinityString(entry)); } -void ChatHandler::PSendSysMessage(uint32 entry, ...) -{ - const char *format = GetTrinityString(entry); - va_list ap; - char str [2048]; - va_start(ap, entry); - vsnprintf(str, 2048, format, ap); - va_end(ap); - SendSysMessage(str); -} - -void ChatHandler::PSendSysMessage(const char *format, ...) -{ - va_list ap; - char str [2048]; - va_start(ap, format); - vsnprintf(str, 2048, format, ap); - va_end(ap); - SendSysMessage(str); -} - bool ChatHandler::ExecuteCommandInTable(ChatCommand* table, const char* text, std::string const& fullcmd) { char const* oldtext = text; diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 3a612dcf67f..8d8060bc638 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -20,6 +20,7 @@ #define TRINITYCORE_CHAT_H #include "SharedDefines.h" +#include "StringFormat.h" #include "WorldSession.h" #include "RBAC.h" @@ -69,9 +70,24 @@ class ChatHandler virtual void SendSysMessage(char const* str); void SendSysMessage(uint32 entry); - void PSendSysMessage(char const* format, ...) ATTR_PRINTF(2, 3); - void PSendSysMessage(uint32 entry, ...); - std::string PGetParseString(uint32 entry, ...) const; + + template + void PSendSysMessage(const char* fmt, Args const&... args) + { + SendSysMessage(Trinity::StringFormat(fmt, args...).c_str()); + } + + template + void PSendSysMessage(uint32 entry, Args const&... args) + { + SendSysMessage(PGetParseString(entry, args...).c_str()); + } + + template + std::string PGetParseString(uint32 entry, Args const&... args) const + { + return Trinity::StringFormat(GetTrinityString(entry), args...); + } bool ParseCommands(const char* text); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 8d5427f4764..f6b4600bf04 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -99,7 +99,8 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND { "Distance", true, true, true }, { "Alive", false, false, false }, { "Health Value", true, true, false }, - { "Health Pct", true, true, false } + { "Health Pct", true, true, false }, + { "Realm Achievement", true, false, false } }; // Checks if object meets the condition diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 0a6a258d06d..bb7e4a2e4cf 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -3825,6 +3825,8 @@ void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, Play } } +int32 const ReputationMgr::Reputation_Cap; + void ObjectMgr::LoadQuests() { uint32 oldMSTime = getMSTime(); diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 5d3eb5f02c0..321e0c44149 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -182,9 +182,8 @@ struct TSpellSummary uint8 Effects; // set of enum SelectEffect } *SpellSummary; -ScriptMgr::ScriptMgr() : _scriptCount(0) +ScriptMgr::ScriptMgr() : _scriptCount(0), _scheduledScripts(0) { - _scheduledScripts = 0; } ScriptMgr::~ScriptMgr() { } diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 427e48c4788..98ce9138e6b 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -1141,7 +1141,7 @@ class ScriptMgr uint32 _scriptCount; //atomic op counter for active scripts amount - std::atomic_long _scheduledScripts; + std::atomic _scheduledScripts; }; #endif diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp index 947bd62860c..e83d39cb922 100644 --- a/src/server/game/Server/WorldSocketMgr.cpp +++ b/src/server/game/Server/WorldSocketMgr.cpp @@ -46,6 +46,8 @@ WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _socketSendBufferSize(-1), m { } +int const boost::asio::socket_base::max_connections; + bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) { _tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index a0434ed1f03..290560087b6 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -7193,7 +7193,7 @@ void Spell::CallScriptDestinationTargetSelectHandlers(SpellDestination& target, bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck) { // Skip if there are not any script - if (!m_loadedScripts.size()) + if (m_loadedScripts.empty()) return true; for (std::list::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr) diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index 4b5d725d6bf..10c01e6a128 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -51,6 +51,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT + ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/dep/zlib ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration diff --git a/src/server/scripts/EasternKingdoms/zone_undercity.cpp b/src/server/scripts/EasternKingdoms/zone_undercity.cpp index 9ce694fb76c..ca281bab60a 100644 --- a/src/server/scripts/EasternKingdoms/zone_undercity.cpp +++ b/src/server/scripts/EasternKingdoms/zone_undercity.cpp @@ -40,25 +40,44 @@ EndContentData */ enum Sylvanas { - QUEST_JOURNEY_TO_UNDERCITY = 9180, - EMOTE_LAMENT_END = 0, - SAY_LAMENT_END = 1, + QUEST_JOURNEY_TO_UNDERCITY = 9180, - SOUND_CREDIT = 10896, - ENTRY_HIGHBORNE_LAMENTER = 21628, - ENTRY_HIGHBORNE_BUNNY = 21641, + EMOTE_LAMENT_END = 0, + SAY_LAMENT_END = 1, + EMOTE_LAMENT = 2, - SPELL_HIGHBORNE_AURA = 37090, - SPELL_SYLVANAS_CAST = 36568, - SPELL_RIBBON_OF_SOULS = 34432, // the real one to use might be 37099 + // Ambassador Sunsorrow + SAY_SUNSORROW_WHISPER = 0, + + SOUND_CREDIT = 10896, + + NPC_HIGHBORNE_LAMENTER = 21628, + NPC_HIGHBORNE_BUNNY = 21641, + NPC_AMBASSADOR_SUNSORROW = 16287, + + SPELL_HIGHBORNE_AURA = 37090, + SPELL_SYLVANAS_CAST = 36568, + //SPELL_RIBBON_OF_SOULS = 34432, the real one to use might be 37099 + SPELL_RIBBON_OF_SOULS = 37099, // Combat spells - SPELL_BLACK_ARROW = 59712, - SPELL_FADE = 20672, - SPELL_FADE_BLINK = 29211, - SPELL_MULTI_SHOT = 59713, - SPELL_SHOT = 59710, - SPELL_SUMMON_SKELETON = 59711 + SPELL_BLACK_ARROW = 59712, + SPELL_FADE = 20672, + SPELL_FADE_BLINK = 29211, + SPELL_MULTI_SHOT = 59713, + SPELL_SHOT = 59710, + SPELL_SUMMON_SKELETON = 59711, + + // Events + EVENT_FADE = 1, + EVENT_SUMMON_SKELETON = 2, + EVENT_BLACK_ARROW = 3, + EVENT_SHOOT = 4, + EVENT_MULTI_SHOT = 5, + EVENT_LAMENT_OF_THE_HIGHBORN = 6, + EVENT_SUNSORROW_WHISPER = 7, + + GUID_EVENT_INVOKER = 1, }; float HighborneLoc[4][3]= @@ -77,26 +96,14 @@ class npc_lady_sylvanas_windrunner : public CreatureScript public: npc_lady_sylvanas_windrunner() : CreatureScript("npc_lady_sylvanas_windrunner") { } - bool OnQuestReward(Player* /*player*/, Creature* creature, const Quest *_Quest, uint32 /*slot*/) override + bool OnQuestReward(Player* player, Creature* creature, const Quest *_Quest, uint32 /*slot*/) override { if (_Quest->GetQuestId() == QUEST_JOURNEY_TO_UNDERCITY) - { - ENSURE_AI(npc_lady_sylvanas_windrunner::npc_lady_sylvanas_windrunnerAI, creature->AI())->LamentEvent = true; - ENSURE_AI(npc_lady_sylvanas_windrunner::npc_lady_sylvanas_windrunnerAI, creature->AI())->DoPlaySoundToSet(creature, SOUND_CREDIT); - creature->CastSpell(creature, SPELL_SYLVANAS_CAST, false); - - for (uint8 i = 0; i < 4; ++i) - creature->SummonCreature(ENTRY_HIGHBORNE_LAMENTER, HighborneLoc[i][0], HighborneLoc[i][1], HIGHBORNE_LOC_Y, HighborneLoc[i][2], TEMPSUMMON_TIMED_DESPAWN, 160000); - } + creature->AI()->SetGUID(player->GetGUID(), GUID_EVENT_INVOKER); return true; } - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_lady_sylvanas_windrunnerAI(creature); - } - struct npc_lady_sylvanas_windrunnerAI : public ScriptedAI { npc_lady_sylvanas_windrunnerAI(Creature* creature) : ScriptedAI(creature) @@ -106,41 +113,51 @@ public: void Initialize() { - LamentEventTimer = 5000; LamentEvent = false; targetGUID.Clear(); - - FadeTimer = 30000; - SummonSkeletonTimer = 20000; - BlackArrowTimer = 15000; - ShotTimer = 8000; - MultiShotTimer = 10000; + playerGUID.Clear(); } - uint32 LamentEventTimer; - bool LamentEvent; - ObjectGuid targetGUID; - - uint32 FadeTimer; - uint32 SummonSkeletonTimer; - uint32 BlackArrowTimer; - uint32 ShotTimer; - uint32 MultiShotTimer; - void Reset() override { Initialize(); + _events.Reset(); } - void EnterCombat(Unit* /*who*/) override { } + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_FADE, 30000); + _events.ScheduleEvent(EVENT_SUMMON_SKELETON, 20000); + _events.ScheduleEvent(EVENT_BLACK_ARROW, 15000); + _events.ScheduleEvent(EVENT_SHOOT, 8000); + _events.ScheduleEvent(EVENT_MULTI_SHOT, 10000); + } + + void SetGUID(ObjectGuid guid, int32 type) override + { + if (type == GUID_EVENT_INVOKER) + { + Talk(EMOTE_LAMENT); + DoPlaySoundToSet(me, SOUND_CREDIT); + DoCast(me, SPELL_SYLVANAS_CAST, false); + playerGUID = guid; + LamentEvent = true; + + for (uint8 i = 0; i < 4; ++i) + me->SummonCreature(NPC_HIGHBORNE_LAMENTER, HighborneLoc[i][0], HighborneLoc[i][1], HIGHBORNE_LOC_Y, HighborneLoc[i][2], TEMPSUMMON_TIMED_DESPAWN, 160000); + + _events.ScheduleEvent(EVENT_LAMENT_OF_THE_HIGHBORN, 2000); + _events.ScheduleEvent(EVENT_SUNSORROW_WHISPER, 10000); + } + } void JustSummoned(Creature* summoned) override { - if (summoned->GetEntry() == ENTRY_HIGHBORNE_BUNNY) + if (summoned->GetEntry() == NPC_HIGHBORNE_BUNNY) { if (Creature* target = ObjectAccessor::GetCreature(*summoned, targetGUID)) { - target->MonsterMoveWithSpeed(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0); + target->GetMotionMaster()->MoveJump(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ() + 15.0f, 0); target->SetPosition(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0.0f); summoned->CastSpell(target, SPELL_RIBBON_OF_SOULS, false); } @@ -152,75 +169,86 @@ public: void UpdateAI(uint32 diff) override { - if (LamentEvent) - { - if (LamentEventTimer <= diff) - { - DoSummon(ENTRY_HIGHBORNE_BUNNY, me, 10.0f, 3000, TEMPSUMMON_TIMED_DESPAWN); - - LamentEventTimer = 2000; - if (!me->HasAura(SPELL_SYLVANAS_CAST)) - { - Talk(SAY_LAMENT_END); - Talk(EMOTE_LAMENT_END); - LamentEvent = false; - } - } else LamentEventTimer -= diff; - } - - if (!UpdateVictim()) + if (!UpdateVictim() && !LamentEvent) return; - // Combat spells + _events.Update(diff); - if (FadeTimer <= diff) - { - DoCast(me, SPELL_FADE); - // add a blink to simulate a stealthed movement and reappearing elsewhere - DoCast(me, SPELL_FADE_BLINK); - FadeTimer = 30000 + rand32() % 5000; - // if the victim is out of melee range she cast multi shot - if (Unit* victim = me->GetVictim()) - if (me->GetDistance(victim) > 10.0f) - DoCast(victim, SPELL_MULTI_SHOT); - } else FadeTimer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (SummonSkeletonTimer <= diff) + while (uint32 eventId = _events.ExecuteEvent()) { - DoCast(me, SPELL_SUMMON_SKELETON); - SummonSkeletonTimer = 20000 + rand32() % 10000; - } else SummonSkeletonTimer -= diff; - - if (BlackArrowTimer <= diff) - { - if (Unit* victim = me->GetVictim()) + switch (eventId) { - DoCast(victim, SPELL_BLACK_ARROW); - BlackArrowTimer = 15000 + rand32() % 5000; + case EVENT_FADE: + DoCast(me, SPELL_FADE); + // add a blink to simulate a stealthed movement and reappearing elsewhere + DoCast(me, SPELL_FADE_BLINK); + // if the victim is out of melee range she cast multi shot + if (Unit* victim = me->GetVictim()) + if (me->GetDistance(victim) > 10.0f) + DoCast(victim, SPELL_MULTI_SHOT); + _events.ScheduleEvent(EVENT_FADE, urand(30000, 35000)); + break; + case EVENT_SUMMON_SKELETON: + DoCast(me, SPELL_SUMMON_SKELETON); + _events.ScheduleEvent(EVENT_SUMMON_SKELETON, urand(20000, 30000)); + break; + case EVENT_BLACK_ARROW: + if (Unit* victim = me->GetVictim()) + DoCast(victim, SPELL_BLACK_ARROW); + _events.ScheduleEvent(EVENT_BLACK_ARROW, urand(15000, 20000)); + break; + case EVENT_SHOOT: + if (Unit* victim = me->GetVictim()) + DoCast(victim, SPELL_SHOT); + _events.ScheduleEvent(EVENT_SHOOT, urand(8000, 10000)); + break; + case EVENT_MULTI_SHOT: + if (Unit* victim = me->GetVictim()) + DoCast(victim, SPELL_MULTI_SHOT); + _events.ScheduleEvent(EVENT_MULTI_SHOT, urand(10000, 13000)); + break; + case EVENT_LAMENT_OF_THE_HIGHBORN: + if (!me->HasAura(SPELL_SYLVANAS_CAST)) + { + Talk(SAY_LAMENT_END); + Talk(EMOTE_LAMENT_END); + LamentEvent = false; + me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); + Reset(); + } + else + { + DoSummon(NPC_HIGHBORNE_BUNNY, me, 10.0f, 3000, TEMPSUMMON_TIMED_DESPAWN); + _events.ScheduleEvent(EVENT_LAMENT_OF_THE_HIGHBORN, 2000); + } + break; + case EVENT_SUNSORROW_WHISPER: + if (Creature* ambassador = me->FindNearestCreature(NPC_AMBASSADOR_SUNSORROW, 20.0f)) + if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID)) + ambassador->AI()->Talk(SAY_SUNSORROW_WHISPER, player); + break; + default: + break; } - } else BlackArrowTimer -= diff; - - if (ShotTimer <= diff) - { - if (Unit* victim = me->GetVictim()) - { - DoCast(victim, SPELL_SHOT); - ShotTimer = 8000 + rand32() % 2000; - } - } else ShotTimer -= diff; - - if (MultiShotTimer <= diff) - { - if (Unit* victim = me->GetVictim()) - { - DoCast(victim, SPELL_MULTI_SHOT); - MultiShotTimer = 10000 + rand32() % 3000; - } - } else MultiShotTimer -= diff; + } DoMeleeAttackIfReady(); } + + private: + EventMap _events; + bool LamentEvent; + ObjectGuid targetGUID; + ObjectGuid playerGUID; }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_lady_sylvanas_windrunnerAI(creature); + } }; /*###### diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index 04bebca66d7..4574f45649f 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -395,6 +395,9 @@ enum NesingwaryTrapper GO_CARIBOU_TRAP_15 = 188008, SPELL_TRAPPED = 46104, + + // Texts + SAY_NESINGWARY_1 = 0 }; #define CaribouTrapsNum 15 @@ -471,7 +474,7 @@ public: phase = 3; break; case 3: - //Talk(SAY_NESINGWARY_1); + Talk(SAY_NESINGWARY_1); phaseTimer = 2000; phase = 4; break; diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt index c18a4de7c91..5f319191c14 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -59,6 +59,7 @@ include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour ${CMAKE_SOURCE_DIR}/dep/SFMT + ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/dep/utf8cpp ${CMAKE_SOURCE_DIR}/src/server ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/src/server/shared/Logging/Appender.cpp b/src/server/shared/Logging/Appender.cpp index dff931e3da8..ca40a857419 100644 --- a/src/server/shared/Logging/Appender.cpp +++ b/src/server/shared/Logging/Appender.cpp @@ -18,6 +18,10 @@ #include "Appender.h" #include "Common.h" #include "Util.h" +#include "StringFormat.h" + +#include +#include std::string LogMessage::getTimeStr(time_t time) { @@ -68,38 +72,36 @@ void Appender::setLogLevel(LogLevel _level) level = _level; } -void Appender::write(LogMessage& message) +void Appender::write(LogMessage* message) { - if (!level || level > message.level) + if (!level || level > message->level) return; - message.prefix.clear(); + std::ostringstream ss; + if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP) - message.prefix.append(message.getTimeStr()); + ss << message->getTimeStr(); if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL) { - if (!message.prefix.empty()) - message.prefix.push_back(' '); + if (ss.rdbuf()->in_avail() == 0) + ss << ' '; - char text[MAX_QUERY_LEN]; - snprintf(text, MAX_QUERY_LEN, "%-5s", Appender::getLogLevelString(message.level)); - message.prefix.append(text); + ss << Trinity::StringFormat("%-5s", Appender::getLogLevelString(message->level)); } if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE) { - if (!message.prefix.empty()) - message.prefix.push_back(' '); + if (ss.rdbuf()->in_avail() == 0) + ss << ' '; - message.prefix.push_back('['); - message.prefix.append(message.type); - message.prefix.push_back(']'); + ss << '[' << message->type << ']'; } - if (!message.prefix.empty()) - message.prefix.push_back(' '); + if (ss.rdbuf()->in_avail() == 0) + ss << ' '; + message->prefix = std::move(ss.str()); _write(message); } diff --git a/src/server/shared/Logging/Appender.h b/src/server/shared/Logging/Appender.h index 6f38eb6aaf7..38c45b3bcf1 100644 --- a/src/server/shared/Logging/Appender.h +++ b/src/server/shared/Logging/Appender.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "Define.h" // Values assigned have their equivalent in enum ACE_Log_Priority @@ -57,16 +58,16 @@ enum AppenderFlags struct LogMessage { - LogMessage(LogLevel _level, std::string const& _type, std::string const& _text) - : level(_level), type(_type), text(_text), mtime(time(NULL)) + LogMessage(LogLevel _level, std::string const& _type, std::string&& _text) + : level(_level), type(_type), text(std::forward(_text)), mtime(time(NULL)) { } static std::string getTimeStr(time_t time); std::string getTimeStr(); - LogLevel level; - std::string type; - std::string text; + LogLevel const level; + std::string const type; + std::string const text; std::string prefix; std::string param1; time_t mtime; @@ -91,11 +92,11 @@ class Appender AppenderFlags getFlags() const; void setLogLevel(LogLevel); - void write(LogMessage& message); + void write(LogMessage* message); static const char* getLogLevelString(LogLevel level); private: - virtual void _write(LogMessage const& /*message*/) = 0; + virtual void _write(LogMessage const* /*message*/) = 0; uint8 id; std::string name; diff --git a/src/server/shared/Logging/AppenderConsole.cpp b/src/server/shared/Logging/AppenderConsole.cpp index ae27337fb9a..2efa4db4d2e 100644 --- a/src/server/shared/Logging/AppenderConsole.cpp +++ b/src/server/shared/Logging/AppenderConsole.cpp @@ -158,14 +158,14 @@ void AppenderConsole::ResetColor(bool stdout_stream) #endif } -void AppenderConsole::_write(LogMessage const& message) +void AppenderConsole::_write(LogMessage const* message) { - bool stdout_stream = !(message.level == LOG_LEVEL_ERROR || message.level == LOG_LEVEL_FATAL); + bool stdout_stream = !(message->level == LOG_LEVEL_ERROR || message->level == LOG_LEVEL_FATAL); if (_colored) { uint8 index; - switch (message.level) + switch (message->level) { case LOG_LEVEL_TRACE: index = 5; @@ -189,9 +189,9 @@ void AppenderConsole::_write(LogMessage const& message) } SetColor(stdout_stream, _colors[index]); - utf8printf(stdout_stream ? stdout : stderr, "%s%s", message.prefix.c_str(), message.text.c_str()); + utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str()); ResetColor(stdout_stream); } else - utf8printf(stdout_stream ? stdout : stderr, "%s%s", message.prefix.c_str(), message.text.c_str()); + utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str()); } diff --git a/src/server/shared/Logging/AppenderConsole.h b/src/server/shared/Logging/AppenderConsole.h index 0f9536b3111..0acf7636e35 100644 --- a/src/server/shared/Logging/AppenderConsole.h +++ b/src/server/shared/Logging/AppenderConsole.h @@ -51,7 +51,7 @@ class AppenderConsole: public Appender private: void SetColor(bool stdout_stream, ColorTypes color); void ResetColor(bool stdout_stream); - void _write(LogMessage const& message) override; + void _write(LogMessage const* message) override; bool _colored; ColorTypes _colors[MaxLogLevels]; }; diff --git a/src/server/shared/Logging/AppenderDB.cpp b/src/server/shared/Logging/AppenderDB.cpp index d297d6d08d3..8a329ea3a0f 100644 --- a/src/server/shared/Logging/AppenderDB.cpp +++ b/src/server/shared/Logging/AppenderDB.cpp @@ -23,18 +23,18 @@ AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level) AppenderDB::~AppenderDB() { } -void AppenderDB::_write(LogMessage const& message) +void AppenderDB::_write(LogMessage const* message) { // Avoid infinite loop, PExecute triggers Logging with "sql.sql" type - if (!enabled || !message.type.find("sql")) + if (!enabled || (message->type.find("sql") != std::string::npos)) return; PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG); - stmt->setUInt64(0, message.mtime); + stmt->setUInt64(0, message->mtime); stmt->setUInt32(1, realmId); - stmt->setString(2, message.type); - stmt->setUInt8(3, uint8(message.level)); - stmt->setString(4, message.text); + stmt->setString(2, message->type); + stmt->setUInt8(3, uint8(message->level)); + stmt->setString(4, message->text); LoginDatabase.Execute(stmt); } diff --git a/src/server/shared/Logging/AppenderDB.h b/src/server/shared/Logging/AppenderDB.h index e20ceaf77b4..09affdb46f1 100644 --- a/src/server/shared/Logging/AppenderDB.h +++ b/src/server/shared/Logging/AppenderDB.h @@ -31,7 +31,7 @@ class AppenderDB: public Appender private: uint32 realmId; bool enabled; - void _write(LogMessage const& message) override; + void _write(LogMessage const* message) override; }; #endif diff --git a/src/server/shared/Logging/AppenderFile.cpp b/src/server/shared/Logging/AppenderFile.cpp index 07a88a367ae..3892adbe3be 100644 --- a/src/server/shared/Logging/AppenderFile.cpp +++ b/src/server/shared/Logging/AppenderFile.cpp @@ -43,21 +43,21 @@ AppenderFile::~AppenderFile() CloseFile(); } -void AppenderFile::_write(LogMessage const& message) +void AppenderFile::_write(LogMessage const* message) { - bool exceedMaxSize = maxFileSize > 0 && (fileSize.load() + message.Size()) > maxFileSize; + bool exceedMaxSize = maxFileSize > 0 && (fileSize.load() + message->Size()) > maxFileSize; if (dynamicName) { char namebuf[TRINITY_PATH_MAX]; - snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message.param1.c_str()); + snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message->param1.c_str()); // always use "a" with dynamic name otherwise it could delete the log we wrote in last _write() call FILE* file = OpenFile(namebuf, "a", backup || exceedMaxSize); if (!file) return; - fprintf(file, "%s%s", message.prefix.c_str(), message.text.c_str()); + fprintf(file, "%s%s", message->prefix.c_str(), message->text.c_str()); fflush(file); - fileSize += uint64(message.Size()); + fileSize += uint64(message->Size()); fclose(file); return; } @@ -67,9 +67,9 @@ void AppenderFile::_write(LogMessage const& message) if (!logfile) return; - fprintf(logfile, "%s%s", message.prefix.c_str(), message.text.c_str()); + fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str()); fflush(logfile); - fileSize += uint64(message.Size()); + fileSize += uint64(message->Size()); } FILE* AppenderFile::OpenFile(std::string const &filename, std::string const &mode, bool backup) diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h index 23651fc1129..36afdd23ad1 100644 --- a/src/server/shared/Logging/AppenderFile.h +++ b/src/server/shared/Logging/AppenderFile.h @@ -30,7 +30,7 @@ class AppenderFile: public Appender private: void CloseFile(); - void _write(LogMessage const& message) override; + void _write(LogMessage const* message) override; FILE* logfile; std::string filename; std::string logDir; diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp index 2f4d221645c..c9a4432039f 100644 --- a/src/server/shared/Logging/Log.cpp +++ b/src/server/shared/Logging/Log.cpp @@ -264,30 +264,18 @@ void Log::ReadLoggersFromConfig() } } -void Log::vlog(std::string const& filter, LogLevel level, char const* str, va_list argptr) -{ - char text[MAX_QUERY_LEN]; - vsnprintf(text, MAX_QUERY_LEN, str, argptr); - write(new LogMessage(level, filter, text)); -} - -void Log::write(LogMessage* msg) const +void Log::write(std::unique_ptr&& msg) const { Logger const* logger = GetLoggerByType(msg->type); - msg->text.append("\n"); if (_ioService) { - auto logOperation = std::shared_ptr(new LogOperation(logger, msg)); + auto logOperation = std::shared_ptr(new LogOperation(logger, std::forward>(msg))); _ioService->post(_strand->wrap([logOperation](){ logOperation->call(); })); - } else - { - logger->write(*msg); - delete msg; - } + logger->write(msg.get()); } std::string Log::GetTimestampStr() @@ -349,40 +337,20 @@ void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const ss << "== START DUMP == (account: " << accountId << " guid: " << guid << " name: " << name << ")\n" << str << "\n== END DUMP ==\n"; - LogMessage* msg = new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str()); + std::unique_ptr msg(new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str())); std::ostringstream param; param << guid << '_' << name; msg->param1 = param.str(); - write(msg); -} - -void Log::outCommand(uint32 account, const char * str, ...) -{ - if (!str || !ShouldLog("commands.gm", LOG_LEVEL_INFO)) - return; - - va_list ap; - va_start(ap, str); - char text[MAX_QUERY_LEN]; - vsnprintf(text, MAX_QUERY_LEN, str, ap); - va_end(ap); - - LogMessage* msg = new LogMessage(LOG_LEVEL_INFO, "commands.gm", text); - - std::ostringstream ss; - ss << account; - msg->param1 = ss.str(); - - write(msg); + write(std::move(msg)); } void Log::SetRealmId(uint32 id) { for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it) if (it->second && it->second->getType() == APPENDER_DB) - ((AppenderDB *)it->second)->setRealmId(id); + static_cast(it->second)->setRealmId(id); } void Log::Close() diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index 408381620f7..85d012c4629 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -22,12 +22,13 @@ #include "Define.h" #include "Appender.h" #include "Logger.h" -#include +#include "StringFormat.h" #include #include #include #include +#include #define LOGGER_ROOT "root" @@ -59,17 +60,34 @@ class Log bool ShouldLog(std::string const& type, LogLevel level) const; bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true); - void outMessage(std::string const& f, LogLevel level, char const* str, ...) ATTR_PRINTF(4, 5); + template + inline void outMessage(std::string const& filter, LogLevel const level, const char* fmt, Args const&... args) + { + write(std::move(std::unique_ptr(new LogMessage(level, filter, std::move(Trinity::StringFormat(fmt, args...)))))); + } + + template + void outCommand(uint32 account, const char* fmt, Args const&... args) + { + if (!ShouldLog("commands.gm", LOG_LEVEL_INFO)) + return; + + std::unique_ptr msg(new LogMessage(LOG_LEVEL_INFO, "commands.gm", std::move(Trinity::StringFormat(fmt, args...)))); + + std::ostringstream ss; + ss << account; + msg->param1 = ss.str(); + + write(std::move(msg)); + } - void outCommand(uint32 account, const char * str, ...) ATTR_PRINTF(3, 4); void outCharDump(char const* str, uint32 account_id, uint64 guid, char const* name); void SetRealmId(uint32 id); private: static std::string GetTimestampStr(); - void vlog(std::string const& f, LogLevel level, char const* str, va_list argptr); - void write(LogMessage* msg) const; + void write(std::unique_ptr&& msg) const; Logger const* GetLoggerByType(std::string const& type) const; Appender* GetAppenderByName(std::string const& name); @@ -126,23 +144,34 @@ inline bool Log::ShouldLog(std::string const& type, LogLevel level) const return logLevel != LOG_LEVEL_DISABLED && logLevel <= level; } -inline void Log::outMessage(std::string const& filter, LogLevel level, const char * str, ...) -{ - va_list ap; - va_start(ap, str); - - vlog(filter, level, str, ap); - - va_end(ap); -} - #define sLog Log::instance() +#define LOG_EXCEPTION_FREE(filterType__, level__, ...) \ + { \ + try \ + { \ + sLog->outMessage(filterType__, level__, __VA_ARGS__); \ + } \ + catch (std::exception& e) \ + { \ + sLog->outMessage("server", LOG_LEVEL_ERROR, "Wrong format occurred (%s) at %s:%u.", \ + e.what(), __FILE__, __LINE__); \ + } \ + } + #if PLATFORM != PLATFORM_WINDOWS +void check_args(const char* format, ...) ATTR_PRINTF(1, 2); + +// This will catch format errors on build time #define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \ do { \ if (sLog->ShouldLog(filterType__, level__)) \ - sLog->outMessage(filterType__, level__, __VA_ARGS__); \ + { \ + if (false) \ + check_args(__VA_ARGS__); \ + \ + LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \ + } \ } while (0) #else #define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \ @@ -150,7 +179,7 @@ inline void Log::outMessage(std::string const& filter, LogLevel level, const cha __pragma(warning(disable:4127)) \ do { \ if (sLog->ShouldLog(filterType__, level__)) \ - sLog->outMessage(filterType__, level__, __VA_ARGS__); \ + LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \ } while (0) \ __pragma(warning(pop)) #endif diff --git a/src/server/shared/Logging/LogOperation.cpp b/src/server/shared/Logging/LogOperation.cpp index 9afb28a49c2..bcd923c705e 100644 --- a/src/server/shared/Logging/LogOperation.cpp +++ b/src/server/shared/Logging/LogOperation.cpp @@ -18,14 +18,8 @@ #include "LogOperation.h" #include "Logger.h" -LogOperation::~LogOperation() -{ - delete msg; -} - int LogOperation::call() { - if (logger && msg) - logger->write(*msg); + logger->write(msg.get()); return 0; } diff --git a/src/server/shared/Logging/LogOperation.h b/src/server/shared/Logging/LogOperation.h index b8655413273..ffdd35c3c09 100644 --- a/src/server/shared/Logging/LogOperation.h +++ b/src/server/shared/Logging/LogOperation.h @@ -18,23 +18,25 @@ #ifndef LOGOPERATION_H #define LOGOPERATION_H +#include + class Logger; struct LogMessage; class LogOperation { public: - LogOperation(Logger const* _logger, LogMessage* _msg) - : logger(_logger), msg(_msg) + LogOperation(Logger const* _logger, std::unique_ptr&& _msg) + : logger(_logger), msg(std::forward>(_msg)) { } - ~LogOperation(); + ~LogOperation() { } int call(); protected: Logger const* logger; - LogMessage* msg; + std::unique_ptr msg; }; #endif diff --git a/src/server/shared/Logging/Logger.cpp b/src/server/shared/Logging/Logger.cpp index 615732deb30..3b02eb47575 100644 --- a/src/server/shared/Logging/Logger.cpp +++ b/src/server/shared/Logging/Logger.cpp @@ -50,9 +50,9 @@ void Logger::setLogLevel(LogLevel _level) level = _level; } -void Logger::write(LogMessage& message) const +void Logger::write(LogMessage* message) const { - if (!level || level > message.level || message.text.empty()) + if (!level || level > message->level || message->text.empty()) { //fprintf(stderr, "Logger::write: Logger %s, Level %u. Msg %s Level %u WRONG LEVEL MASK OR EMPTY MSG\n", getName().c_str(), getLogLevel(), message.text.c_str(), message.level); return; diff --git a/src/server/shared/Logging/Logger.h b/src/server/shared/Logging/Logger.h index a81ee8d7bd2..1aee75c5d72 100644 --- a/src/server/shared/Logging/Logger.h +++ b/src/server/shared/Logging/Logger.h @@ -32,7 +32,7 @@ class Logger std::string const& getName() const; LogLevel getLogLevel() const; void setLogLevel(LogLevel level); - void write(LogMessage& message) const; + void write(LogMessage* message) const; private: std::string name; diff --git a/src/server/shared/Utilities/StringFormat.h b/src/server/shared/Utilities/StringFormat.h new file mode 100644 index 00000000000..70d9aefb14d --- /dev/null +++ b/src/server/shared/Utilities/StringFormat.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008-2015 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * 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 . + */ + +#ifndef TRINITYCORE_STRING_FORMAT_H +#define TRINITYCORE_STRING_FORMAT_H + +#include + +namespace Trinity +{ + //! Default TC string format function + template + inline std::string StringFormat(const char* fmt, Args const&... args) + { + return fmt::sprintf(fmt, args...); + } +} + +#endif diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 326709e9155..ddf336388d3 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -48,6 +48,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/dep/sockets/include ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zmqpp + ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/src/server/collision ${CMAKE_SOURCE_DIR}/src/server/collision/Management ${CMAKE_SOURCE_DIR}/src/server/collision/Models @@ -175,6 +176,7 @@ target_link_libraries(worldserver gsoap Detour zmqpp + format ${JEMALLOC_LIBRARY} ${READLINE_LIBRARY} ${TERMCAP_LIBRARY}