clutchlog  0.16
clutchlog.h
Go to the documentation of this file.
1 #pragma once
2 #ifndef CLUTCHLOG_H
3 #define CLUTCHLOG_H
5 
7 #include <ciso646>
8  #ifdef FSEXPERIMENTAL
9  #include <experimental/filesystem>
10  namespace fs = std::experimental::filesystem;
11 #else
12  #include <filesystem>
13  namespace fs = std::filesystem;
14 #endif
15 
16 #include <iostream>
17 #include <sstream>
18 #include <fstream>
19 #include <cassert>
20 #include <cstdlib>
21 #include <string>
22 #include <limits>
23 #include <regex>
24 #include <map>
25 
27 #if __has_include(<execinfo.h>) && __has_include(<stdlib.h>) && __has_include(<libgen.h>)
28  #include <execinfo.h> // execinfo
29  #include <stdlib.h> // getenv
30  #include <libgen.h> // basename
31  #define CLUTCHLOG_HAVE_UNIX_SYSINFO 1
32 #else
33  #define CLUTCHLOG_HAVE_UNIX_SYSINFO 0
34 #endif
35 
37 #if __has_include(<sys/ioctl.h>) && __has_include(<stdio.h>) && __has_include(<unistd.h>)
38  #include <sys/ioctl.h>
39  #include <stdio.h>
40  #include <unistd.h>
41  #define CLUTCHLOG_HAVE_UNIX_SYSIOCTL 1
42 #else
43  #define CLUTCHLOG_HAVE_UNIX_SYSIOCTL 0
44 #endif
45 
46 
47 /**********************************************************************
48  * Enable by default in Debug builds.
49  **********************************************************************/
50 #ifndef WITH_CLUTCHLOG
51  #ifndef NDEBUG
52  #define WITH_CLUTCHLOG
54  #endif
55 #endif
56 
57 /**********************************************************************
58  * Macros definitions
59  **********************************************************************/
60 #ifdef WITH_CLUTCHLOG
61 
65 #ifndef CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG
66  #define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::progress
68 #endif // CLUTCHLOG_DEFAULT_DEPTH_BUILT
69 
76 #define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__
78 
80 #ifndef NDEBUG
81  #define CLUTCHLOGD( LEVEL, WHAT, DEPTH_DELTA ) do { \
82  auto& clutchlog__logger = clutchlog::logger(); \
83  std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
84  clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC, DEPTH_DELTA); \
85  } while(0)
86 #else // not Debug build.
87  #define CLUTCHLOGD( LEVEL, WHAT, DEPTH_DELTA ) do { \
88  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
89  auto& clutchlog__logger = clutchlog::logger(); \
90  std::ostringstream clutchlog__msg ; clutchlog__msg << WHAT; \
91  clutchlog__logger.log(clutchlog::level::LEVEL, clutchlog__msg.str(), CLUTCHLOC, DEPTH_DELTA); \
92  } \
93  } while(0)
94 #endif // NDEBUG
95 
97 #ifndef NDEBUG
98  #define CLUTCHLOG( LEVEL, WHAT ) \
99  CLUTCHLOGD(LEVEL, WHAT, 0)
100 #else // not Debug build.
101  #define CLUTCHLOG( LEVEL, WHAT ) \
102  CLUTCHLOGD(LEVEL, WHAT, 0)
103 #endif // NDEBUG
104 
106 #ifndef NDEBUG
107  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
108  auto& clutchlog__logger = clutchlog::logger(); \
109  clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
110  CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
111  } while(0)
112 #else // not Debug build.
113  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do { \
114  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
115  auto& clutchlog__logger = clutchlog::logger(); \
116  clutchlog__logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), \
117  CLUTCHLOC, FILENAME, CLUTCHDUMP_DEFAULT_SEP); \
118  } \
119  } while(0)
120 #endif // NDEBUG
121 
123 #ifndef NDEBUG
124  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
125  auto& clutchlog__logger = clutchlog::logger(); \
126  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
127  if(clutchlog__scope.matches) { \
128  FUNC(__VA_ARGS__); \
129  } \
130  } while(0)
131 #else // not Debug build.
132  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do { \
133  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
134  auto& clutchlog__logger = clutchlog::logger(); \
135  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
136  if(clutchlog__scope.matches) { \
137  FUNC(__VA_ARGS__); \
138  } \
139  } \
140  } while(0)
141 #endif // NDEBUG
142 
144 #ifndef NDEBUG
145  #define CLUTCHCODE( LEVEL, ... ) do { \
146  auto& clutchlog__logger = clutchlog::logger(); \
147  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
148  if(clutchlog__scope.matches) { \
149  __VA_ARGS__ \
150  } \
151  } while(0)
152 #else // not Debug build.
153  #define CLUTCHCODE( LEVEL, CODE ) do { \
154  if(clutchlog::level::LEVEL <= CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG) { \
155  auto& clutchlog__logger = clutchlog::logger(); \
156  clutchlog::scope_t clutchlog__scope = clutchlog__logger.locate(clutchlog::level::LEVEL, CLUTCHLOC); \
157  if(clutchlog__scope.matches) { \
158  CODE \
159  } \
160  } \
161  } while(0)
162 #endif // NDEBUG
163 
166 #else // not WITH_CLUTCHLOG
167  // Disabled macros can still be called in Release builds.
168  #define CLUTCHLOG( LEVEL, WHAT ) do {/*nothing*/} while(0)
169  #define CLUTCHLOGD( LEVEL, WHAT, DEPTH_DELTA ) do {/*nothing*/} while(0)
170  #define CLUTCHDUMP( LEVEL, CONTAINER, FILENAME ) do {/*nothing*/} while(0)
171  #define CLUTCHFUNC( LEVEL, FUNC, ... ) do {/*nothing*/} while(0)
172  #define CLUTCHCODE( LEVEL, CODE ) do {/*nothing*/} while(0)
173 #endif // WITH_CLUTCHLOG
174 
175 /**********************************************************************
176  * Implementation
177  **********************************************************************/
178 
179 #ifdef WITH_CLUTCHLOG
180 
188 {
189  protected:
190 
195  #ifndef NDEBUG
196  #ifndef CLUTCHLOG_DEFAULT_FORMAT
197  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 // Enables: name, depth and depth_marks
199  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1 // Enables: hfill
200  #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func} @ {file}:{line}\n"
201  #else
202  #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
203  #endif
204  #else
205  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
206  #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg} {hfill} {func} @ {file}:{line}\n"
207  #else
208  #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
209  #endif
210  #endif
211  #endif
212  #else
213  #ifndef CLUTCHLOG_DEFAULT_FORMAT
214  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
216  #define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func}\n"
217  #else
218  #define CLUTCHLOG_DEFAULT_FORMAT "{level_letter} {msg}\t\t\t\t\t{func}\n"
219  #endif
220  #endif
221  #endif
222  static inline std::string default_format = CLUTCHLOG_DEFAULT_FORMAT;
224 
225  #ifndef NDEBUG
226  #ifndef CLUTCHDUMP_DEFAULT_FORMAT
227  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
229  #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"
230  #else
231  #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func} @ {file}:{line}"
232  #endif
233  #endif // CLUTCHDUMP_DEFAULT_FORMAT
234  #else
235  #ifndef CLUTCHDUMP_DEFAULT_FORMAT
236  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
238  #define CLUTCHDUMP_DEFAULT_FORMAT "# [{name}] {level} in {func} (at depth {depth})"
239  #else
240  #define CLUTCHDUMP_DEFAULT_FORMAT "# {level} in {func}"
241  #endif
242  #endif // CLUTCHDUMP_DEFAULT_FORMAT
243  #endif
244  static inline std::string dump_default_format = CLUTCHDUMP_DEFAULT_FORMAT;
246 
247  #ifndef CLUTCHDUMP_DEFAULT_SEP
248  #define CLUTCHDUMP_DEFAULT_SEP "\n"
250  #endif // CLUTCHDUMP_DEFAULT_SEP
251  static inline std::string dump_default_sep = CLUTCHDUMP_DEFAULT_SEP;
253 
254  #ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK
255  #define CLUTCHLOG_DEFAULT_DEPTH_MARK ">"
257  #endif // CLUTCHLOG_DEFAULT_DEPTH_MARK
258  static inline std::string default_depth_mark = CLUTCHLOG_DEFAULT_DEPTH_MARK;
260 
261  #ifndef CLUTCHLOG_STRIP_CALLS
262  #define CLUTCHLOG_STRIP_CALLS 5
264  #endif // CLUTCHLOG_STRIP_CALLS
265  static inline unsigned int default_strip_calls = CLUTCHLOG_STRIP_CALLS;
267 
268  #ifndef CLUTCHLOG_DEFAULT_HFILL_MARK
269  #define CLUTCHLOG_DEFAULT_HFILL_MARK '.'
271  #endif // CLUTCHLOG_DEFAULT_HFILL_MARK
274 
275 
276  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
277  #ifndef CLUTCHLOG_DEFAULT_HFILL_MAX
278  #define CLUTCHLOG_DEFAULT_HFILL_MAX 300
279  #endif
280  #ifndef CLUTCHLOG_DEFAULT_HFILL_MIN
281  #define CLUTCHLOG_DEFAULT_HFILL_MIN 150
282  #endif
283  #endif
284  static inline size_t default_hfill_max = CLUTCHLOG_DEFAULT_HFILL_MAX;
287  static inline size_t default_hfill_min = CLUTCHLOG_DEFAULT_HFILL_MIN;
288 
289  // NOTE: there is no CLUTCHLOG_HFILL_STYLE for defaulting,
290  // but you can still set `hfill_style(...)` on the logger singleton.
291  /* @} DefaultConfig */
292  /* @} */
293 
294 
295  public:
296 
306  static clutchlog& logger()
307  {
308  static clutchlog instance;
309  return instance;
310  }
311 
313  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
314 
316  enum filename {path, base, dir, dirbase, stem, dirstem};
317 
379  class fmt {
380  public:
382  enum class ansi {
384  colors_16 = -1, // Not supposed to be casted.
386  colors_256 = 5, // Casted as short in color::operator<<.
388  colors_16M = 2 // Casted as short in color::operator<<
389  } mode;
390 
392  enum class typo {
393  reset = 0,
394  bold = 1,
395  underline = 4,
396  inverse = 7,
397  none = -1
398  } style;
399 
402  enum class fg {
404  black = 30,
405  red = 31,
406  green = 32,
407  yellow = 33,
408  blue = 34,
409  magenta = 35,
410  cyan = 36,
411  white = 37,
412  bright_black = 90,
413  bright_red = 91,
414  bright_green = 92,
415  bright_yellow = 93,
416  bright_blue = 94,
417  bright_magenta = 95,
418  bright_cyan = 96,
419  bright_white = 97,
420  none = -1
421  } fore;
422 
424  enum class bg {
425  black = 40,
426  red = 41,
427  green = 42,
428  yellow = 43,
429  blue = 44,
430  magenta = 45,
431  cyan = 46,
432  white = 47,
433  bright_black = 100,
434  bright_red = 101,
435  bright_green = 102,
436  bright_yellow = 103,
437  bright_blue = 104,
438  bright_magenta = 105,
439  bright_cyan = 106,
440  bright_white = 107,
441  none = -1
442  } back;
443 
444  protected:
446  friend std::ostream& operator<<(std::ostream& os, const std::tuple<fg,bg,typo>& fbs)
447  {
448  auto [f,b,s] = fbs;
449  std::vector<short> codes; codes.reserve(3);
450  if(f != fg::none) { codes.push_back(static_cast<short>(f));}
451  if(b != bg::none) { codes.push_back(static_cast<short>(b));}
452  if(s != typo::none) { codes.push_back(static_cast<short>(s));}
453  if(codes.size() == 0) {
454  return os;
455 
456  } else {
457  os << "\033[";
458  os << codes[0];
459  for(size_t i=1; i < codes.size(); ++i) {
460  os << ";" << codes[i];
461  }
462  os << "m";
463  }
464  return os;
465  }
466 
468  friend std::ostream& operator<<(std::ostream& os, const typo& s)
469  {
470  if(s != typo::none) {
471  os << "\033[" << static_cast<short>(s) << "m";
472  }
473  return os;
474  }
475 
478  protected:
483  struct color {
484  ansi mode; // Not const to allow for the implicit copy assignemnt operator.
485 
487  enum class ground { // idem.
488  fore = 38,
489  back = 48
490  } type;
491 
497  color(ansi a, ground g) : mode(a), type(g) {}
498 
500  virtual bool is_set() const = 0;
501 
503  virtual std::ostream& print_on( std::ostream& os) const = 0;
504 
506  friend std::ostream& operator<<(std::ostream& os, const color& c)
507  {
508  if(c.is_set()) {
509  os << "\033[" << static_cast<short>(c.type) << ";" << static_cast<short>(c.mode) << ";";
510  c.print_on(os);
511  os << "m";
512  }
513  return os;
514  }
515  };
516 
517  // There is no color_16 because it would be the same as color_256, only with different indices,
518  // hence making it more complicated for the user to select the right constructor.
519  // Here, we just use enum for 16 colors, and indices for 256 colors.
520 
522  struct color_256 : public color {
526  short index;
527 
531  color_256(ground t) : color(ansi::colors_256, t), index(-1) {}
532 
538  color_256(ground t, const short i) : color(ansi::colors_256, t), index(i) {assert(-1 <= i and i <= 255);}
539 
541  bool is_set() const {return index > -1;}
542 
544  std::ostream& print_on( std::ostream& os) const
545  {
546  os << index;
547  return os;
548  }
549  };
550 
552  struct fg_256 : public color_256 {
554  fg_256() : color_256(ground::fore) {}
555 
559  fg_256(const short f) : color_256(ground::fore, f) {}
560 
564  fg_256(const fg&) : color_256(ground::fore, -1) {}
565 
566  } fore_256;
567 
569  struct bg_256 : public color_256 {
571  bg_256() : color_256(ground::back) {}
572 
576  bg_256(const short b) : color_256(ground::back, b) {}
577 
581  bg_256(const bg&) : color_256(ground::back, -1) {}
582 
583  } back_256;
584 
586  struct color_16M : public color {
590  short red, green, blue;
591 
595  color_16M(ground t) : color(ansi::colors_16M, t), red(-1), green(-1), blue(-1) {}
596 
604  color_16M(ground t, short r, short g, short b)
605  : color(ansi::colors_16M, t), red(r), green(g), blue(b) {}
606 
614  color_16M(ground t, const std::string& srgb) : color(ansi::colors_16M, t)
615  {
616  assert(srgb.size() == 7);
617  if(srgb.size() != 7) {
618  red = -1;
619  green = -1;
620  blue = -1;
621  } else {
622  char i = 0;
623  if(srgb.at(0) == '#') {
624  i = 1;
625  }
626  std::istringstream(srgb.substr(0+i,2)) >> std::hex >> red;
627  std::istringstream(srgb.substr(2+i,2)) >> std::hex >> green;
628  std::istringstream(srgb.substr(4+i,2)) >> std::hex >> blue;
629  }
630  assert(-1 <= red and red <= 255);
631  assert(-1 <= green and green <= 255);
632  assert(-1 <= blue and blue <= 255);
633  }
634 
636  bool is_set() const {return red > -1 and green > -1 and blue > -1;}
637 
639  std::ostream& print_on( std::ostream& os) const
640  {
641  os << red << ";" << green << ";" << blue;
642  return os;
643  }
644  };
645 
647  struct fg_16M : public color_16M {
649  fg_16M() : color_16M(ground::fore) {}
650 
659  fg_16M(short r, short g, short b) : color_16M(ground::fore, r,g,b) {}
660 
667  fg_16M(const std::string& srgb) : color_16M(ground::fore, srgb) {}
668 
672  fg_16M(const fg&) : color_16M(ground::fore, -1,-1,-1) {}
673 
674  } fore_16M;
675 
677  struct bg_16M : public color_16M {
679  bg_16M() : color_16M(ground::back) {}
680 
689  bg_16M(short r, short g, short b) : color_16M(ground::back, r,g,b) {}
690 
697  bg_16M(const std::string& srgb) : color_16M(ground::back, srgb) {}
698 
702  bg_16M(const bg&) : color_16M(ground::back, -1,-1,-1) {}
703 
704  } back_16M;
705 
708  public:
710  fmt() : mode(ansi::colors_16), style(typo::none), fore(fg::none), back(bg::none) {}
711 
714  fmt( fg f, bg b = bg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
715  fmt( fg f, typo s , bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
716  fmt( bg b, fg f = fg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
717  fmt( bg b, typo s , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
718  fmt(typo s, fg f = fg::none, bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
719  fmt(typo s, bg b , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
724  fmt(fg_256 f, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(b) {}
725  fmt(fg_256 f, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(bg::none) {}
726  fmt(fg, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(fg::none), back_256(b) {}
731  fmt(const short fr, const short fg, const short fb,
732  const short gr, const short gg, const short gb,
733  typo s = typo::none)
734  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(gr,gg,gb) {}
735  fmt(fg,
736  const short gr, const short gg, const short gb,
737  typo s = typo::none)
738  : mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(gr,gg,gb) {}
739  fmt(const short fr, const short fg, const short fb,
740  bg, typo s = typo::none)
741  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
742  fmt(const short fr, const short fg, const short fb,
743  typo s = typo::none)
744  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
745 
746  fmt(const std::string& f, const std::string& b, typo s = typo::none)
747  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(b) {}
748  fmt(fg, const std::string& b, typo s = typo::none)
749  : mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(b) {}
750  fmt(const std::string& f, bg, typo s = typo::none)
751  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
752  fmt(const std::string& f, typo s = typo::none)
753  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
756  protected:
757 
759  std::ostream& print_on( std::ostream& os) const
760  {
761  if(mode == ansi::colors_16) {
762  // Print all in a single escape.
763  os << std::make_tuple(fore,back,style);
764 
765  } else {
766  // 256 or 16M: always print separated escapes for foreground/background.
767  if(mode == ansi::colors_256) {
768  os << fore_256;
769  os << back_256;
770 
771  } else if(mode == ansi::colors_16M) {
772  os << fore_16M;
773  os << back_16M;
774  }
775  // In any case, print the style separately.
776  os << style;
777  }
778  return os;
779  }
780 
781  public:
793  friend std::ostream& operator<<(std::ostream& os, const fmt& fmt)
794  {
795  return fmt.print_on(os);
796  }
797 
808  std::string operator()( const std::string& msg ) const
809  {
810  std::ostringstream os;
811  this->print_on(os);
812  fmt reset(fmt::typo::reset);
813  os << msg;
814  reset.print_on(os);
815  return os.str();
816  }
817 
820  std::string str() const
821  {
822  std::ostringstream os;
823  this->print_on(os);
824  return os.str();
825  }
826 
827  static fmt hash( const std::string& str, const std::vector<fmt> domain = {})
828  {
829  size_t h = std::hash<std::string>{}(str);
830  if(domain.size() == 0) {
831  return fmt(static_cast<short>(h % 256));
832  } else {
833  return fmt(domain[h % domain.size()]);
834  }
835  }
836  }; // fmt class
837 
843  public:
844  clutchlog(clutchlog const&) = delete;
845  void operator=(clutchlog const&) = delete;
846 
847  private:
848  clutchlog() :
849  // system, main, log
851  _level_word({
852  {level::critical,"Critical"},
853  {level::error ,"Error"},
854  {level::warning ,"Warning"},
855  {level::progress,"Progress"},
856  {level::note ,"Note"},
857  {level::info ,"Info"},
858  {level::debug ,"Debug"},
859  {level::xdebug ,"XDebug"}
860  }),
861  _level_short({
862  {level::critical, "Crit"},
863  {level::error , "Erro"},
864  {level::warning , "Warn"},
865  {level::progress, "Prog"},
866  {level::note , "Note"},
867  {level::info , "Info"},
868  {level::debug , "Dbug"},
869  {level::xdebug , "XDbg"}
870  }),
871  _level_fmt({
872  {level::critical,fmt(fmt::fg::red, fmt::typo::underline)},
873  {level::error ,fmt(fmt::fg::red, fmt::typo::bold)},
874  {level::warning ,fmt(fmt::fg::magenta, fmt::typo::bold)},
875  {level::progress,fmt()},
876  {level::note ,fmt()},
877  {level::info ,fmt()},
878  {level::debug ,fmt()},
879  {level::xdebug ,fmt()}
880  }),
883  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
884  _hfill_char(clutchlog::default_hfill_char),
885  _hfill_fmt(fmt::fg::none),
886  _hfill_max(clutchlog::default_hfill_max),
887  _hfill_min(clutchlog::default_hfill_min),
888  #endif
889  _out(&std::clog),
890  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
891  _depth(std::numeric_limits<size_t>::max() - _strip_calls),
892  _depth_mark(clutchlog::default_depth_mark),
893  #endif
894  _stage(level::error),
895  _in_file(".*"),
896  _in_func(".*"),
897  _in_line(".*"),
898  // Empty vectors by default:
899  // _filehash_fmts
900  // _funchash_fmts
901  // _depth_fmts
902  _filename(filename::path)
903  {
904  // Reverse the level->word map into a word->level map.
905  for(auto& lw : _level_word) {
906  _word_level[lw.second] = lw.first;
907  }
908 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
909  struct winsize w;
910  ioctl(STDERR_FILENO, TIOCGWINSZ, &w);
911  _nb_columns = std::max(std::min((size_t)w.ws_col, default_hfill_max), default_hfill_min);
912 #endif
913  }
914 
915  protected:
917  size_t _strip_calls;
919  const std::map<level,std::string> _level_word;
921  std::map<std::string,level> _word_level;
923  std::map<level,std::string> _level_short;
925  std::map<level,fmt> _level_fmt;
927  std::string _format_log;
929  std::string _format_dump;
930  #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
931 
932  char _hfill_char;
934  fmt _hfill_fmt;
936  size_t _hfill_max;
938  size_t _hfill_min;
939  #endif
940 
941  std::ostream* _out;
942  #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
943 
944  size_t _depth;
946  std::string _depth_mark;
947  #endif
948 
951  std::regex _in_file;
953  std::regex _in_func;
955  std::regex _in_line;
956 
958  std::vector<fmt> _filehash_fmts;
960  std::vector<fmt> _funchash_fmts;
961 
962 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
963 
964  static const size_t _max_buffer = 4096;
966  std::vector<fmt> _depth_fmts;
967 #endif
968 
969 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
970 
971  size_t _nb_columns;
972 #endif
973 
978  public:
979 
983  void format(const std::string& format) {_format_log = format;}
986  std::string format() const {return _format_log;}
987 
989  void format_comment(const std::string& format) {_format_dump = format;}
991  std::string format_comment() const {return _format_dump;}
992 
994  void out(std::ostream& out) {_out = &out;}
996  std::ostream& out() {return *_out;}
997 
998 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
999  void depth(size_t d) {_depth = d;}
1002  size_t depth() const {return _depth;}
1003 
1005  void depth_mark(const std::string mark) {_depth_mark = mark;}
1007  std::string depth_mark() const {return _depth_mark;}
1008 
1010  void strip_calls(const size_t n) {_strip_calls = n;}
1012  size_t strip_calls() const {return _strip_calls;}
1013 #endif
1014 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
1015  void hfill_mark(const char mark) {_hfill_char = mark;}
1018  char hfill_mark() const {return _hfill_char;}
1020  void hfill_style(fmt style) {_hfill_fmt = style;}
1025  template<class ... FMT>
1026  void hfill_style(FMT... styles) { this->hfill_style(fmt(styles...)); }
1028  fmt hfill_style() const {return _hfill_fmt;}
1030  void hfill_max(const size_t nmax) {_hfill_max = nmax;}
1032  size_t hfill_max() {return _hfill_max;}
1034  void hfill_min(const size_t nmin) {_hfill_min = nmin;}
1036  size_t hfill_min() {return _hfill_min;}
1037 #endif
1038 
1045  void filehash_styles(std::vector<fmt> styles) {_filehash_fmts = styles;}
1053  void funchash_styles(std::vector<fmt> styles) {_funchash_fmts = styles;}
1062  void depth_styles(std::vector<fmt> styles) {_depth_fmts = styles;}
1063 
1065  void threshold(level l) {_stage = l;}
1067  void threshold(const std::string& l) {_stage = this->level_of(l);}
1069  level threshold() const {return _stage;}
1071  const std::map<std::string,level>& levels() const { return _word_level;}
1072 
1077  level level_of(const std::string name)
1078  {
1079  const auto ilevel = _word_level.find(name);
1080  if( ilevel != std::end(_word_level)) {
1081  return ilevel->second;
1082  } else {
1083  throw std::out_of_range("'" + name + "' is not a valid log level name");
1084  }
1085  }
1086 
1088  void file(std::string file) {_in_file = file;}
1090  void func(std::string func) {_in_func = func;}
1092  void line(std::string line) {_in_line = line;}
1093 
1095  void location(
1096  const std::string& in_file,
1097  const std::string& in_function=".*",
1098  const std::string& in_line=".*"
1099  )
1100  {
1101  file(in_file);
1102  func(in_function);
1103  line(in_line);
1104  }
1105 
1110  template<class ... FMT>
1111  void style(level stage, FMT... styles) { this->style(stage,fmt(styles...)); }
1113  void style(level stage, fmt style) { _level_fmt.at(stage) = style; }
1115  fmt style(level stage) const { return _level_fmt.at(stage); }
1116 
1118  void filename(filename f) {_filename = f;}
1119 
1122  public:
1123 
1127  struct scope_t {
1130  bool matches;
1133 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1134 
1135  size_t depth;
1136 #endif
1137 
1138  bool there;
1141  matches(false),
1142  stage(level::xdebug),
1144  depth(0),
1145 #endif
1146  there(false)
1147  {}
1148  }; // scope_t
1149 
1150 
1153  const level& stage,
1154  const std::string& file,
1155  const std::string& func,
1156  const size_t line
1157  ) const
1158  {
1159  scope_t scope; // False scope by default.
1160 
1161  /***** Log level stage *****/
1162  // Test stage first, because it's fastest.
1163  scope.stage = stage;
1164  if(not (scope.stage <= _stage)) {
1165  // Bypass useless computations if no match
1166  // because of the stage.
1167  return scope;
1168  }
1169 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1170  /***** Stack depth *****/
1171  // Backtrace in second, quite fast.
1172  size_t stack_depth;
1173  void *buffer[_max_buffer];
1174  stack_depth = backtrace(buffer, _max_buffer);
1175  scope.depth = stack_depth;
1176  if(not (scope.depth <= _depth + _strip_calls)) {
1177  // Bypass if no match.
1178  return scope;
1179  }
1180 #endif
1181 
1182  /***** Location *****/
1183  // Location last, slowest.
1184  std::ostringstream sline; sline << line;
1185  scope.there =
1186  std::regex_search(file, _in_file)
1187  and std::regex_search(func, _in_func)
1188  and std::regex_search(sline.str(), _in_line);
1189 
1190  // No need to retest stage and depth, which are true here.
1191  scope.matches = scope.there;
1192 
1193  return scope;
1194  } // locate
1195 
1203  std::string replace(
1204  const std::string& form,
1205  const std::string& mark,
1206  const std::string& tag
1207  ) const
1208  {
1209  // Useless debug code, unless something fancy would be done with name tags.
1210  // std::regex re;
1211  // try {
1212  // re = std::regex(mark);
1213  //
1214  // } catch(const std::regex_error& e) {
1215  // std::cerr << "ERROR with a regular expression \"" << mark << "\": ";
1216  // switch(e.code()) {
1217  // case std::regex_constants::error_collate:
1218  // std::cerr << "the expression contains an invalid collating element name";
1219  // break;
1220  // case std::regex_constants::error_ctype:
1221  // std::cerr << "the expression contains an invalid character class name";
1222  // break;
1223  // case std::regex_constants::error_escape:
1224  // std::cerr << "the expression contains an invalid escaped character or a trailing escape";
1225  // break;
1226  // case std::regex_constants::error_backref:
1227  // std::cerr << "the expression contains an invalid back reference";
1228  // break;
1229  // case std::regex_constants::error_brack:
1230  // std::cerr << "the expression contains mismatched square brackets ('[' and ']')";
1231  // break;
1232  // case std::regex_constants::error_paren:
1233  // std::cerr << "the expression contains mismatched parentheses ('(' and ')')";
1234  // break;
1235  // case std::regex_constants::error_brace:
1236  // std::cerr << "the expression contains mismatched curly braces ('{' and '}')";
1237  // break;
1238  // case std::regex_constants::error_badbrace:
1239  // std::cerr << "the expression contains an invalid range in a {} expression";
1240  // break;
1241  // case std::regex_constants::error_range:
1242  // std::cerr << "the expression contains an invalid character range (e.g. [b-a])";
1243  // break;
1244  // case std::regex_constants::error_space:
1245  // std::cerr << "there was not enough memory to convert the expression into a finite state machine";
1246  // break;
1247  // case std::regex_constants::error_badrepeat:
1248  // std::cerr << "one of *?+{ was not preceded by a valid regular expression";
1249  // break;
1250  // case std::regex_constants::error_complexity:
1251  // std::cerr << "the complexity of an attempted match exceeded a predefined level";
1252  // break;
1253  // case std::regex_constants::error_stack:
1254  // std::cerr << "there was not enough memory to perform a match";
1255  // break;
1256  // default:
1257  // std::cerr << "unknown error";
1258  // }
1259  // std::cerr << std::endl;
1260  // throw;
1261  // } // catch
1262 
1263  const std::regex re(mark);
1264  return std::regex_replace(form, re, tag);
1265  }
1266 
1268  std::string replace(
1269  const std::string& form,
1270  const std::string& mark,
1271  const size_t tag
1272  ) const
1273  {
1274  std::ostringstream stag; stag << tag;
1275  return replace(form, mark, stag.str());
1276  }
1277 
1279  std::string format(
1280  std::string row,
1281  const std::string& what,
1283  const std::string& name,
1284 #endif
1285  const level& stage,
1286  const std::string& file,
1287  const std::string& func,
1288  const size_t line
1290  ,
1291  const size_t depth
1292 #endif
1293  ) const
1294  {
1295  row = replace(row, "\\{msg\\}", what);
1296 
1297  const std::filesystem::path filepath(file);
1298  assert(filepath.is_absolute());
1299  std::string filename;
1300  std::filesystem::path::iterator ip = filepath.end();
1301  std::advance(ip, -2);
1302  switch(_filename) {
1303  case filename::base:
1304  filename = filepath.filename().string();
1305  break;
1306  case filename::dir:
1307  filename = ip->string();
1308  break;
1309  case filename::dirbase:
1310  filename = (*ip / filepath.filename()).string();
1311  break;
1312  case filename::stem:
1313  filename = filepath.stem().string();
1314  break;
1315  case filename::dirstem:
1316  filename = (*ip / filepath.stem()).string();
1317  break;
1318  case filename::path:
1319  default:
1320  filename = file;
1321  break;
1322  }
1323  row = replace(row, "\\{file\\}", filename);
1324 
1325 
1326  row = replace(row, "\\{func\\}", func);
1327  row = replace(row, "\\{line\\}", line);
1328 
1329  row = replace(row, "\\{level\\}", _level_word.at(stage));
1330  std::string letter(1, _level_word.at(stage).at(0)); // char -> string
1331  row = replace(row, "\\{level_letter\\}", letter);
1332  row = replace(row, "\\{level_short\\}", _level_short.at(stage));
1333 
1334 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1335  size_t actual_depth = depth - _strip_calls;
1336  row = replace(row, "\\{name\\}", name);
1337  row = replace(row, "\\{depth\\}", actual_depth);
1338 
1339  if(_depth_fmts.size() == 0) {
1340  row = replace(row, "\\{depth_fmt\\}", fmt(actual_depth % 256).str() );
1341 
1342  std::ostringstream chevrons;
1343  for(size_t i = 0; i < actual_depth; ++i) {
1344  chevrons << _depth_mark;
1345  }
1346  row = replace(row, "\\{depth_marks\\}", chevrons.str());
1347 
1348  } else {
1349  row = replace(row, "\\{depth_fmt\\}",
1350  _depth_fmts[std::min(actual_depth,_depth_fmts.size()-1)].str() );
1351 
1352  std::ostringstream chevrons;
1353  for(size_t i = 0; i < actual_depth; ++i) {
1354  chevrons << _depth_fmts[std::min(i+1,_depth_fmts.size()-1)].str()
1355  << _depth_mark;
1356  }
1357  row = replace(row, "\\{depth_marks\\}", chevrons.str());
1358  }
1359 #endif
1360  row = replace(row, "\\{level_fmt\\}", _level_fmt.at(stage).str());
1361  row = replace(row, "\\{filehash_fmt\\}", fmt::hash(file, _filehash_fmts).str() );
1362  row = replace(row, "\\{funchash_fmt\\}", fmt::hash(func, _funchash_fmts).str() );
1363 
1364 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL
1365  // hfill is replaced last to allow for correct line width estimation.
1366  const std::string raw_row = replace(row, "\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]", "");
1367  const std::string hfill_tag = "{hfill}";
1368  const size_t hfill_pos = row.find(hfill_tag);
1369  const size_t raw_hfill_pos = raw_row.find(hfill_tag);
1370  const size_t nb_columns = std::max(std::min((size_t)_nb_columns, _hfill_max), _hfill_min);
1371  if(hfill_pos != std::string::npos) {
1372  assert(raw_hfill_pos != std::string::npos);
1373  if(nb_columns > 0) {
1374  const size_t left_len = raw_hfill_pos;
1375  const size_t right_len = raw_row.size() - raw_hfill_pos - hfill_tag.size();
1376  if(right_len+left_len > nb_columns) {
1377  // The right part would go over the terminal width: add a new row.
1378  if(right_len < nb_columns) {
1379  // There is room for the right part on a new line.
1380  const std::string hfill(std::max((size_t)0, nb_columns-right_len), _hfill_char);
1381  const std::string hfill_styled = _hfill_fmt(hfill);
1382  row = replace(row, "\\{hfill\\}", "\n"+hfill_styled);
1383  } else {
1384  // Right part still goes over columns: let it go.
1385  const std::string hfill(1, _hfill_char);
1386  const std::string hfill_styled = _hfill_fmt(hfill);
1387  row = replace(row, "\\{hfill\\}", "\n"+hfill_styled);
1388  }
1389  } else {
1390  // There is some space in between left and right parts.
1391  const std::string hfill(std::max((size_t)0, nb_columns - (right_len+left_len)), _hfill_char);
1392  const std::string hfill_styled = _hfill_fmt(hfill);
1393  row = replace(row, "\\{hfill\\}", hfill_styled);
1394  }
1395  } else {
1396  // We don't know the terminal width.
1397  const std::string hfill(1, _hfill_char);
1398  const std::string hfill_styled = _hfill_fmt(hfill);
1399  row = replace(row, "\\{hfill\\}", hfill_styled);
1400  }
1401  }
1402 #else
1403  // We cannot know the terminal width.
1404  const std::string hfill(1, _hfill_char);
1405  const std::string hfill_styled = _hfill_fmt(hfill);
1406  row = replace(row, "\\{hfill\\}", hfill_styled);
1407 #endif
1408  return _level_fmt.at(stage)(row);
1409  }
1410 
1412  void log(
1413  const level& stage,
1414  const std::string& what,
1415  const std::string& file, const std::string& func, const size_t line,
1416  const size_t depth_delta = 0
1417  ) const
1418  {
1419  scope_t scope = locate(stage, file, func, line);
1420 
1421  if(scope.matches) {
1422 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1423  *_out << format(_format_log, what, basename(getenv("_")),
1424  stage, file, func,
1425  line, scope.depth + depth_delta );
1426 #else
1427  *_out << format(_format_log, what,
1428  stage, file, func,
1429  line );
1430 #endif
1431  _out->flush();
1432  } // if scopes.matches
1433  }
1434 
1436  template<class In>
1437  void dump(
1438  const level& stage,
1439  const In container_begin, const In container_end,
1440  const std::string& file, const std::string& func, const size_t line,
1441  const std::string& filename_template = "dump_{n}.dat",
1442  const std::string sep = dump_default_sep
1443  ) const
1444  {
1445  scope_t scope = locate(stage, file, func, line);
1446 
1447  if(scope.matches) {
1448  const std::string tag = "\\{n\\}";
1449  const std::regex re(tag);
1450  std::string outfile = "";
1451 
1452  // If the file name template has the {n} tag.
1453  if(std::regex_search(filename_template, re)) {
1454  // Increment n until a free one is found.
1455  size_t n = 0;
1456  do {
1457  outfile = replace(filename_template, tag, n);
1458  n++;
1459  } while( fs::exists( outfile ) );
1460 
1461  } else {
1462  // Use the parameter as is.
1463  outfile = filename_template;
1464  }
1465 
1466  std::ofstream fd(outfile);
1467 
1468  if(_format_dump.size() > 0) {
1469 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1470  fd << format(_format_dump, "", basename(getenv("_")),
1471  stage, file, func,
1472  line, scope.depth );
1473 #else
1474  fd << format(_format_dump, "",
1475  stage, file, func,
1476  line );
1477 #endif
1478  fd << sep; // sep after comment line.
1479  }
1480 
1481  std::copy(container_begin, container_end,
1482  std::ostream_iterator<typename In::value_type>(fd, sep.c_str()));
1483 
1484  fd.close();
1485  } // if scopes.matches
1486  }
1487 
1489 };
1490 
1493 #else // not WITH_CLUTCHLOG
1494 
1495 
1496 /**********************************************************************
1497  * Fake implementation
1498  **********************************************************************/
1499 
1500 // Equivalent class with empty methods, will be optimized out
1501 // while allowing to actually have calls implemented without WITH_CLUTCHLOG guards.
1502 #pragma GCC diagnostic push
1503 #pragma GCC diagnostic ignored "-Wreturn-type"
1504 class clutchlog
1505 {
1506  public:
1507  static clutchlog& logger() {}
1508  enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};
1509  enum filename {path, base, dir, dirbase, stem, dirstem};
1510  class fmt {
1511  public:
1512  enum class ansi { colors_16, colors_256, colors_16M} mode;
1513  enum class typo { reset, bold, underline, inverse, none} style;
1514  enum class fg { black, red, green, yellow, blue, magenta, cyan, white, bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white, none} fore;
1515  enum class bg { black, red, green, yellow, blue, magenta, cyan, white, bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white, none } back;
1516  protected:
1517  friend std::ostream& operator<<(std::ostream&, const std::tuple<fg,bg,typo>&) {}
1518  friend std::ostream& operator<<(std::ostream&, const typo&) {}
1519  protected:
1520  struct color {
1521  ansi mode;
1522  enum class ground { fore, back } type;
1523  color(ansi a, ground g) : mode(a), type(g) {}
1524  virtual bool is_set() const = 0;
1525  virtual std::ostream& print_on( std::ostream&) const = 0;
1526  friend std::ostream& operator<<(std::ostream&, const color&) {}
1527  };
1528  struct color_256 : public color {
1529  short index;
1530  color_256(ground t) : color(ansi::colors_256, t), index(-1) {}
1531  color_256(ground t, const short i) : color(ansi::colors_256, t), index(i) {}
1532  bool is_set() const {}
1533  std::ostream& print_on( std::ostream&) const {}
1534  };
1535  struct fg_256 : public color_256 {
1536  fg_256() : color_256(ground::fore) {}
1537  fg_256(const short f) : color_256(ground::fore, f) {}
1538  fg_256(const fg&) : color_256(ground::fore, -1) {}
1539  } fore_256;
1540  struct bg_256 : public color_256 {
1541  bg_256() : color_256(ground::back) {}
1542  bg_256(const short b) : color_256(ground::back, b) {}
1543  bg_256(const bg&) : color_256(ground::back, -1) {}
1544  } back_256;
1545  struct color_16M : public color {
1546  short red, green, blue;
1547  color_16M(ground t) : color(ansi::colors_16M, t), red(-1), green(-1), blue(-1) {}
1548  color_16M(ground t, short r, short g, short b) : color(ansi::colors_16M, t), red(r), green(g), blue(b) {}
1549  color_16M(ground t, const std::string&) : color(ansi::colors_16M, t) {}
1550  bool is_set() const {return red > -1 and green > -1 and blue > -1;}
1551  std::ostream& print_on( std::ostream&) const {}
1552  };
1553  struct fg_16M : public color_16M {
1554  fg_16M() : color_16M(ground::fore) {}
1555  fg_16M(short r, short g, short b) : color_16M(ground::fore, r,g,b) {}
1556  fg_16M(const std::string& srgb) : color_16M(ground::fore, srgb) {}
1557  fg_16M(const fg&) : color_16M(ground::fore, -1,-1,-1) {}
1558  } fore_16M;
1559  struct bg_16M : public color_16M {
1560  bg_16M() : color_16M(ground::back) {}
1561  bg_16M(short r, short g, short b) : color_16M(ground::back, r,g,b) {}
1562  bg_16M(const std::string& srgb) : color_16M(ground::back, srgb) {}
1563  bg_16M(const bg&) : color_16M(ground::back, -1,-1,-1) {}
1564  } back_16M;
1565  public:
1566  fmt() : mode(ansi::colors_16), style(typo::none), fore(fg::none), back(bg::none) {}
1567  fmt( fg f, bg b = bg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1568  fmt( fg f, typo s , bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1569  fmt( bg b, fg f = fg::none, typo s = typo::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1570  fmt( bg b, typo s , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1571  fmt(typo s, fg f = fg::none, bg b = bg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1572  fmt(typo s, bg b , fg f = fg::none) : mode(ansi::colors_16), style(s), fore(f), back(b) {}
1573  fmt(fg_256 f, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(b) {}
1574  fmt(fg_256 f, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(f), back_256(bg::none) {}
1575  fmt(fg, bg_256 b, typo s = typo::none) : mode(ansi::colors_256), style(s), fore_256(fg::none), back_256(b) {}
1576  fmt(const short fr, const short fg, const short fb,
1577  const short gr, const short gg, const short gb,
1578  typo s = typo::none)
1579  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(gr,gg,gb) {}
1580  fmt(fg,
1581  const short gr, const short gg, const short gb,
1582  typo s = typo::none)
1583  : mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(gr,gg,gb) {}
1584  fmt(const short fr, const short fg, const short fb,
1585  bg, typo s = typo::none)
1586  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
1587  fmt(const short fr, const short fg, const short fb,
1588  typo s = typo::none)
1589  : mode(ansi::colors_16M), style(s), fore_16M(fr,fg,fb), back_16M(bg::none) {}
1590 
1591  fmt(const std::string& f, const std::string& b, typo s = typo::none)
1592  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(b) {}
1593  fmt(fg, const std::string& b, typo s = typo::none)
1594  : mode(ansi::colors_16M), style(s), fore_16M(fg::none), back_16M(b) {}
1595  fmt(const std::string& f, bg, typo s = typo::none)
1596  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
1597  fmt(const std::string& f, typo s = typo::none)
1598  : mode(ansi::colors_16M), style(s), fore_16M(f), back_16M(bg::none) {}
1599  protected:
1600  std::ostream& print_on( std::ostream&) const {}
1601  public:
1602  friend std::ostream& operator<<(std::ostream&, const fmt&) {}
1603  std::string operator()( const std::string&) const {}
1604  std::string str() const {}
1605  static fmt hash( const std::string&, const std::vector<fmt>) {}
1606  };
1607  public:
1608  clutchlog(clutchlog const&) = delete;
1609  void operator=(clutchlog const&) = delete;
1610  private:
1611  clutchlog() {}
1612  protected:
1613  struct scope_t {};
1614  scope_t locate(
1615  const level&,
1616  const std::string&,
1617  const std::string&,
1618  const size_t
1619  ) const
1620  {}
1621  public:
1622  void format(const std::string&) {}
1623  std::string format() const {}
1624 
1625  void format_comment(const std::string&) {}
1626  std::string format_comment() const {}
1627 
1628  void out(std::ostream&) {}
1629  std::ostream& out() {}
1630 
1631 #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1
1632  void depth(size_t) {}
1633  size_t depth() const {}
1634 
1635  void depth_mark(const std::string) {}
1636  std::string depth_mark() const {}
1637  void strip_calls(const size_t) {}
1638  size_t strip_calls() const {}
1639 #endif
1640 #if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1
1641  void hfill_mark(const char) {}
1642  char hfill_mark() const {}
1643  void hfill_fmt(fmt) {}
1644  fmt hfill_fmt() const {}
1645  void hfill_min(const size_t) {}
1646  size_t hfill_min() {}
1647  void hfill_max(const size_t) {}
1648  size_t hfill_max() {}
1649 #endif
1650  void filehash_styles(std::vector<fmt> ) {}
1651  void funchash_styles(std::vector<fmt> ) {}
1652  void depth_styles(std::vector<fmt>) {}
1653 
1654  void threshold(level) {}
1655  void threshold(const std::string&) {}
1656  level threshold() const {}
1657  const std::map<std::string,level> levels() const {}
1658  level level_of(const std::string) {}
1659 
1660  void file(std::string) {}
1661  void func(std::string) {}
1662  void line(std::string) {}
1663 
1664 #pragma GCC diagnostic push
1665 #pragma GCC diagnostic ignored "-Wunused-parameter"
1666  void location(
1667  const std::string&,
1668  const std::string& in_function=".*",
1669  const std::string& in_line=".*"
1670  )
1671  {}
1672 #pragma GCC diagnostic pop
1673  template<class ... FMT>
1674  void style(level, FMT...) {}
1675  void style(level, fmt) {}
1676  fmt style(level) const {}
1677  void filename(filename) {}
1678  public:
1679  std::string replace(
1680  const std::string&,
1681  const std::string&,
1682  const std::string&
1683  ) const
1684  {}
1685 
1686  std::string replace(
1687  const std::string&,
1688  const std::string&,
1689  const size_t
1690  ) const
1691  {}
1692 
1693  std::string format(
1694  std::string,
1695  const std::string&,
1697  const std::string&,
1698 #endif
1699  const level&,
1700  const std::string&,
1701  const std::string&,
1702  const size_t
1704  ,
1705  const size_t
1706 #endif
1707  ) const
1708  {}
1709 
1710  void log(
1711  const level&,
1712  const std::string&,
1713  const std::string&, const std::string&, size_t
1714  ) const
1715  {}
1716 
1717  template<class In>
1718  void dump(
1719  const level&,
1720  const In, const In,
1721  const std::string&, const std::string&, size_t,
1722  const std::string&,
1723  const std::string
1724  ) const
1725  {}
1726 };
1727 #pragma GCC diagnostic pop
1728 #endif // WITH_CLUTCHLOG
1729 
1730 #endif // CLUTCHLOG_H
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const std::tuple< fg, bg, typo > &fbs)
Output stream operator for a 3-tuple of 16-colors mode tags.
Definition: clutchlog.h:446
clutchlog::default_depth_mark
static std::string default_depth_mark
Default mark for stack depth.
Definition: clutchlog.h:259
clutchlog::_format_log
std::string _format_log
Current format of the standard output.
Definition: clutchlog.h:927
clutchlog::fmt::color_16M::color_16M
color_16M(ground t, const std::string &srgb)
Hex triplet string constructor.
Definition: clutchlog.h:614
clutchlog::dump
void dump(const level &stage, const In container_begin, const In container_end, const std::string &file, const std::string &func, const size_t line, const std::string &filename_template="dump_{n}.dat", const std::string sep=dump_default_sep) const
Dump a serializable container after a comment line with log information.
Definition: clutchlog.h:1437
clutchlog::depth_styles
void depth_styles(std::vector< fmt > styles)
Set the styles for value-dependant depth formatting.
Definition: clutchlog.h:1062
clutchlog::_level_fmt
std::map< level, fmt > _level_fmt
Dictionary of level identifier to their format.
Definition: clutchlog.h:925
clutchlog::fmt::back
enum clutchlog::fmt::bg back
Background color.
clutchlog::_funchash_fmts
std::vector< fmt > _funchash_fmts
List of candidate format objects for value-dependant function name styling.
Definition: clutchlog.h:960
clutchlog::fmt::str
std::string str() const
Return the formatting code as a string.
Definition: clutchlog.h:820
clutchlog::fmt::fg_256
Foreground in 256-colors mode.
Definition: clutchlog.h:552
clutchlog::line
void line(std::string line)
Set the regular expression filtering the line location.
Definition: clutchlog.h:1092
clutchlog::fmt::color::operator<<
friend std::ostream & operator<<(std::ostream &os, const color &c)
Print the actually encoded escaped color sequence on the given stream.
Definition: clutchlog.h:506
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const typo &s)
Output stream operator for a typo tag alone, in 16-colors mode.
Definition: clutchlog.h:468
clutchlog::dump_default_format
static std::string dump_default_format
Default format of the comment line in file dump.
Definition: clutchlog.h:245
clutchlog::_filename
filename _filename
Filename rendering method.
Definition: clutchlog.h:975
clutchlog::out
void out(std::ostream &out)
Set the output stream on which to print.
Definition: clutchlog.h:994
clutchlog::fmt::color_16M::is_set
bool is_set() const
Returns true if the underying representation encodes an existing color.
Definition: clutchlog.h:636
clutchlog::fmt::fg_16M::fg_16M
fg_16M(const fg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:672
clutchlog::dump_default_sep
static std::string dump_default_sep
Default item separator for dump.
Definition: clutchlog.h:252
clutchlog::format
std::string format(std::string row, const std::string &what, const level &stage, const std::string &file, const std::string &func, const size_t line) const
Substitute all tags in the format string with the corresponding information and apply the style corre...
Definition: clutchlog.h:1279
clutchlog::fmt::bg_256
Background in 256-colors mode.
Definition: clutchlog.h:569
CLUTCHLOG_DEFAULT_DEPTH_MARK
#define CLUTCHLOG_DEFAULT_DEPTH_MARK
Compile-time default mark for stack depth.
Definition: clutchlog.h:256
clutchlog::default_strip_calls
static unsigned int default_strip_calls
Number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:266
clutchlog::default_hfill_min
static size_t default_hfill_min
Default minimum width (number of characters) at which to fill for right-aligning the right part of me...
Definition: clutchlog.h:287
clutchlog::replace
std::string replace(const std::string &form, const std::string &mark, const std::string &tag) const
Replace mark by tag in form.
Definition: clutchlog.h:1203
clutchlog::fmt::color_256::color_256
color_256(ground t)
Constructor.
Definition: clutchlog.h:531
clutchlog::fmt::back_16M
clutchlog::fmt::bg_16M back_16M
Current background in 16M-colors mode.
clutchlog::fmt::color
Interface class for colors representation.
Definition: clutchlog.h:483
clutchlog::fmt::ansi::colors_16
@ colors_16
16 colors mode.
clutchlog::fmt::bg_16M
background in 256-colors mode.
Definition: clutchlog.h:677
clutchlog::default_hfill_char
static char default_hfill_char
Default character used as a filling for right-align the right part of messages with "{hfill}".
Definition: clutchlog.h:273
clutchlog::scope_t::matches
bool matches
Everything is compatible.
Definition: clutchlog.h:1130
clutchlog::fmt::style
enum clutchlog::fmt::typo style
Typographic style.
clutchlog::fmt::color_16M
Abstract base class for 16M colors objects (24-bits ANSI).
Definition: clutchlog.h:586
clutchlog::fmt::fg_256::fg_256
fg_256(const fg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:564
clutchlog::format_comment
void format_comment(const std::string &format)
Set the template string for dumps.
Definition: clutchlog.h:989
clutchlog::fmt::bg_16M::bg_16M
bg_16M(const std::string &srgb)
Hex triplet string constructor.
Definition: clutchlog.h:697
clutchlog::file
void file(std::string file)
Set the regular expression filtering the file location.
Definition: clutchlog.h:1088
clutchlog::locate
scope_t locate(const level &stage, const std::string &file, const std::string &func, const size_t line) const
Gather information on the current location of the call.
Definition: clutchlog.h:1152
clutchlog::fmt::fore_16M
clutchlog::fmt::fg_16M fore_16M
Current foreground in 16M-colors mode.
clutchlog::fmt::color_256
Abstract base class for 256 colors objects (8-bits ANSI).
Definition: clutchlog.h:522
clutchlog::fmt::fmt
fmt()
Empty constructor, only useful for a no-op formatter.
Definition: clutchlog.h:710
clutchlog::style
void style(level stage, fmt style)
Set the style (color and typo) of the given log level, passing a fmt instance.
Definition: clutchlog.h:1113
clutchlog::threshold
void threshold(level l)
Set the log level (below which logs are not printed) with an identifier.
Definition: clutchlog.h:1065
clutchlog::threshold
level threshold() const
Get the log level below which logs are not printed.
Definition: clutchlog.h:1069
clutchlog::fmt::color::is_set
virtual bool is_set() const =0
Should return true if the underying representation encodes an existing color.
clutchlog::_level_short
std::map< level, std::string > _level_short
dictionary of level identifier to their 4-letters representation.
Definition: clutchlog.h:923
clutchlog::level
level
Available log levels.
Definition: clutchlog.h:313
clutchlog::fmt::color_256::color_256
color_256(ground t, const short i)
Constructor.
Definition: clutchlog.h:538
clutchlog::fmt::color_256::print_on
std::ostream & print_on(std::ostream &os) const
Print the color index on the given stream.
Definition: clutchlog.h:544
clutchlog::fmt::color_16M::color_16M
color_16M(ground t)
Constructor.
Definition: clutchlog.h:595
clutchlog::default_hfill_max
static size_t default_hfill_max
Default maximum width (number of characters) for which to fill for right-aligning the right part of m...
Definition: clutchlog.h:285
clutchlog::funchash_styles
void funchash_styles(std::vector< fmt > styles)
Set the candidate styles for value-dependant function name formatting.
Definition: clutchlog.h:1053
clutchlog::scope_t::scope_t
scope_t()
Constructor.
Definition: clutchlog.h:1140
clutchlog::_in_func
std::regex _in_func
Current function location filter.
Definition: clutchlog.h:953
clutchlog::default_format
static std::string default_format
Default format of the messages.
Definition: clutchlog.h:223
clutchlog::fmt::bg_16M::bg_16M
bg_16M(short r, short g, short b)
Numeric triplet constructor.
Definition: clutchlog.h:689
clutchlog::logger
static clutchlog & logger()
Get the logger instance.
Definition: clutchlog.h:306
clutchlog::fmt::fg_16M
Foreground in 256-colors mode.
Definition: clutchlog.h:647
clutchlog::fmt::fore_256
clutchlog::fmt::fg_256 fore_256
Current foreground in 256-colors mode.
clutchlog::fmt::fore
enum clutchlog::fmt::fg fore
Foreground color.
clutchlog::filehash_styles
void filehash_styles(std::vector< fmt > styles)
Set the candidate styles for value-dependant file name formatting.
Definition: clutchlog.h:1045
clutchlog::fmt::color::type
enum clutchlog::fmt::color::ground type
Type of color (foreground or background).
clutchlog::fmt
Color and style formatter for ANSI terminal escape sequences.
Definition: clutchlog.h:379
clutchlog::fmt::color_256::index
short index
The encoded color index in 4-bits ANSI.
Definition: clutchlog.h:526
clutchlog::fmt::bg_256::bg_256
bg_256()
Empty constructor: no color.
Definition: clutchlog.h:571
clutchlog::func
void func(std::string func)
Set the regular expression filtering the function location.
Definition: clutchlog.h:1090
clutchlog::format
std::string format() const
Get the template string.
Definition: clutchlog.h:986
clutchlog::_in_file
std::regex _in_file
Current file location filter.
Definition: clutchlog.h:951
clutchlog::style
void style(level stage, FMT... styles)
Set the style (color and typo) of the given log level.
Definition: clutchlog.h:1111
clutchlog::fmt::bg_256::bg_256
bg_256(const bg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:581
clutchlog::fmt::fg_16M::fg_16M
fg_16M()
Empty constructor: no color.
Definition: clutchlog.h:649
clutchlog::level_of
level level_of(const std::string name)
Return the log level tag corresponding to the given pre-configured name.
Definition: clutchlog.h:1077
clutchlog::filename
void filename(filename f)
Sets the file naming scheme. *‍/.
Definition: clutchlog.h:1118
clutchlog::_level_word
const std::map< level, std::string > _level_word
Dictionary of level identifier to their string representation.
Definition: clutchlog.h:919
clutchlog::fmt::operator()
std::string operator()(const std::string &msg) const
Format the given string with the currently encoded format.
Definition: clutchlog.h:808
clutchlog::fmt::color_16M::color_16M
color_16M(ground t, short r, short g, short b)
Numeric triplet constructor.
Definition: clutchlog.h:604
clutchlog::fmt::color_16M::print_on
std::ostream & print_on(std::ostream &os) const
Print the color RGB triplet on the given stream.
Definition: clutchlog.h:639
clutchlog::fmt::bg
bg
Background color codes.
Definition: clutchlog.h:424
CLUTCHLOG_DEFAULT_FORMAT
#define CLUTCHLOG_DEFAULT_FORMAT
Compile-time default format of the messages (debug mode: with absolute location).
Definition: clutchlog.h:208
clutchlog::_in_line
std::regex _in_line
Current line location filter.
Definition: clutchlog.h:955
clutchlog::fmt::fg_256::fg_256
fg_256(const short f)
Constructor.
Definition: clutchlog.h:559
clutchlog::fmt::ansi::colors_256
@ colors_256
256 colors mode.
clutchlog::fmt::mode
enum clutchlog::fmt::ansi mode
Current ANSI color mode.
clutchlog::replace
std::string replace(const std::string &form, const std::string &mark, const size_t tag) const
Replace mark by tag in form, converting tag to its string representation first.
Definition: clutchlog.h:1268
clutchlog::format_comment
std::string format_comment() const
Get the template string for dumps.
Definition: clutchlog.h:991
clutchlog::fmt::fg_256::fg_256
fg_256()
Empty constructor: no color.
Definition: clutchlog.h:554
clutchlog::fmt::ansi::colors_16M
@ colors_16M
16 millions ("true") colors mode.
clutchlog::_format_dump
std::string _format_dump
Current format of the file output.
Definition: clutchlog.h:929
CLUTCHDUMP_DEFAULT_SEP
#define CLUTCHDUMP_DEFAULT_SEP
Compile-time default item separator for dump.
Definition: clutchlog.h:249
clutchlog::fmt::bg_256::bg_256
bg_256(const short b)
Constructor.
Definition: clutchlog.h:576
clutchlog::fmt::color::ground
ground
Codes for representing foreground or background.
Definition: clutchlog.h:487
clutchlog::filename
filename
Available filename rendering methods.
Definition: clutchlog.h:316
clutchlog::scope_t
Structure holding a location matching.
Definition: clutchlog.h:1128
CLUTCHLOG_DEFAULT_HFILL_MARK
#define CLUTCHLOG_DEFAULT_HFILL_MARK
Character used as a filling for right-align the right part of messages with "{hfill}".
Definition: clutchlog.h:270
clutchlog::fmt::print_on
std::ostream & print_on(std::ostream &os) const
Print the currently encoded format escape code on the given output stream.
Definition: clutchlog.h:759
clutchlog::fmt::color_256::is_set
bool is_set() const
Returns true if the underying representation encodes an existing color.
Definition: clutchlog.h:541
clutchlog::_out
std::ostream * _out
Standard output.
Definition: clutchlog.h:941
clutchlog::out
std::ostream & out()
Get the output stream on which to print.
Definition: clutchlog.h:996
clutchlog::threshold
void threshold(const std::string &l)
Set the log level (below which logs are not printed) with a string.
Definition: clutchlog.h:1067
clutchlog::fmt::color::print_on
virtual std::ostream & print_on(std::ostream &os) const =0
Should print the underlying representation on the given stream.
clutchlog::levels
const std::map< std::string, level > & levels() const
Get the map of available log levels string representations toward their identifier....
Definition: clutchlog.h:1071
clutchlog::_strip_calls
size_t _strip_calls
Current number of call stack levels to remove from depth display.
Definition: clutchlog.h:917
clutchlog::scope_t::stage
level stage
Current log level.
Definition: clutchlog.h:1132
clutchlog::scope_t::there
bool there
Location is compatible.
Definition: clutchlog.h:1138
clutchlog::fmt::fg_16M::fg_16M
fg_16M(const std::string &srgb)
Hex triplet string constructor.
Definition: clutchlog.h:667
CLUTCHLOG_STRIP_CALLS
#define CLUTCHLOG_STRIP_CALLS
Compile-time number of call stack levels to remove from depth display by default.
Definition: clutchlog.h:263
clutchlog::fmt::operator<<
friend std::ostream & operator<<(std::ostream &os, const fmt &fmt)
Output stream overload.
Definition: clutchlog.h:793
clutchlog::log
void log(const level &stage, const std::string &what, const std::string &file, const std::string &func, const size_t line, const size_t depth_delta=0) const
Print a log message IF the location matches the given one.
Definition: clutchlog.h:1412
clutchlog::fmt::bg_16M::bg_16M
bg_16M(const bg &)
Conversion constructor from 16-colors mode.
Definition: clutchlog.h:702
clutchlog::fmt::bg_16M::bg_16M
bg_16M()
Empty constructor: no color.
Definition: clutchlog.h:679
clutchlog::_word_level
std::map< std::string, level > _word_level
Dictionary of level string to their identifier.
Definition: clutchlog.h:921
clutchlog::_stage
level _stage
Current log level.
Definition: clutchlog.h:949
clutchlog::style
fmt style(level stage) const
Get the configured fmt instance of the given log level.
Definition: clutchlog.h:1115
clutchlog::fmt::typo
typo
Typographic style codes.
Definition: clutchlog.h:392
clutchlog::location
void location(const std::string &in_file, const std::string &in_function=".*", const std::string &in_line=".*")
Set the regular expressions filtering the location.
Definition: clutchlog.h:1095
CLUTCHLOG_HAVE_UNIX_SYSINFO
#define CLUTCHLOG_HAVE_UNIX_SYSINFO
True if POSIX headers necessary for stack depth management are available.
Definition: clutchlog.h:33
clutchlog::_filehash_fmts
std::vector< fmt > _filehash_fmts
List of candidate format objects for value-dependant file name styling.
Definition: clutchlog.h:958
clutchlog
The single class which holds everything.
Definition: clutchlog.h:187
clutchlog::fmt::ansi
ansi
ANSI code configuring the available number of colors.
Definition: clutchlog.h:382
clutchlog::fmt::fg_16M::fg_16M
fg_16M(short r, short g, short b)
Numeric triplet constructor.
Definition: clutchlog.h:659
clutchlog::fmt::fg
fg
Foreground color codes.
Definition: clutchlog.h:403
clutchlog::fmt::color_16M::red
short red
The encoded RGB indices.
Definition: clutchlog.h:590
CLUTCHDUMP_DEFAULT_FORMAT
#define CLUTCHDUMP_DEFAULT_FORMAT
Compile-time default format of the comment line in file dump.
Definition: clutchlog.h:231
clutchlog::fmt::color::color
color(ansi a, ground g)
Constructor.
Definition: clutchlog.h:497
clutchlog::fmt::back_256
clutchlog::fmt::bg_256 back_256
Current background in 256-colors mode.