diff options
Diffstat (limited to 'contrib/otshell_utils/utils.hpp')
-rw-r--r-- | contrib/otshell_utils/utils.hpp | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/contrib/otshell_utils/utils.hpp b/contrib/otshell_utils/utils.hpp new file mode 100644 index 000000000..6cfd11ee1 --- /dev/null +++ b/contrib/otshell_utils/utils.hpp @@ -0,0 +1,446 @@ +/// @file +/// @author rfree (current maintainer in monero.cc project) +/// @brief various general utils taken from (and relate to) otshell project, including loggiang/debug + +/* See other files here for the LICENCE that applies here. */ + +#include "ccolor.hpp" +#ifndef INCLUDE_OT_NEWCLI_UTILS +#define INCLUDE_OT_NEWCLI_UTILS + +#include "lib_common1.hpp" +#ifdef __unix + #include <unistd.h> +#endif + +#ifndef CFG_WITH_TERMCOLORS + #error "You requested to turn off terminal colors (CFG_WITH_TERMCOLORS), however currently they are hardcoded (this option to turn them off is not yet implemented)." +#endif + +///Macros related to automatic deduction of class name etc; +#define MAKE_CLASS_NAME(NAME) private: static std::string GetObjectName() { return #NAME; } +#define MAKE_STRUCT_NAME(NAME) private: static std::string GetObjectName() { return #NAME; } public: + +namespace nOT { + +namespace nUtils { + +/// @brief general based for my runtime errors +class myexception : public std::runtime_error { + public: + myexception(const char * what); + myexception(const std::string &what); + //virtual ~myexception(); + virtual void Report() const; +}; + +/// @macro Use this macro INJECT_OT_COMMON_USING_NAMESPACE_COMMON_1 as a shortcut for various using std::string etc. +INJECT_OT_COMMON_USING_NAMESPACE_COMMON_1; // <=== namespaces + +// ====================================================================================== +/// text trimming functions (they do mutate the passes string); they trim based on std::isspace. also return it's reference again +/// http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring +std::string & trim(std::string &s); ///< trim text http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring +std::string & ltrim(std::string &s); ///< left trim +std::string & rtrim(std::string &s); ///< right trim + +// ====================================================================================== + +std::string get_current_time(); + +// string conversions +template <class T> +std::string ToStr(const T & obj) { + std::ostringstream oss; + oss << obj; + return oss.str(); +} + +struct cNullstream : std::ostream { + cNullstream() : std::ios(0), std::ostream(0) {} +}; +extern cNullstream g_nullstream; // a stream that does nothing (eats/discards data) +// ========== debug ========== +// _dbg_ignore is moved to global namespace (on purpose) + +// TODO make _dbg_ignore thread-safe everywhere + +extern std::mutex gLoggerGuard; + + + +#define _debug_level_c(CHANNEL,LEVEL,VAR) do { if (_dbg_ignore< LEVEL) { \ + nOT::nUtils::gLoggerGuard.try_lock(); \ + gCurrentLogger.write_stream(LEVEL,CHANNEL) << nOT::nUtils::get_current_time() << ' ' << OT_CODE_STAMP << ' ' << VAR << gCurrentLogger.endline() << std::flush; \ + nOT::nUtils::gLoggerGuard.unlock(); \ + } } while(0) + +#define _debug_level(LEVEL,VAR) _debug_level_c("",LEVEL,VAR) + +#define _dbg3(VAR) _debug_level( 20,VAR) +#define _dbg2(VAR) _debug_level( 30,VAR) +#define _dbg1(VAR) _debug_level( 40,VAR) // details +#define _info(VAR) _debug_level( 50,VAR) // more boring info +#define _note(VAR) _debug_level( 70,VAR) // info +#define _fact(VAR) _debug_level( 75,VAR) // interesting event +#define _mark(VAR) _debug_level( 80,VAR) // marked action +#define _warn(VAR) _debug_level( 90,VAR) // some problem +#define _erro(VAR) _debug_level(100,VAR) // error - report + +#define _dbg3_c(C,VAR) _debug_level_c(C, 20,VAR) +#define _dbg2_c(C,VAR) _debug_level_c(C, 30,VAR) +#define _dbg1_c(C,VAR) _debug_level_c(C, 40,VAR) // details +#define _info_c(C,VAR) _debug_level_c(C, 50,VAR) // more boring info +#define _note_c(C,VAR) _debug_level_c(C, 70,VAR) // info +#define _fact_c(C,VAR) _debug_level_c(C, 75,VAR) // interesting event +#define _mark_c(C,VAR) _debug_level_c(C, 80,VAR) // marked action +#define _warn_c(C,VAR) _debug_level_c(C, 90,VAR) // some problem +#define _erro_c(C,VAR) _debug_level_c(C,100,VAR) // error - report + +// lock // because od VAR +#define _scope_debug_level_c(CHANNEL,LEVEL,VAR) \ + std::ostringstream debug_detail_oss; \ + nOT::nUtils::gLoggerGuard.try_lock(); \ + debug_detail_oss << OT_CODE_STAMP << ' ' << VAR ; \ + nOT::nUtils::nDetail::cDebugScopeGuard debugScopeGuard; \ + if (_dbg_ignore<LEVEL) debugScopeGuard.Assign(CHANNEL,LEVEL, debug_detail_oss.str()); \ + if (_dbg_ignore<LEVEL) _debug_level_c(CHANNEL,LEVEL,debug_detail_oss.str() + " ... begin"); \ + nOT::nUtils::gLoggerGuard.unlock(); +#define _scope_debug_level(LEVEL,VAR) _scope_debug_level_c("",LEVEL,VAR) + +#define _scope_dbg1(VAR) _scope_debug_level( 20,VAR) +#define _scope_dbg2(VAR) _scope_debug_level( 30,VAR) +#define _scope_dbg3(VAR) _scope_debug_level( 40,VAR) // details +#define _scope_info(VAR) _scope_debug_level( 50,VAR) // more boring info +#define _scope_note(VAR) _scope_debug_level( 70,VAR) // info +#define _scope_fact(VAR) _scope_debug_level( 75,VAR) // interesting event +#define _scope_mark(VAR) _scope_debug_level( 80,VAR) // marked action +#define _scope_warn(VAR) _scope_debug_level( 90,VAR) // some problem +#define _scope_erro(VAR) _scope_debug_level( 100,VAR) // error - report + +/*** +@brief do not use this namespace directly, it is implementation detail. +*/ +namespace nDetail { + +/*** +@brief a Debug scope-guard, to log a debug message when current scope is left. Do NOT use this directly, +only use it via the macros like _scope_dbg1 etc. +*/ +class cDebugScopeGuard { + protected: + string mMsg; + int mLevel; + string mChan; + public: + cDebugScopeGuard(); + ~cDebugScopeGuard(); + void Assign(const string &chan, const int level, const string &msg); +}; + +const char* DbgShortenCodeFileName(const char *s); ///< Returns a pointer to some part of the string that was given, skipping directory names, for log/debug + +}; // namespace nDetail + +// ========== logger ========== + +/*** +@brief Class to write debug into. Used it by calling the debug macros _dbg1(...) _info(...) _erro(...) etc, NOT directly! +@author rfree (maintainer) +*/ +class cLogger { + public: + cLogger(); + ~cLogger(); + std::ostream & write_stream(int level); ///< starts a new message on given level (e.g. writes out the icon/tag) and returns stream to output to + std::ostream & write_stream(int level, const std::string & channel); ///< the same but with name of the debug channel + + void setOutStreamFromGlobalOptions(); // set debug level, file etc - according to global Options + void setOutStreamFile(const std::string &fname); // switch to using this file + void setDebugLevel(int level); // change the debug level e.g. to mute debug from now + + std::string icon(int level) const; ///< returns "icon" for given debug level. It is text, might include color controll characters + std::string endline() const; ///< returns string to be written at end of message + + protected: + unique_ptr<std::ofstream> mOutfile; + std::ostream * mStream; ///< pointing only! can point to our own mOutfile, or maye to global null stream + + std::map< std::string , std::ofstream * > mChannels; // the ofstream objects are owned by this class + + int mLevel; ///< current debug level + + std::ostream & SelectOutput(int level, const std::string & channel); + void OpenNewChannel(const std::string & channel); + std::string GetLogBaseDir() const; + + std::map< std::thread::id , int > mThread2Number; // change long thread IDs into a short nice number to show + int mThread2Number_Biggest; // current biggest value held there (biggest key) - works as growing-only counter basically + int Thread2Number(const std::thread::id id); // convert the system's thread id into a nice short our id; make one if new thread +}; + + + +// ==================================================================== +// vector debug + +template <class T> +std::string vectorToStr(const T & v) { + std::ostringstream oss; + for(auto rec: v) { + oss << rec <<","; + } + return oss.str(); +} + +template <class T> +void DisplayVector(std::ostream & out, const std::vector<T> &v, const std::string &delim=" ") { + std::copy( v.begin(), v.end(), std::ostream_iterator<T>(out, delim.c_str()) ); +} + +template <class T> +void EndlDisplayVector(std::ostream & out, const std::vector<T> &v, const std::string &delim=" ") { + out << std::endl; + DisplayVector(out,v,delim); +} + +template <class T> +void DisplayVectorEndl(std::ostream & out, const std::vector<T> &v, const std::string &delim=" ") { + DisplayVector(out,v,delim); + out << std::endl; +} + +template <class T> +void DbgDisplayVector(const std::vector<T> &v, const std::string &delim=" ") { + std::cerr << "["; + std::copy( v.begin(), v.end(), std::ostream_iterator<T>(std::cerr, delim.c_str()) ); + std::cerr << "]"; +} + +string stringToColor(const string &hash); +template <class T, class T2> +void DisplayMap(std::ostream & out, const std::map<T, T2> &m, const std::string &delim=" ") { + auto *no_color = zkr::cc::fore::console; + for(auto var : m) { + out << stringToColor(var.first) << var.first << delim << var.second << no_color << endl; + } + +} + +template <class T, class T2> +void EndlDisplayMap(std::ostream & out, const std::map<T, T2> &m, const std::string &delim=" ") { + out << endl; + for(auto var : m) { + out << var.first << delim << var.second << endl; + } +} + +template <class T, class T2> +void DbgDisplayMap(const std::map<T, T2> &m, const std::string &delim=" ") { + for(auto var : m) { + std::cerr << var.first << delim << var.second << endl; + } +} + + +template <class T> +void DbgDisplayVectorEndl(const std::vector<T> &v, const std::string &delim=" ") { + DbgDisplayVector(v,delim); + std::cerr << std::endl; +} + +void DisplayStringEndl(std::ostream & out, const std::string text); + +bool CheckIfBegins(const std::string & beggining, const std::string & all); +bool CheckIfEnds (std::string const & ending, std::string const & all); +std::string SpaceFromEscape(const std::string &s); +std::string EscapeFromSpace(const std::string &s); +vector<string> WordsThatMatch(const std::string & sofar, const vector<string> & possib); +char GetLastChar(const std::string & str); +std::string GetLastCharIf(const std::string & str); // TODO unicode? +std::string EscapeString(const std::string &s); + + +template <class T> +std::string DbgVector(const std::vector<T> &v, const std::string &delim="|") { + std::ostringstream oss; + oss << "["; + bool first=true; + for(auto vElement : v) { if (!first) oss<<delim; first=false; oss <<vElement ; } + oss << "]"; + //std::copy( v.begin(), v.end(), std::ostream_iterator<T>(oss, delim.c_str()) ); + return oss.str(); +} + +template <class T> +std::ostream & operator<<(std::ostream & os, const map< T, vector<T> > & obj){ + os << "["; + for(auto const & elem : obj) { + os << " [" << elem.first << "=" << DbgVector(elem.second) << "] "; + } + os << "]"; + return os; +} + +template <class T, class T2> +std::string DbgMap(const map<T, T2> & map) { + std::ostringstream oss; + oss << map; + return oss.str(); +} + +// ==================================================================== +// assert + +// ASRT - assert. Name like ASSERT() was too long, and ASS() was just... no. +// Use it like this: ASRT( x>y ); with the semicolon at end, a clever trick forces this syntax :) +#define ASRT(x) do { if (!(x)) nOT::nUtils::Assert(false, OT_CODE_STAMP, #x); } while(0) + +void Assert(bool result, const std::string &stamp, const std::string &condition); + +// ==================================================================== +// advanced string + +const std::string GetMultiline(string endLine = "~"); +vector<string> SplitString(const string & str); + +bool checkPrefix(const string & str, char prefix = '^'); + +// ==================================================================== +// nUse utils + +enum class eSubjectType {Account, Asset, User, Server, Unknown}; + +string SubjectType2String(const eSubjectType & type); +eSubjectType String2SubjectType(const string & type); + +// ==================================================================== +// operation on files + +/// @brief tools related to filesystem +/// @author rfree (maintainer) +class cFilesystemUtils { // if we do not want to use boost in given project (or we could optionally write boost here later) + public: + static bool CreateDirTree(const std::string & dir, bool only_below=false); + static char GetDirSeparator(); // eg '/' or '\' +}; + + +/// @brief utils to e.g. edit a file from console +/// @author rfree (maintainer) +class cEnvUtils { + int fd; + string mFilename; + + void GetTmpTextFile(); + void CloseFile(); + void OpenEditor(); + const string ReadFromTmpFile(); +public: + const string Compose(); + const string ReadFromFile(const string path); +}; +void hintingToTxt(std::fstream & file, string command, vector<string> &commands); +void generateQuestions (std::fstream & file, string command); +void generateAnswers (std::fstream & file, string command, vector<string> &completions); + +// ==================================================================== + +namespace nOper { // nOT::nUtils::nOper +// cool shortcut operators, like vector + vecotr operator working same as string (appending) +// isolated to namespace because it's unorthodox ide to implement this + +using namespace std; + +// TODO use && and move? +template <class T> +vector<T> operator+(const vector<T> &a, const vector<T> &b) { + vector<T> ret = a; + ret.insert( ret.end() , b.begin(), b.end() ); + return ret; +} + +template <class T> +vector<T> operator+(const T &a, const vector<T> &b) { + vector<T> ret(1,a); + ret.insert( ret.end() , b.begin(), b.end() ); + return ret; +} + +template <class T> +vector<T> operator+(const vector<T> &a, const T &b) { + vector<T> b_vector(1,a); + return a + b_vector; +} + +template <class T> +vector<T>& operator+=(vector<T> &a, const vector<T> &b) { + a.insert( a.end() , b.begin(), b.end() ); + return a; +} + +// map +template <class TK,class TV> +map<TK,TV> operator+(const map<TK,TV> &a, const map<TK,TV> &b) { + map<TK,TV> ret = a; + for (const auto & elem : b) { + ret.insert(elem); + } + return ret; +} + + +} // nOT::nUtils::nOper + +// ==================================================================== + +// ==================================================================== + +// Algorithms + +// ==================================================================== +// ==================================================================== + + +/** +@brief Special type that on creation will be initialized to have value INIT given as template argument. +Might be usefull e.g. to express in the declaration of class what will be the default value of member variable +See also http://www.boost.org/doc/libs/1_56_0/libs/utility/value_init.htm +Probably not needed when using boost in your project. +*/ +template <class T, T INIT> +class value_init { + private: + T data; + public: + value_init(); + + T& operator=(const T& v) { data=v; return *this; } + operator T const &() const { return data; } + operator T&() { return data; } +}; + +template <class T, T INIT> +value_init<T, INIT>::value_init() : data(INIT) { } + +}; // namespace nUtils + +}; // namespace nOT + + +// global namespace +extern nOT::nUtils::cLogger gCurrentLogger; ///< The current main logger. Usually do not use it directly, instead use macros like _dbg1 etc + +std::string GetObjectName(); ///< Method to return name of current object; To use in debug; Can be shadowed in your classes. (Might be not used currently) + +const extern int _dbg_ignore; ///< the global _dbg_ignore, but local code (blocks, classes etc) you could shadow it in your code blocks, +// to override debug compile-time setting for given block/class, e.g. to disable debug in one of your methods or increase it there. +// Or to make it runtime by providing a class normal member and editing it in runtime + +#define OT_CODE_STAMP ( nOT::nUtils::ToStr("[") + nOT::nUtils::nDetail::DbgShortenCodeFileName(__FILE__) + nOT::nUtils::ToStr("+") + nOT::nUtils::ToStr(__LINE__) + nOT::nUtils::ToStr(" ") + (GetObjectName()) + nOT::nUtils::ToStr("::") + nOT::nUtils::ToStr(__FUNCTION__) + nOT::nUtils::ToStr("]")) + + + + +#endif + |