diff --git a/src/logging.h b/src/logging.h index 53003b34c..47028b478 100644 --- a/src/logging.h +++ b/src/logging.h @@ -1,170 +1,185 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_LOGGING_H #define BITCOIN_LOGGING_H #include #include #include #include #include #include #include static const bool DEFAULT_LOGTIMEMICROS = false; static const bool DEFAULT_LOGIPS = false; static const bool DEFAULT_LOGTIMESTAMPS = true; extern bool fLogIPs; extern const char *const DEFAULT_DEBUGLOGFILE; struct CLogCategoryActive { std::string category; bool active; }; namespace BCLog { enum LogFlags : uint32_t { NONE = 0, NET = (1 << 0), TOR = (1 << 1), MEMPOOL = (1 << 2), HTTP = (1 << 3), BENCH = (1 << 4), ZMQ = (1 << 5), DB = (1 << 6), RPC = (1 << 7), ESTIMATEFEE = (1 << 8), ADDRMAN = (1 << 9), SELECTCOINS = (1 << 10), REINDEX = (1 << 11), CMPCTBLOCK = (1 << 12), RAND = (1 << 13), PRUNE = (1 << 14), PROXY = (1 << 15), MEMPOOLREJ = (1 << 16), LIBEVENT = (1 << 17), COINDB = (1 << 18), QT = (1 << 19), LEVELDB = (1 << 20), ALL = ~uint32_t(0), }; class Logger { private: FILE *m_fileout = nullptr; std::mutex m_file_mutex; std::list m_msgs_before_open; /** * m_started_new_line is a state variable that will suppress printing of the * timestamp when multiple calls are made that don't end in a newline. */ std::atomic_bool m_started_new_line{true}; /** * Log categories bitfield. */ std::atomic m_categories{0}; std::string LogTimestampStr(const std::string &str); public: bool m_print_to_console = false; bool m_print_to_file = false; bool m_log_timestamps = DEFAULT_LOGTIMESTAMPS; bool m_log_time_micros = DEFAULT_LOGTIMEMICROS; fs::path m_file_path; std::atomic m_reopen_file{false}; ~Logger(); /** Send a string to the log output */ void LogPrintStr(const std::string &str); bool OpenDebugLog(); void ShrinkDebugFile(); uint32_t GetCategoryMask() const { return m_categories.load(); } void EnableCategory(LogFlags category); bool EnableCategory(const std::string &str); void DisableCategory(LogFlags category); bool DisableCategory(const std::string &str); /** Return true if log accepts specified category */ bool WillLogCategory(LogFlags category) const; /** Default for whether ShrinkDebugFile should be run */ bool DefaultShrinkDebugFile() const; }; } // namespace BCLog BCLog::Logger &LogInstance(); /** Return true if log accepts specified category */ static inline bool LogAcceptCategory(BCLog::LogFlags category) { return LogInstance().WillLogCategory(category); } /** Returns a string with the log categories. */ std::string ListLogCategories(); /** Returns a vector of the active log categories. */ std::vector ListActiveLogCategories(); /** Return true if str parses as a log category and set the flag */ bool GetLogCategory(BCLog::LogFlags &flag, const std::string &str); // Be conservative when using LogPrintf/error or other things which // unconditionally log to debug.log! It should not be the case that an inbound // peer can fill up a user's disk with debug.log entries. static inline void MarkUsed() {} template static inline void MarkUsed(const T &t, const Args &... args) { (void)t; MarkUsed(args...); } +template +std::string FormatStringFromLogArgs(const char *fmt, const Args &... args) { + return fmt; +} #ifdef USE_COVERAGE #define LogPrintf(...) \ do { \ MarkUsed(__VA_ARGS__); \ } while (0) #define LogPrint(category, ...) \ do { \ MarkUsed(__VA_ARGS__); \ } while (0) #else -#define LogPrint(category, ...) \ +#define LogPrintf(...) \ do { \ - if (LogAcceptCategory((category))) { \ - LogInstance().LogPrintStr(tfm::format(__VA_ARGS__)); \ + /* Unlikely name to avoid shadowing variables */ \ + std::string _log_msg_; \ + try { \ + _log_msg_ = tfm::format(__VA_ARGS__); \ + } catch (tinyformat::format_error & fmterr) { \ + /** \ + * Original format string will have newline so don't add one here \ + */ \ + _log_msg_ = "Error \"" + std::string(fmterr.what()) + \ + "\" while formatting log message: " + \ + FormatStringFromLogArgs(__VA_ARGS__); \ } \ + LogInstance().LogPrintStr(_log_msg_); \ } while (0) - -#define LogPrintf(...) \ +#define LogPrint(category, ...) \ do { \ - LogInstance().LogPrintStr(tfm::format(__VA_ARGS__)); \ + if (LogAcceptCategory((category))) { \ + LogPrintf(__VA_ARGS__); \ + } \ } while (0) #endif /** * These are aliases used to explicitly state that the message should not end * with a newline character. It allows for detecting the missing newlines that * could make the logs hard to read. */ #define LogPrintfToBeContinued LogPrintf #define LogPrintToBeContinued LogPrint #endif // BITCOIN_LOGGING_H diff --git a/src/tinyformat.h b/src/tinyformat.h index 0e8ff32a1..cdb947d30 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -1,1084 +1,1090 @@ // tinyformat.h // Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com] // // Boost Software License - Version 1.0 // // Permission is hereby granted, free of charge, to any person or organization // obtaining a copy of the software and accompanying documentation covered by // this license (the "Software") to use, reproduce, display, distribute, // execute, and transmit the Software, and to prepare derivative works of the // Software, and to permit third-parties to whom the Software is furnished to // do so, all subject to the following: // // The copyright notices in the Software and this entire statement, including // the above license grant, this restriction and the following disclaimer, // must be included in all copies of the Software, in whole or in part, and // all derivative works of the Software, unless such copies or derivative // works are solely in the form of machine-executable object code generated by // a source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //------------------------------------------------------------------------------ // Tinyformat: A minimal type safe printf replacement // // tinyformat.h is a type safe printf replacement library in a single C++ // header file. Design goals include: // // * Type safety and extensibility for user defined types. // * C99 printf() compatibility, to the extent possible using std::ostream // * Simplicity and minimalism. A single header file to include and distribute // with your projects. // * Augment rather than replace the standard stream formatting mechanism // * C++98 support, with optional C++11 niceties // // // Main interface example usage // ---------------------------- // // To print a date to std::cout: // // std::string weekday = "Wednesday"; // const char* month = "July"; // size_t day = 27; // long hour = 14; // int min = 44; // // tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min); // // The strange types here emphasize the type safety of the interface; it is // possible to print a std::string using the "%s" conversion, and a // size_t using the "%d" conversion. A similar result could be achieved // using either of the tfm::format() functions. One prints on a user provided // stream: // // tfm::format(std::cerr, "%s, %s %d, %.2d:%.2d\n", // weekday, month, day, hour, min); // // The other returns a std::string: // // std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n", // weekday, month, day, hour, min); // std::cout << date; // // These are the three primary interface functions. There is also a // convenience function printfln() which appends a newline to the usual result // of printf() for super simple logging. // // // User defined format functions // ----------------------------- // // Simulating variadic templates in C++98 is pretty painful since it requires // writing out the same function for each desired number of arguments. To make // this bearable tinyformat comes with a set of macros which are used // internally to generate the API, but which may also be used in user code. // // The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and // TINYFORMAT_PASSARGS(n) will generate a list of n argument types, // type/name pairs and argument names respectively when called with an integer // n between 1 and 16. We can use these to define a macro which generates the // desired user defined function with n arguments. To generate all 16 user // defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an // example, see the implementation of printf() at the end of the source file. // // Sometimes it's useful to be able to pass a list of format arguments through // to a non-template function. The FormatList class is provided as a way to do // this by storing the argument list in a type-opaque way. Continuing the // example from above, we construct a FormatList using makeFormatList(): // // FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, // min); // // The format list can now be passed into any non-template function and used // via a call to the vformat() function: // // tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList); // // // Additional API information // -------------------------- // // Error handling: Define TINYFORMAT_ERROR to customize the error handling for // format strings which are unsupported or have the wrong number of format // specifiers (calls assert() by default). // // User defined types: Uses operator<< for user defined types by default. // Overload formatValue() for more control. #ifndef TINYFORMAT_H_INCLUDED #define TINYFORMAT_H_INCLUDED namespace tinyformat {} //------------------------------------------------------------------------------ // Config section. Customize to your liking! // Namespace alias to encourage brevity namespace tfm = tinyformat; // Error handling; calls assert() by default. -#define TINYFORMAT_ERROR(reasonString) throw std::runtime_error(reasonString) +#define TINYFORMAT_ERROR(reasonString) \ + throw tinyformat::format_error(reasonString) // Define for C++11 variadic templates which make the code shorter & more // general. If you don't define this, C++11 support is autodetected below. #define TINYFORMAT_USE_VARIADIC_TEMPLATES //------------------------------------------------------------------------------ // Implementation details. #include #include #include #include #include #ifndef TINYFORMAT_ERROR #define TINYFORMAT_ERROR(reason) assert(0 && reason) #endif #if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) && \ !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES) #ifdef __GXX_EXPERIMENTAL_CXX0X__ #define TINYFORMAT_USE_VARIADIC_TEMPLATES #endif #endif #if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201 // std::showpos is broken on old libstdc++ as provided with OSX. See // http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html #define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND #endif #ifdef __APPLE__ // Workaround OSX linker warning: Xcode uses different default symbol // visibilities for static libs vs executables (see issue #25) #define TINYFORMAT_HIDDEN __attribute__((visibility("hidden"))) #else #define TINYFORMAT_HIDDEN #endif namespace tinyformat { +class format_error : public std::runtime_error { +public: + format_error(const std::string &what) : std::runtime_error(what) {} +}; + //------------------------------------------------------------------------------ namespace detail { // Test whether type T1 is convertible to type T2 template struct is_convertible { private: // two types of different size struct fail { char dummy[2]; }; struct succeed { char dummy; }; // Try to convert a T1 to a T2 by plugging into tryConvert static fail tryConvert(...); static succeed tryConvert(const T2 &); static const T1 &makeT1(); public: #ifdef _MSC_VER // Disable spurious loss of precision warnings in tryConvert(makeT1()) #pragma warning(push) #pragma warning(disable : 4244) #pragma warning(disable : 4267) #endif // Standard trick: the (...) version of tryConvert will be chosen from // the overload set only if the version taking a T2 doesn't match. Then // we compare the sizes of the return types to check which function // matched. Very neat, in a disgusting kind of way :) static const bool value = sizeof(tryConvert(makeT1())) == sizeof(succeed); #ifdef _MSC_VER #pragma warning(pop) #endif }; // Detect when a type is not a wchar_t string template struct is_wchar { typedef int tinyformat_wchar_is_not_supported; }; template <> struct is_wchar {}; template <> struct is_wchar {}; template struct is_wchar {}; template struct is_wchar {}; // Format the value by casting to type fmtT. This default implementation // should never be called. template ::value> struct formatValueAsType { static void invoke(std::ostream & /*out*/, const T & /*value*/) { assert(0); } }; // Specialized version for types that can actually be converted to fmtT, as // indicated by the "convertible" template parameter. template struct formatValueAsType { static void invoke(std::ostream &out, const T &value) { out << static_cast(value); } }; #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND template ::value> struct formatZeroIntegerWorkaround { static bool invoke(std::ostream & /**/, const T & /**/) { return false; } }; template struct formatZeroIntegerWorkaround { static bool invoke(std::ostream &out, const T &value) { if (static_cast(value) == 0 && out.flags() & std::ios::showpos) { out << "+0"; return true; } return false; } }; #endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND // Convert an arbitrary type to integer. The version with convertible=false // throws an error. template ::value> struct convertToInt { static int invoke(const T & /*value*/) { TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to " "integer for use as variable width or precision"); return 0; } }; // Specialization for convertToInt when conversion is possible template struct convertToInt { static int invoke(const T &value) { return static_cast(value); } }; // Format at most ntrunc characters to the given stream. template inline void formatTruncated(std::ostream &out, const T &value, int ntrunc) { std::ostringstream tmp; tmp << value; std::string result = tmp.str(); out.write(result.c_str(), (std::min)(ntrunc, static_cast(result.size()))); } #define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \ inline void formatTruncated(std::ostream &out, type *value, int ntrunc) { \ std::streamsize len = 0; \ while (len < ntrunc && value[len] != 0) \ ++len; \ out.write(value, len); \ } // Overload for const char* and char*. Could overload for signed & unsigned // char too, but these are technically unneeded for printf compatibility. TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char) TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char) #undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR } // namespace detail //------------------------------------------------------------------------------ // Variable formatting functions. May be overridden for user-defined types if // desired. /// Format a value into a stream, delegating to operator<< by default. /// /// Users may override this for their own types. When this function is called, /// the stream flags will have been modified according to the format string. /// The format specification is provided in the range [fmtBegin, fmtEnd). For /// truncating conversions, ntrunc is set to the desired maximum number of /// characters, for example "%.7s" calls formatValue with ntrunc = 7. /// /// By default, formatValue() uses the usual stream insertion operator /// operator<< to format the type T, with special cases for the %c and %p /// conversions. template inline void formatValue(std::ostream &out, const char * /*fmtBegin*/, const char *fmtEnd, int ntrunc, const T &value) { #ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS // Since we don't support printing of wchar_t using "%ls", make it fail at // compile time in preference to printing as a void* at runtime. typedef typename detail::is_wchar::tinyformat_wchar_is_not_supported DummyType; (void)DummyType(); // avoid unused type warning with gcc-4.8 #endif // The mess here is to support the %c and %p conversions: if these // conversions are active we try to convert the type to a char or const // void* respectively and format that instead of the value itself. For the // %p conversion it's important to avoid dereferencing the pointer, which // could otherwise lead to a crash when printing a dangling (const char*). const bool canConvertToChar = detail::is_convertible::value; const bool canConvertToVoidPtr = detail::is_convertible::value; if (canConvertToChar && *(fmtEnd - 1) == 'c') detail::formatValueAsType::invoke(out, value); else if (canConvertToVoidPtr && *(fmtEnd - 1) == 'p') detail::formatValueAsType::invoke(out, value); #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND else if (detail::formatZeroIntegerWorkaround::invoke(out, value)) /**/ ; #endif else if (ntrunc >= 0) { // Take care not to overread C strings in truncating conversions like // "%.4s" where at most 4 characters may be read. detail::formatTruncated(out, value, ntrunc); } else out << value; } // Overloaded version for char types to support printing as an integer #define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \ inline void formatValue(std::ostream &out, const char * /*fmtBegin*/, \ const char *fmtEnd, int /**/, charType value) { \ switch (*(fmtEnd - 1)) { \ case 'u': \ case 'd': \ case 'i': \ case 'o': \ case 'X': \ case 'x': \ out << static_cast(value); \ break; \ default: \ out << value; \ break; \ } \ } // per 3.9.1: char, signed char and uint8_t are all distinct types TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char) TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char) TINYFORMAT_DEFINE_FORMATVALUE_CHAR(uint8_t) #undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR //------------------------------------------------------------------------------ // Tools for emulating variadic templates in C++98. The basic idea here is // stolen from the boost preprocessor metaprogramming library and cut down to // be just general enough for what we need. #define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_##n #define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_##n #define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_##n #define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_##n // To keep it as transparent as possible, the macros below have been generated // using python via the excellent cog.py code generation script. This avoids // the need for a bunch of complex (but more general) preprocessor tricks as // used in boost.preprocessor. // // To rerun the code generation in place, use `cog.py -r tinyformat.h` // (see http://nedbatchelder.com/code/cog). Alternatively you can just create // extra versions by hand. /*[[[cog maxParams = 16 def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1): for j in range(startInd,maxParams+1): list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)]) cog.outl(lineTemplate % {'j':j, 'list':list}) makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s', 'class T%(i)d') cog.outl() makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s', 'const T%(i)d& v%(i)d') cog.outl() makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d') cog.outl() cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1') makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s', 'v%(i)d', startInd = 2) cog.outl() cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' + ' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)])) ]]]*/ #define TINYFORMAT_ARGTYPES_1 class T1 #define TINYFORMAT_ARGTYPES_2 class T1, class T2 #define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3 #define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4 #define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5 #define TINYFORMAT_ARGTYPES_6 \ class T1, class T2, class T3, class T4, class T5, class T6 #define TINYFORMAT_ARGTYPES_7 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7 #define TINYFORMAT_ARGTYPES_8 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7, \ class T8 #define TINYFORMAT_ARGTYPES_9 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7, \ class T8, class T9 #define TINYFORMAT_ARGTYPES_10 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7, \ class T8, class T9, class T10 #define TINYFORMAT_ARGTYPES_11 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7, \ class T8, class T9, class T10, class T11 #define TINYFORMAT_ARGTYPES_12 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7, \ class T8, class T9, class T10, class T11, class T12 #define TINYFORMAT_ARGTYPES_13 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7, \ class T8, class T9, class T10, class T11, class T12, class T13 #define TINYFORMAT_ARGTYPES_14 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7, \ class T8, class T9, class T10, class T11, class T12, class T13, \ class T14 #define TINYFORMAT_ARGTYPES_15 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7, \ class T8, class T9, class T10, class T11, class T12, class T13, \ class T14, class T15 #define TINYFORMAT_ARGTYPES_16 \ class T1, class T2, class T3, class T4, class T5, class T6, class T7, \ class T8, class T9, class T10, class T11, class T12, class T13, \ class T14, class T15, class T16 #define TINYFORMAT_VARARGS_1 const T1 &v1 #define TINYFORMAT_VARARGS_2 const T1 &v1, const T2 &v2 #define TINYFORMAT_VARARGS_3 const T1 &v1, const T2 &v2, const T3 &v3 #define TINYFORMAT_VARARGS_4 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4 #define TINYFORMAT_VARARGS_5 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5 #define TINYFORMAT_VARARGS_6 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6 #define TINYFORMAT_VARARGS_7 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7 #define TINYFORMAT_VARARGS_8 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7, const T8 &v8 #define TINYFORMAT_VARARGS_9 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9 #define TINYFORMAT_VARARGS_10 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10 #define TINYFORMAT_VARARGS_11 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, \ const T10 &v10, const T11 &v11 #define TINYFORMAT_VARARGS_12 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, \ const T10 &v10, const T11 &v11, const T12 &v12 #define TINYFORMAT_VARARGS_13 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, \ const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13 #define TINYFORMAT_VARARGS_14 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, \ const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13, \ const T14 &v14 #define TINYFORMAT_VARARGS_15 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, \ const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13, \ const T14 &v14, const T15 &v15 #define TINYFORMAT_VARARGS_16 \ const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \ const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, \ const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13, \ const T14 &v14, const T15 &v15, const T16 &v16 #define TINYFORMAT_PASSARGS_1 v1 #define TINYFORMAT_PASSARGS_2 v1, v2 #define TINYFORMAT_PASSARGS_3 v1, v2, v3 #define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4 #define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5 #define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6 #define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7 #define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8 #define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9 #define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 #define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 #define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 #define TINYFORMAT_PASSARGS_13 \ v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 #define TINYFORMAT_PASSARGS_14 \ v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 #define TINYFORMAT_PASSARGS_15 \ v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 #define TINYFORMAT_PASSARGS_16 \ v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 #define TINYFORMAT_PASSARGS_TAIL_1 #define TINYFORMAT_PASSARGS_TAIL_2 , v2 #define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3 #define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4 #define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5 #define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6 #define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7 #define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8 #define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9 #define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10 #define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 #define TINYFORMAT_PASSARGS_TAIL_12 \ , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 #define TINYFORMAT_PASSARGS_TAIL_13 \ , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 #define TINYFORMAT_PASSARGS_TAIL_14 \ , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 #define TINYFORMAT_PASSARGS_TAIL_15 \ , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 #define TINYFORMAT_PASSARGS_TAIL_16 \ , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 #define TINYFORMAT_FOREACH_ARGNUM(m) \ m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) \ m(15) m(16) //[[[end]]] namespace detail { // Type-opaque holder for an argument to format(), with associated actions // on the type held as explicit function pointers. This allows FormatArg's // for each argument to be allocated as a homogenous array inside FormatList // whereas a naive implementation based on inheritance does not. class FormatArg { public: FormatArg() : m_value(nullptr), m_formatImpl(nullptr), m_toIntImpl(nullptr) {} template explicit FormatArg(const T &value) : m_value(static_cast(&value)), m_formatImpl(&formatImpl), m_toIntImpl(&toIntImpl) {} void format(std::ostream &out, const char *fmtBegin, const char *fmtEnd, int ntrunc) const { assert(m_value); assert(m_formatImpl); m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value); } int toInt() const { assert(m_value); assert(m_toIntImpl); return m_toIntImpl(m_value); } private: template TINYFORMAT_HIDDEN static void formatImpl(std::ostream &out, const char *fmtBegin, const char *fmtEnd, int ntrunc, const void *value) { formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast(value)); } template TINYFORMAT_HIDDEN static int toIntImpl(const void *value) { return convertToInt::invoke(*static_cast(value)); } const void *m_value; void (*m_formatImpl)(std::ostream &out, const char *fmtBegin, const char *fmtEnd, int ntrunc, const void *value); int (*m_toIntImpl)(const void *value); }; // Parse and return an integer from the string c, as atoi() // On return, c is set to one past the end of the integer. inline int parseIntAndAdvance(const char *&c) { int i = 0; for (; *c >= '0' && *c <= '9'; ++c) i = 10 * i + (*c - '0'); return i; } // Print literal part of format string and return next format spec position. // // Skips over any occurrences of '%%', printing a literal '%' to the output. // The position of the first % character of the next nontrivial format spec // is returned, or the end of string. inline const char *printFormatStringLiteral(std::ostream &out, const char *fmt) { const char *c = fmt; for (;; ++c) { switch (*c) { case '\0': out.write(fmt, c - fmt); return c; case '%': out.write(fmt, c - fmt); if (*(c + 1) != '%') return c; // for "%%", tack trailing % onto next literal section. fmt = ++c; break; default: break; } } } // Parse a format string and set the stream state accordingly. // // The format mini-language recognized here is meant to be the one from C99, // with the form "%[flags][width][.precision][length]type". // // Formatting options which can't be natively represented using the ostream // state are returned in spacePadPositive (for space padded positive // numbers) and ntrunc (for truncating conversions). argIndex is incremented // if necessary to pull out variable width and precision. The function // returns a pointer to the character after the end of the current format // spec. inline const char * streamStateFromFormat(std::ostream &out, bool &spacePadPositive, int &ntrunc, const char *fmtStart, const detail::FormatArg *formatters, int &argIndex, int numFormatters) { if (*fmtStart != '%') { TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in " "format string"); return fmtStart; } // Reset stream state to defaults. out.width(0); out.precision(6); out.fill(' '); // Reset most flags; ignore irrelevant unitbuf & skipws. out.unsetf(std::ios::adjustfield | std::ios::basefield | std::ios::floatfield | std::ios::showbase | std::ios::boolalpha | std::ios::showpoint | std::ios::showpos | std::ios::uppercase); bool precisionSet = false; bool widthSet = false; int widthExtra = 0; const char *c = fmtStart + 1; // 1) Parse flags for (;; ++c) { switch (*c) { case '#': out.setf(std::ios::showpoint | std::ios::showbase); continue; case '0': // overridden by left alignment ('-' flag) if (!(out.flags() & std::ios::left)) { // Use internal padding so that numeric values are // formatted correctly, eg -00010 rather than 000-10 out.fill('0'); out.setf(std::ios::internal, std::ios::adjustfield); } continue; case '-': out.fill(' '); out.setf(std::ios::left, std::ios::adjustfield); continue; case ' ': // overridden by show positive sign, '+' flag. if (!(out.flags() & std::ios::showpos)) spacePadPositive = true; continue; case '+': out.setf(std::ios::showpos); spacePadPositive = false; widthExtra = 1; continue; default: break; } break; } // 2) Parse width if (*c >= '0' && *c <= '9') { widthSet = true; out.width(parseIntAndAdvance(c)); } if (*c == '*') { widthSet = true; int width = 0; if (argIndex < numFormatters) width = formatters[argIndex++].toInt(); else TINYFORMAT_ERROR( "tinyformat: Not enough arguments to read variable width"); if (width < 0) { // negative widths correspond to '-' flag set out.fill(' '); out.setf(std::ios::left, std::ios::adjustfield); width = -width; } out.width(width); ++c; } // 3) Parse precision if (*c == '.') { ++c; int precision = 0; if (*c == '*') { ++c; if (argIndex < numFormatters) precision = formatters[argIndex++].toInt(); else TINYFORMAT_ERROR("tinyformat: Not enough arguments to read " "variable precision"); } else { if (*c >= '0' && *c <= '9') { precision = parseIntAndAdvance(c); } else if (*c == '-') { // negative precisions ignored, treated as zero. parseIntAndAdvance(++c); } } out.precision(precision); precisionSet = true; } // 4) Ignore any C99 length modifier while (*c == 'l' || *c == 'h' || *c == 'L' || *c == 'j' || *c == 'z' || *c == 't') ++c; // 5) We're up to the conversion specifier character. // Set stream flags based on conversion specifier (thanks to the // boost::format class for forging the way here). bool intConversion = false; switch (*c) { case 'u': case 'd': case 'i': out.setf(std::ios::dec, std::ios::basefield); intConversion = true; break; case 'o': out.setf(std::ios::oct, std::ios::basefield); intConversion = true; break; case 'X': out.setf(std::ios::uppercase); // FALLTHROUGH case 'x': case 'p': out.setf(std::ios::hex, std::ios::basefield); intConversion = true; break; case 'E': out.setf(std::ios::uppercase); // FALLTHROUGH case 'e': out.setf(std::ios::scientific, std::ios::floatfield); out.setf(std::ios::dec, std::ios::basefield); break; case 'F': out.setf(std::ios::uppercase); // FALLTHROUGH case 'f': out.setf(std::ios::fixed, std::ios::floatfield); break; case 'G': out.setf(std::ios::uppercase); // FALLTHROUGH case 'g': out.setf(std::ios::dec, std::ios::basefield); // As in boost::format, let stream decide float format. out.flags(out.flags() & ~std::ios::floatfield); break; case 'a': case 'A': TINYFORMAT_ERROR("tinyformat: the %a and %A conversion specs " "are not supported"); break; case 'c': // Handled as special case inside formatValue() break; case 's': if (precisionSet) ntrunc = static_cast(out.precision()); // Make %s print booleans as "true" and "false" out.setf(std::ios::boolalpha); break; case 'n': // Not supported - will cause problems! TINYFORMAT_ERROR( "tinyformat: %n conversion spec not supported"); break; case '\0': TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly " "terminated by end of string"); return c; default: break; } if (intConversion && precisionSet && !widthSet) { // "precision" for integers gives the minimum number of digits (to // be padded with zeros on the left). This isn't really supported by // the iostreams, but we can approximately simulate it with the // width if the width isn't otherwise used. out.width(out.precision() + widthExtra); out.setf(std::ios::internal, std::ios::adjustfield); out.fill('0'); } return c + 1; } //------------------------------------------------------------------------------ inline void formatImpl(std::ostream &out, const char *fmt, const detail::FormatArg *formatters, int numFormatters) { // Saved stream state std::streamsize origWidth = out.width(); std::streamsize origPrecision = out.precision(); std::ios::fmtflags origFlags = out.flags(); char origFill = out.fill(); for (int argIndex = 0; argIndex < numFormatters; ++argIndex) { // Parse the format string fmt = printFormatStringLiteral(out, fmt); bool spacePadPositive = false; int ntrunc = -1; const char *fmtEnd = streamStateFromFormat(out, spacePadPositive, ntrunc, fmt, formatters, argIndex, numFormatters); if (argIndex >= numFormatters) { // Check args remain after reading any variable width/precision TINYFORMAT_ERROR("tinyformat: Not enough format arguments"); return; } const FormatArg &arg = formatters[argIndex]; // Format the arg into the stream. if (!spacePadPositive) arg.format(out, fmt, fmtEnd, ntrunc); else { // The following is a special case with no direct correspondence // between stream formatting and the printf() behaviour. // Simulate it crudely by formatting into a temporary string // stream and munging the resulting string. std::ostringstream tmpStream; tmpStream.copyfmt(out); tmpStream.setf(std::ios::showpos); arg.format(tmpStream, fmt, fmtEnd, ntrunc); // allocates... yuck. std::string result = tmpStream.str(); for (size_t i = 0, iend = result.size(); i < iend; ++i) if (result[i] == '+') result[i] = ' '; out << result; } fmt = fmtEnd; } // Print remaining part of format string. fmt = printFormatStringLiteral(out, fmt); if (*fmt != '\0') TINYFORMAT_ERROR( "tinyformat: Too many conversion specifiers in format string"); // Restore stream state out.width(origWidth); out.precision(origPrecision); out.flags(origFlags); out.fill(origFill); } } // namespace detail /// List of template arguments format(), held in a type-opaque way. /// /// A const reference to FormatList (typedef'd as FormatListRef) may be /// conveniently used to pass arguments to non-template functions: All type /// information has been stripped from the arguments, leaving just enough of a /// common interface to perform formatting as required. class FormatList { public: FormatList(detail::FormatArg *formatters, int N) : m_formatters(formatters), m_N(N) {} friend void vformat(std::ostream &out, const char *fmt, const FormatList &list); private: const detail::FormatArg *m_formatters; int m_N; }; /// Reference to type-opaque format list for passing to vformat() typedef const FormatList &FormatListRef; namespace detail { // Format list subclass with fixed storage to avoid dynamic allocation template class FormatListN : public FormatList { public: #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES template explicit FormatListN(const Args &... args) : FormatList(&m_formatterStore[0], N), m_formatterStore{ FormatArg(args)...} { static_assert(sizeof...(args) == N, "Number of args must be N"); } #else // C++98 version void init(int) {} #define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \ \ template \ explicit FormatListN(TINYFORMAT_VARARGS(n)) \ : FormatList(&m_formatterStore[0], n) { \ assert(n == N); \ init(0, TINYFORMAT_PASSARGS(n)); \ } \ \ template \ void init(int i, TINYFORMAT_VARARGS(n)) { \ m_formatterStore[i] = FormatArg(v1); \ init(i + 1 TINYFORMAT_PASSARGS_TAIL(n)); \ } TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR) #undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR #endif private: FormatArg m_formatterStore[N]; }; // Special 0-arg version - MSVC says zero-sized C array in struct is // nonstandard. template <> class FormatListN<0> : public FormatList { public: FormatListN() : FormatList(0, 0) {} }; } // namespace detail //------------------------------------------------------------------------------ // Primary API functions #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES /// Make type-agnostic format list from list of template arguments. /// /// The exact return type of this function is an implementation detail and /// shouldn't be relied upon. Instead it should be stored as a FormatListRef: /// /// FormatListRef formatList = makeFormatList( /*...*/ ); template detail::FormatListN makeFormatList(const Args &... args) { return detail::FormatListN(args...); } #else // C++98 version inline detail::FormatListN<0> makeFormatList() { return detail::FormatListN<0>(); } #define TINYFORMAT_MAKE_MAKEFORMATLIST(n) \ template \ detail::FormatListN makeFormatList(TINYFORMAT_VARARGS(n)) { \ return detail::FormatListN(TINYFORMAT_PASSARGS(n)); \ } TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST) #undef TINYFORMAT_MAKE_MAKEFORMATLIST #endif /// Format list of arguments to the stream according to the given format string. /// /// The name vformat() is chosen for the semantic similarity to vprintf(): the /// list of format arguments is held in a single function argument. inline void vformat(std::ostream &out, const char *fmt, FormatListRef list) { detail::formatImpl(out, fmt, list.m_formatters, list.m_N); } #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES /// Format list of arguments to the stream according to given format string. template void format(std::ostream &out, const char *fmt, const Args &... args) { vformat(out, fmt, makeFormatList(args...)); } /// Format list of arguments according to the given format string and return the /// result as a string. template std::string format(const char *fmt, const Args &... args) { std::ostringstream oss; format(oss, fmt, args...); return oss.str(); } /// Format list of arguments to std::cout, according to the given format string template void printf(const char *fmt, const Args &... args) { format(std::cout, fmt, args...); } template void printfln(const char *fmt, const Args &... args) { format(std::cout, fmt, args...); std::cout << '\n'; } #else // C++98 version inline void format(std::ostream &out, const char *fmt) { vformat(out, fmt, makeFormatList()); } inline std::string format(const char *fmt) { std::ostringstream oss; format(oss, fmt); return oss.str(); } inline void printf(const char *fmt) { format(std::cout, fmt); } inline void printfln(const char *fmt) { format(std::cout, fmt); std::cout << '\n'; } #define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \ \ template \ void format(std::ostream &out, const char *fmt, TINYFORMAT_VARARGS(n)) { \ vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n))); \ } \ \ template \ std::string format(const char *fmt, TINYFORMAT_VARARGS(n)) { \ std::ostringstream oss; \ format(oss, fmt, TINYFORMAT_PASSARGS(n)); \ return oss.str(); \ } \ \ template \ void printf(const char *fmt, TINYFORMAT_VARARGS(n)) { \ format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ } \ \ template \ void printfln(const char *fmt, TINYFORMAT_VARARGS(n)) { \ format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ std::cout << '\n'; \ } TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS) #undef TINYFORMAT_MAKE_FORMAT_FUNCS #endif // Added for Bitcoin Core template std::string format(const std::string &fmt, const Args &... args) { std::ostringstream oss; format(oss, fmt.c_str(), args...); return oss.str(); } } // namespace tinyformat #define strprintf tfm::format #endif // TINYFORMAT_H_INCLUDED diff --git a/src/util/system.h b/src/util/system.h index 7b756ad67..3e165d239 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -1,392 +1,392 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. /** * Server/client environment: argument handling, config file parsing, * thread wrappers, startup time */ #ifndef BITCOIN_UTIL_SYSTEM_H #define BITCOIN_UTIL_SYSTEM_H #if defined(HAVE_CONFIG_H) #include #endif #include #include #include #include #include #include #include #include #include // for boost::thread_interrupted #include #include #include #include #include #include #include #include #include // Application startup time (used for uptime calculation) int64_t GetStartupTime(); extern const char *const BITCOIN_CONF_FILENAME; extern const char *const BITCOIN_PID_FILENAME; /** Translate a message to the native language of the user. */ const extern std::function G_TRANSLATION_FUN; /** * Translation function. * If no translation function is set, simply return the input. */ inline std::string _(const char *psz) { return G_TRANSLATION_FUN ? (G_TRANSLATION_FUN)(psz) : psz; } void SetupEnvironment(); bool SetupNetworking(); template bool error(const char *fmt, const Args &... args) { - LogPrintf("ERROR: " + tfm::format(fmt, args...) + "\n"); + LogPrintf("ERROR: %s\n", tfm::format(fmt, args...)); return false; } void PrintExceptionContinue(const std::exception *pex, const char *pszThread); bool FileCommit(FILE *file); bool TruncateFile(FILE *file, unsigned int length); int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); bool RenameOver(fs::path src, fs::path dest); bool LockDirectory(const fs::path &directory, const std::string lockfile_name, bool probe_only = false); bool DirIsWritable(const fs::path &directory); bool CheckDiskSpace(const fs::path &dir, uint64_t additional_bytes = 0); /** * Release all directory locks. This is used for unit testing only, at runtime * the global destructor will take care of the locks. */ void ReleaseDirectoryLocks(); bool TryCreateDirectories(const fs::path &p); fs::path GetDefaultDataDir(); // The blocks directory is always net specific. const fs::path &GetBlocksDir(); const fs::path &GetDataDir(bool fNetSpecific = true); void ClearDatadirCache(); fs::path GetConfigFile(const std::string &confPath); #ifndef WIN32 fs::path GetPidFile(); void CreatePidFile(const fs::path &path, pid_t pid); #endif #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif void runCommand(const std::string &strCommand); NODISCARD bool ParseKeyValue(std::string &key, std::string &val); /** * Most paths passed as configuration arguments are treated as relative to * the datadir if they are not absolute. * * @param path The path to be conditionally prefixed with datadir. * @param net_specific Forwarded to GetDataDir(). * @return The normalized path. */ fs::path AbsPathForConfigVal(const fs::path &path, bool net_specific = true); inline bool IsSwitchChar(char c) { #ifdef WIN32 return c == '-' || c == '/'; #else return c == '-'; #endif } enum class OptionsCategory { OPTIONS, CONNECTION, WALLET, WALLET_DEBUG_TEST, ZMQ, DEBUG_TEST, CHAINPARAMS, NODE_RELAY, BLOCK_CREATION, RPC, GUI, COMMANDS, REGISTER_COMMANDS, // Always the last option to avoid printing these in the help HIDDEN, }; class ArgsManager { protected: friend class ArgsManagerHelper; struct Arg { std::string m_help_param; std::string m_help_text; bool m_debug_only; Arg(const std::string &help_param, const std::string &help_text, bool debug_only) : m_help_param(help_param), m_help_text(help_text), m_debug_only(debug_only){}; }; mutable CCriticalSection cs_args; std::map> m_override_args GUARDED_BY(cs_args); std::map> m_config_args GUARDED_BY(cs_args); std::string m_network GUARDED_BY(cs_args); std::set m_network_only_args GUARDED_BY(cs_args); std::map> m_available_args GUARDED_BY(cs_args); bool ReadConfigStream(std::istream &stream, std::string &error, bool ignore_invalid_keys = false); public: ArgsManager(); /** * Select the network in use */ void SelectConfigNetwork(const std::string &network); NODISCARD bool ParseParameters(int argc, const char *const argv[], std::string &error); bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys = false); /** * Log warnings for options in m_section_only_args when they are specified * in the default section but not overridden on the command line or in a * network-specific section in the config file. */ void WarnForSectionOnlyArgs(); /** * Return a vector of strings of the given argument * * @param strArg Argument to get (e.g. "-foo") * @return command-line arguments */ std::vector GetArgs(const std::string &strArg) const; /** * Return true if the given argument has been manually set. * * @param strArg Argument to get (e.g. "-foo") * @return true if the argument has been set */ bool IsArgSet(const std::string &strArg) const; /** * Return true if the argument was originally passed as a negated option, * i.e. -nofoo. * * @param strArg Argument to get (e.g. "-foo") * @return true if the argument was passed negated */ bool IsArgNegated(const std::string &strArg) const; /** * Return string argument or default value. * * @param strArg Argument to get (e.g. "-foo") * @param default (e.g. "1") * @return command-line argument or default value */ std::string GetArg(const std::string &strArg, const std::string &strDefault) const; /** * Return integer argument or default value. * * @param strArg Argument to get (e.g. "-foo") * @param default (e.g. 1) * @return command-line argument (0 if invalid number) or default value */ int64_t GetArg(const std::string &strArg, int64_t nDefault) const; /** * Return boolean argument or default value. * * @param strArg Argument to get (e.g. "-foo") * @param default (true or false) * @return command-line argument or default value */ bool GetBoolArg(const std::string &strArg, bool fDefault) const; /** * Set an argument if it doesn't already have a value. * * @param strArg Argument to set (e.g. "-foo") * @param strValue Value (e.g. "1") * @return true if argument gets set, false if it already had a value */ bool SoftSetArg(const std::string &strArg, const std::string &strValue); /** * Set a boolean argument if it doesn't already have a value. * * @param strArg Argument to set (e.g. "-foo") * @param fValue Value (e.g. false) * @return true if argument gets set, false if it already had a value */ bool SoftSetBoolArg(const std::string &strArg, bool fValue); // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already // been set. Also called directly in testing. void ForceSetArg(const std::string &strArg, const std::string &strValue); // Forces a multi arg setting, used only in testing void ForceSetMultiArg(const std::string &strArg, const std::string &strValue); /** * Looks for -regtest, -testnet and returns the appropriate BIP70 chain * name. * @return CBaseChainParams::MAIN by default; raises runtime error if an * invalid combination is given. */ std::string GetChainName() const; /** * Add argument */ void AddArg(const std::string &name, const std::string &help, const bool debug_only, const OptionsCategory &cat); // Remove an arg setting, used only in testing void ClearArg(const std::string &strArg); /** * Clear available arguments */ void ClearArgs() { LOCK(cs_args); m_available_args.clear(); } /** * Get the help string */ std::string GetHelpMessage() const; /** * Check whether we know of this arg */ bool IsArgKnown(const std::string &key) const; }; extern ArgsManager gArgs; /** * @return true if help has been requested via a command-line arg */ bool HelpRequested(const ArgsManager &args); /** * Format a string to be used as group of options in help messages. * * @param message Group name (e.g. "RPC server options:") * @return the formatted string */ std::string HelpMessageGroup(const std::string &message); /** * Format a string to be used as option description in help messages. * * @param option Option message (e.g. "-rpcuser=") * @param message Option description (e.g. "Username for JSON-RPC connections") * @return the formatted string */ std::string HelpMessageOpt(const std::string &option, const std::string &message); /** * Return the number of physical cores available on the current system. * @note This does not count virtual cores, such as those provided by * HyperThreading when boost is newer than 1.56. */ int GetNumCores(); void RenameThread(const char *name); /** * .. and a wrapper that just calls func once */ template void TraceThread(const char *name, Callable func) { std::string s = strprintf("bitcoin-%s", name); RenameThread(s.c_str()); try { LogPrintf("%s thread start\n", name); func(); LogPrintf("%s thread exit\n", name); } catch (const boost::thread_interrupted &) { LogPrintf("%s thread interrupt\n", name); throw; } catch (const std::exception &e) { PrintExceptionContinue(&e, name); throw; } catch (...) { PrintExceptionContinue(nullptr, name); throw; } } std::string CopyrightHolders(const std::string &strPrefix); namespace util { //! Simplification of std insertion template inline void insert(Tdst &dst, const Tsrc &src) { dst.insert(dst.begin(), src.begin(), src.end()); } template inline void insert(std::set &dst, const Tsrc &src) { dst.insert(src.begin(), src.end()); } #ifdef WIN32 class WinCmdLineArgs { public: WinCmdLineArgs(); ~WinCmdLineArgs(); std::pair get(); private: int argc; char **argv; std::vector args; }; #endif } // namespace util /** * On platforms that support it, tell the kernel the calling thread is * CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details. * * @return The return value of sched_setschedule(), or 1 on systems without * sched_setchedule(). */ int ScheduleBatchPriority(); #endif // BITCOIN_UTIL_SYSTEM_H